Spring的@Enable*注解的工作原理

一 列举几个@Enable*注解的功能

  • @EnableAspectJAutoProxy:开启对AspectJ自动代理的支持。
  • @EnableAsync:开启异步方法支持。
  • @EnableScheduling:开启计划任务
  • @EnableWebMvc:开启Web Mvc配置功能

二 点睛

通过简单的@Enable*来开启一项功能的支持,从而避免自己配置大量的代码,大大降低了使用难度。

通过观察这些@Enable*注解的源码,会发现所有的注解都有一个@Import注解,该注解是用来导入配置类的,这也意味着这些开启的实现是导入了一些自动配置的Bean。

这些导入方式分三类,我们一探究竟。

三 导入配置类方式

1 直接导入配置类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {

}

直接导入配置类SchedulingConfiguration,SchedulingConfiguration注解了@Configuration,且注册了ScheduledAnnotationBeanPostProcessor的Bean,源码如下:

@Configuration
public class SchedulingConfiguration {

    @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
        return new ScheduledAnnotationBeanPostProcessor();
    }

}

2 依据条件选配置类

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {

    Class annotation() default Annotation.class;
    boolean proxyTargetClass() default false;
    AdviceMode mode() default AdviceMode.PROXY;  //默认值
    int order() default Ordered.LOWEST_PRECEDENCE;
}

AsyncConfigurationSelector通过条件来选择需要导入的配置类,AsyncConfigurationSelector的根接口是ImportSelector,这个接口需要实现selectImports方法,在该方法中进行了条件判断。如果adviceMode为PROXY,则返回ProxyAsyncConfiguration这个配置类;如果为ASPECTJ,则返回AspectJAsyncConfiguration配置类,源码如下:

public class AsyncConfigurationSelector extends AdviceModeImportSelector {

    private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
            "org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";

    @Override
    public String[] selectImports(AdviceMode adviceMode) {
        switch (adviceMode) {
            case PROXY:
                return new String[] { ProxyAsyncConfiguration.class.getName() };
            case ASPECTJ:
                return new String[] { ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME };
            default:
                return null;
        }
    }

}

3 动态注册Bean

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    boolean proxyTargetClass() default false;

}

AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar的作用是在运行时自动添加Bean到已有的配置类,通过重写下面方法:

    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

其中importingClassMetadata参数用来获得当前配置类上的注解:BeanDefinitionRegistry参数用来注册Bean。源码如下:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

        AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

        AnnotationAttributes enableAJAutoProxy =
                AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
        if (enableAJAutoProxy.getBoolean("proxyTargetClass")) {
            AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
        }
    }

}

 

你可能感兴趣的:(spring)