1. 程式人生 > >第十三章 @Enable*註解的工作原理

第十三章 @Enable*註解的工作原理

在前面的章節中,我們使用了

@EnableAspectJAutoProxy開啟對AspectJ自動代理的支援
@EnableAsync開啟非同步方法的支援
@EnableScheduling開啟計劃任務的支援

通過簡單的@Enable*來開啟一項功能的支援,從而避免大量的配置,降低了使用難度,這是怎麼做到的呢?我們可以來研究一下這些註解的原碼

直接匯入配置類

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

直接匯入了配置類SchedulingConfiguration,再看SchedulingConfiguration的原始碼

@Configuration
public class SchedulingConfiguration {

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

SchedulingConfiguration類註解了@Configuration,且註冊了一個ScheduledAnnotationBeanPostProcessor的Bean,而真正處理計劃任務的細節都是在這個Bean裡面。

依據條件選擇配置類

@Target(ElementType.TYPE)
@Retention
(RetentionPolicy.RUNTIME) @Documented @Import(AsyncConfigurationSelector.class) public @interface EnableAsync { Class<? extends Annotation> annotation() default Annotation.class; boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; int order() default Ordered.LOWEST_PRECEDENCE; }

匯入了AsyncConfigurationSelector類,通過條件來選擇需要匯入的配置類。

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

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

    /**
     * {@inheritDoc}
     * @return {@link ProxyAsyncConfiguration} or {@code AspectJAsyncConfiguration} for
     * {@code PROXY} and {@code ASPECTJ} values of {@link EnableAsync#mode()}, respectively
     */
    @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;
        }
    }

}

動態註冊Bean

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

    boolean proxyTargetClass() default false;

}

匯入AspectJAutoProxyRegistrar類,AspectJAutoProxyRegistrar實現了ImportBeanDefinitionRegistrar介面,ImportBeanDefinitionRegistrar的作用是在執行時自動新增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);
        }
    }

}