说说你对@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/
http://itsoku.com/course/5/99
来源:https://www.cnblogs.com/afei688/p/16775448.html
本站部分图文来源于网络,如有侵权请联系删除。