大廠面試官最常問的@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