1.源码比较
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
@Configuration包含了@Component注解,因此我们是否可以推测两者的加载顺序不同?@Configutation是在@Compnent之后加载的?
2.使用方式和场景
- 使用@Configuration 创建一个延迟队列
@Configuration
public class DelayRabbitConfig {
public static final String IMMS_DELAY_EXCHANGE = "DELAY.EXCHANGE";
/**
* 创建一个自定义交换机 类型为x-delayed-message
*/
@Bean
public CustomExchange delayExchange() {
Map<String, Object> args = new HashMap<>();
args.put("x-delayed-type", "direct");
return new CustomExchange(IMMS_DELAY_EXCHANGE, "x-delayed-message", true, false, args);
}
}
使用规则:
- 配置必须以类的形式提供
- 配置类不能是final(无法被动态代理)
- 通常为了通过@Bean生成Spring管理的实例
- 配置类必须是非本地的 也即不能是private修饰
- 嵌套配置类必须声明为static
- 使用@Component
@Component
public class MQListener {
public static final String LOGIN_TIMEOUT_QUEUE = "login.timeout.queue";
@Resource
private VerificationService accountService;
/**
* 处理营销通用消息
*/
@RabbitListener(queues = AMQPConstant.LOGIN_TIMEOUT_QUEUE)
public void processMsg(Message message) {
String messageJsonStr = new String(message.getBody());
log.info("收到消息: {}", message);
// 处理消息
ReceiveEntity receiveEntity = JSON.parseObject(messageJsonStr, ReceiveEntity.class);
if (LOGIN_TIMEOUT_QUEUE.equals(receiveEntity.getType())) {
accountService.logout(JSON
.parseObject(JSON.toJSONString(receiveEntity.getMessage()), VerificationAccountDTO.class));
}
}
}
3.区别
- @Configuration中@Bean创建的bean是单例的,主要是通过cglib动态代理来创建bean实例。因此是单例的。
- @Component的@Bean在容器中是创建的是多例
4.实现
- Component源码
ConfigurationClassPostProcessor
/**
* {@link BeanFactoryPostProcessor} used for bootstrapping processing of
* {@link Configuration @Configuration} classes.
*/
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
//....
}
通过postProcessBeanFactory后置处理器增强@Configuration标注的类
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
int factoryId = System.identityHashCode(beanFactory);
if (this.factoriesPostProcessed.contains(factoryId)) {
throw new IllegalStateException(
"postProcessBeanFactory already called on this post-processor against " + beanFactory);
}
this.factoriesPostProcessed.add(factoryId);
if (!this.registriesPostProcessed.contains(factoryId)) {
//处理配置类的扩展属性
processConfigBeanDefinitions((BeanDefinitionRegistry) beanFactory);
}
enhanceConfigurationClasses(beanFactory);
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}
BeanDefinition·分成了两种,一种是全配置类,一种是半配置类.
public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
return metadata.isAnnotated(Configuration.class.getName());
}
public void enhanceConfigurationClasses(ConfigurableListableBeanFactory beanFactory) {
// .....
Map<String, AbstractBeanDefinition> configBeanDefs = new LinkedHashMap<>();
for (String beanName : beanFactory.getBeanDefinitionNames()) {
BeanDefinition beanDef = beanFactory.getBeanDefinition(beanName);
//如果是@Configuration的注解[也就是FULL类型的] 会放到configBeanDefs
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef)) {
if (!(beanDef instanceof AbstractBeanDefinition)) {
throw new BeanDefinitionStoreException("Cannot enhance @Configuration bean definition '" +
beanName + "' since it is not stored in an AbstractBeanDefinition subclass");
}
else if (logger.isInfoEnabled() && beanFactory.containsSingleton(beanName)) {
logger.info("Cannot enhance @Configuration bean definition '" + beanName +
"' since its singleton instance has been created too early. The typical cause " +
"is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor " +
"return type: Consider declaring such methods as 'static'.");
}
configBeanDefs.put(beanName, (AbstractBeanDefinition) beanDef);
}
}
ConfigurationClassEnhancer enhancer = new ConfigurationClassEnhancer();
for (Map.Entry<String, AbstractBeanDefinition> entry : configBeanDefs.entrySet()) {
AbstractBeanDefinition beanDef = entry.getValue();
beanDef.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
try {
Class<?> configClass = beanDef.resolveBeanClass(this.beanClassLoader);
if (configClass != null) {
//通过代理增强方法
Class<?> enhancedClass = enhancer.enhance(configClass, this.beanClassLoader);
if (configClass != enhancedClass) {
if (logger.isTraceEnabled()) {
logger.trace(String.format("Replacing bean definition '%s' existing class '%s' with " +
"enhanced class '%s'", entry.getKey(), configClass.getName(), enhancedClass.getName()));
}
beanDef.setBeanClass(enhancedClass);
}
}
}
catch (Throwable ex) {
throw new IllegalStateException("Cannot load configuration class: " + beanDef.getBeanClassName(), ex);
}
}
}
- @Component注解则是按照spring中bean生命周期进行bean的创建
4.总结
@Component在Spring中是代表LITE模式的配置注解,这种模式下的注解不会被Spring所代理,就是一个标准类,如果在这个类中有@Bean标注的方法,那么方法间的相互调用,其实就是普通Java类的方法的调用。
@Configuration在Spring中是代表FULL模式的配置注解,这种模式下的类会被Spring所代理,那么在这个类中的@Bean方法的相互调用,就相当于调用了代理方法,那么在代理方法中会判断,是否调用getBean方法还是invokeSuper方法,这里就是这两个注解的最根本的区别。