注解@Configuration和@Component区别

  1. @Configuration 注解是 Spring 组件注解的一种,通过普通的 Bean 扫描也可以扫描到 @Configuration。
  2. @Configuration 注解注册到 Spring 中的 Bean 是一个 CGLIB 代理的 Bean,而不是原始 Bean,这一点和 @Component 不一样,@Component 注册到 Spring 容器中的还是原始 Bean。

@Configuration中所有带@Bean注解的方法都会被动态代理,调用该方法返回的都是同一个实例。

1
2
3
4
5
6
7
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
String value() default "";
}

从定义来看,@Configuration注解本质上还是@Component,因此<context:component-scan/>或者@ComponentScan都能处理@Configuration注解的类。

@Configuration 标记的类必须符合下面的要求:

  • 配置类必须以类的形式提供(不能是工厂方法返回的实例),允许通过生成子类在运行时增强(cglib 动态代理)。
  • 配置类不能是 final 类(没法动态代理)。
  • 配置注解通常为了通过 @Bean 注解生成 Spring 容器管理的类。
  • 配置类必须是非本地的(即不能在方法中声明,不能是 private)。
  • 任何嵌套配置类都必须声明为static。
  • @Bean方法不能创建进一步的配置类(也就是返回的bean如果带有@Configuration,也不会被特殊处理,只会作为普通的 bean)。

Spring 容器在启动时,会加载默认的一些PostProcessor,其中就有 ConfigurationClassPostProcessor,这个后置处理程序专门处理带有@Configuration注解的类,会在bean定义加载完成后,在bean初始化前进行处理。主要处理的过程就是使用 cglib 动态代理增强类,而且是对其中带有@Bean注解的方法进行处理。

使用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
public class JavaConfig {

@Bean
User user() {
User user = new User();
user.setDog(dog());
return user;
}

@Bean
Dog dog() {
return new Dog();
}
}

上面的示例,获取从容器JavaConfig这个bean返回的是一个被代理的 JavaConfig 对象。

在 user() 方法中调用 dog() 方法的时候,调用的是一个代理对象的 dog 方法,在这个代理对象的 dog 方法中,会首先去检查 Spring 容器中是否存在 Dog 对象,如果存在,则直接使用 Spring 容器中的 dog 对象,就不会真正去执行 dog 方法而获取到一个新的 dog 对象了,如果 Spring 容器中不存在 dog 对象,才会创建新的 dog 对象出来。

当然也可以用@Component替换@Configuration:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class JavaConfig {

@Bean
final User user() {
User user = new User();
user.setDog(dog());
return user;
}

@Bean
Dog dog() {
return new Dog();
}
}

但上面的示例,获取从容器JavaConfig这个bean返回的是一个原始的 JavaConfig 对象。

由于没有被代理,因此在 user 方法中调用 dog 方法的时候,就直接调用了,因此 user 中的 dog 和最终 dog 方法注册到 Spring 容器中的 dog 不是同一个。如果想要确保 user 中的 dog 和 Spring 容器中的 dog 是同一个,那么可以通过参数将所需要的对象注入进来,类似下面这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Component
public class JavaConfig {

@Bean
final User user(Dog dog) {
User user = new User();
user.setDog(dog);
return user;
}

@Bean
Dog dog() {
return new Dog();
}
}