大厂面试官最常问的@Configuration+@Bean(JDKConfig编程方式)

177 阅读3分钟

大厂面试官最常问的@Configuration+@Bean(JDKConfig编程方式)案例分享


现在大部分的Spring项目都采用了基于注解的配置,采用了@Configuration 替换标签的做法。一行 简单的注解就可以解决很多事情。但是,其实每一个注解背后都有很多值得学习和思考的内容。这 些思考的点也是很多大厂面试官喜欢问的内容。

@Configuration处理类:org.springframework.beans.factory.annotation.AnnotatedGenericBeanDefinition

@Bean处理类:org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader$ConfigurationClassBeanDefinition

· 项目包结构

F:.

├─java

│ └─com

│ └─example

│ └─demo4

│ │ Demo4Application.java

│ │

│ ├─configuration

│ │ PersonConfiguration.java

│ │ StuConfiguration.java

│ │

│ ├─controll

│ │ StuController.java

│ │

│ ├─dao

│ │ StuDao.java

│ │ StuDaoImp.java

│ │

│ ├─entity

│ │ Person.java

│ │ Stu.java

│ │

│ └─server

│ StuService.java

│ StuServiceImp.java

└─resources

application.properties

project.text

· Beans依赖图

·

·

问题1:@Configuration和@Component区别**(@Configuration自动cglib动态代理)**

·

o @Configuration 中所有带 @Bean 注解的方法都会被动态代理,因此调用该方法返回的都是同一个实例(Spring启动时会专门处理@Configuration)。proxyBeanMethods可以设置成false,取消代理。除此之外以下@Bean无法动态代理。

o 配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。

o 配置类不能是 final 类

o 配置类必须是非本地的(即不能在方法中声明,不能是 private)。

o 任何嵌套配置类都必须声明为static。

o @Bean必须是单例(默认就是,别改成prototype)

o @Component里面的@Bean不是代理的

o 代理和不代理的区别如下代码:

//拿到@Bean->person

Person person = context.getBean(Person.class);

//拿到组件

PersonConfiguration personConfiguration = context.getBean(PersonConfiguration.class);

//执行组件里面的person()方法

Person person1=personConfiguration.person();

//使用stu

System.out.println(stu.getClass().getName());

//获取组件里面的person()方法对象的hashCode

System.out.println("person1:"+person1.getClass().getName() + "@" + Integer.toHexString(person1.hashCode()));

//@Bean->person对象的hashCode

System.out.println("person:"+person.getClass().getName() + "@" + Integer.toHexString(person.hashCode()));

//从IOC容器中取出存在的personBean

Map<String, Person> beansOfType = context.getBeansOfType(Person.class);

//对比知道不代理执行组件里面的person()方法的对象不会被Spring管理,代理就会管理

System.out.println("beansOfType:"+beansOfType.get("person").getClass().getName() + "@" + Integer.toHexString(person.hashCode()));

·

问题2:expected single matching bean but found 2

·

o

同类型多个Beans,引发原因比如使用了context.getBean(Stu.class)、@Autowired只用ByType类获取或者注入Beans的时候

o

o

使用名称获取,不优先使用ByType,==如果是其它第三方(也许第三方直接ByType)那么可以采取【禁止使用】或【优先使用】

o

o

禁止使用

o

o @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class })

o application.properties里配置:spring.autoconfigure.exclude=全类名,全类名

o

优先使用(在设计层面不建议这样使用)

o

o

@Bean

@Primary

public Person person() {

return new Person();

}

o

o

==正确姿态约定好命名规则尤为重要==

o

·

问题3:could not be registered. A bean with that name has already been defined in file

·

o 组件重复问题,大多使用配置:spring.main.allow-bean-definition-overriding=true

o 以上配置会覆盖Bean,并且依然产生具体对象

具体底层实现类(谁定义存储了这些注册类??):

·

AnnotatedGenericBeanDefinition:存储@Configuration注解注释的类

·

·

ScannedGenericBeanDefinition:存储@Component、@Service、@Controller等注解注释的类

·

·

spring初始化时,会用GenericBeanDefinition或是ConfigurationClassBeanDefinition(用@Bean注解注释的类)存储用户自定义的Bean,在初始化Bean时,又会将其转换为RootBeanDefinition