Spring的@Component和@Configuration注解
从Spring3.0,@Component和@Configuration 都可与用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
PS:@Configuration注解的配置类有如下要求:
- @Configuration不可以是final类型;
- @Configuration不可以是匿名类;
- 嵌套的configuration必须是静态类。
@Component和@Configuration作为配置类的差别
@Configuration
public class MyTestConfig {
@Bean
public Driver driver(){
Driver driver = new Driver();
driver.setId(1);
driver.setName("driver");
driver.setCar(car());
return driver;
}
@Bean
public Car car(){
Car car = new Car();
car.setId(1);
car.setName("car");
return car;
}
}
测试代码如下
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestApplicationTests {
@Autowired
private Car car;
@Autowired
private Driver driver;
@Test
public void contextLoads() {
boolean result = driver.getCar() == car;
System.out.println(result ? "同一个car" : "不同的car");
}
}
打印结果如下:
同一个car
替换为Component后的打印结果:
不同的car
原理
从上面的结果可以发现 使用Configuration时在driver和spring容器之中的是同一个对象,而使用Component时是不同的对象。
造成不同结果的原因在ConfigurationClassPostProcessor类之中,通过调用enhanceConfigurationClasses方法,为被注解@Configuration的类进行CGLIB代理。
虽然Component注解也会当做配置类,但是并不会为其生成CGLIB代理Class,所以在生成Driver对象时和生成Car对象时调用car()方法执行了两次new操作,所以是不同的对象。当时Configuration注解时,生成当前对象的子类Class,并对方法拦截,第二次调用car()方法时直接从BeanFactory之中获取对象,所以得到的是同一个对象。