1.@Configuration和@Compnent

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);
    }
}

使用规则:

  1. 配置必须以类的形式提供
  2. 配置类不能是final(无法被动态代理)
  3. 通常为了通过@Bean生成Spring管理的实例
  4. 配置类必须是非本地的 也即不能是private修饰
  5. 嵌套配置类必须声明为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·分成了两种,一种是全配置类,一种是半配置类.
image-20230507上午115931028
image-20230507上午115720004

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方法,这里就是这两个注解的最根本的区别。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值