說說你對@Configuration的理解? 定義 @Configuration這個註解是一個類註解,加在類上,標識該類是一個配置類,讓這個類的功能等同於一個bean xml配置文件。 @Configuration public class SpringConfig { } 上面代碼類似於下麵的xm ...
說說你對@Configuration的理解?
定義
@Configuration這個註解是一個類註解,加在類上,標識該類是一個配置類,讓這個類的功能等同於一個bean xml配置文件。
@Configuration
public class SpringConfig {
}
上面代碼類似於下麵的xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
</beans>
一般 @Configuration 都是和 @Bean 註解結合使用的,上文代碼塊中使用 @Configuration 定義了一個配置類,相當於定義了一個空的 xml 配置文件,此時我們要在SpringBean 類中註冊bean,那麼我們就要用到@Bean註解了。
@Bean
這個註解是一個方法註解,用在方法上,表示通過方法來定義一個bean,預設將方法名稱作為bean名稱,將方法返回值作為bean對象,註冊到spring容器中。類似於bean xml配置文件中的bean元素,用來在spring容器中註冊一個bean。
@Confuguration
public class SpringConfig {
// 導入自定義的bean:bean名稱為方法預設值:user1
@Bean
public User user1() {
return new User();
}
// bean名稱通過value指定:user2Bean
@Bean("user2Bean")
public User user2() {
return new User();
}
// 導入第三方bean
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
ds.setUsername("root");
ds.setPassword("123");
return ds;
}
}
用法
@Configuration註解的使用步驟:
- 定義一個類,在類上添加
@Configuration
註解; - 通過
AnnotationConfigApplicationContext
容器來載入@Configuration
註解修飾的配置類,會將配置類中所有的bean註冊到spring容器中。
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
拓展
如果去掉 @Configuration,會怎樣?
舉個例子:
定義一個User類和Order類
public class User {
public User() {
System.out.println("無參創建User");
}
}
public class Order {
private User user;
public Order(User user) {
this.user = user;
}
@Override
public String toString() {
return "Order{" +
"user=" + user +
'}';
}
}
定義一個配置類
//@Configuration
public class SpringConfig {
// bean名稱為方法預設值:user1
@Bean
public User user() {
return new User();
}
@Bean
public Order order() {
System.out.println("調用order()方法");
return new Order(this.user());
}
@Bean()
public Order order2() {
System.out.println("調用order2()方法");
return new Order(this.user());
}
}
測試類
public class SpringTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
for (String beanName : ctx.getBeanDefinitionNames()) {
System.out.printf("beanName: %s \t bean對象: %s\n", beanName, ctx.getBean(beanName));
}
}
}
① 加上 @Configuration 註解時輸出的結果:
無參創建User
調用order()方法
調用order2()方法
(這裡省略Spring容器創建時預設載入的bean)
beanName: springConfig bean對象: cn.afei.config.SpringConfig$$EnhancerBySpringCGLIB$$f76b28e8@4ae3c1cd
beanName: user bean對象: cn.afei.domain.User@29f69090
beanName: order bean對象: Order{user=cn.afei.domain.User@29f69090}
beanName: order2 bean對象: Order{user=cn.afei.domain.User@29f69090}
加上 @Configuration,類中定義了3個Bean,Order中註入User對象時,會復用創建好的User對象,User的構造器只被調用了一次,保證了User對象單例。
被@Configuration修飾的bean最後輸出的時候帶有
EnhancerBySpringCGLIB
的字樣,說明這個bean是被CGLIB處理過的,變成了一個代理對象。
② 去掉 @Configuration 註解時輸出的結果:
無參創建User
調用order()方法
無參創建User
調用order2()方法
無參創建User
beanName: springConfig bean對象: cn.afei.config.SpringConfig@543c6f6d
beanName: user bean對象: cn.afei.domain.User@13eb8acf
beanName: order bean對象: Order{user=cn.afei.domain.User@51c8530f}
beanName: order2 bean對象: Order{user=cn.afei.domain.User@7403c468}
去掉了 @Configuration,類中定義了3個Bean,每個Bean都會去創建一個User對象,User的構造器被調用了三次。
沒有@Configuration註解的bean沒有Cglib的字樣。
被@Configuration修飾的類,spring容器中會通過cglib給這個類創建一個代理,代理會攔截所有被@Bean
修飾的方法,預設情況(bean為單例)下確保這些方法只被調用一次,從而確保這些bean是同一個bean,即單例的。
總結
- @Configuration註解修飾的類,會被spring通過cglib做增強處理,通過cglib會生成一個代理對象,代理會攔截所有被@Bean註解修飾的方法,可以確保這些bean是單例的。
- 不管@Bean所在的類上是否有@Configuration註解,@Bean註解都會生效,都可以將@Bean修飾的方法作為一個bean註冊到spring容器中。
參考
https://www.bilibili.com/video/BV1Fi4y1S7ix/