Spring中的@Enable注解


本文轉載自SpringBoot中神奇的@Enable注解?

導語

在SpringBoot開發過程,我們經常會遇到@Enable開始的好多注解,比如@EnableEurekaServer、@EnableAsync、@EnableScheduling等,今天我們就來分析下這些注解到底是如何工作的?

@Enable實現的原理

通過這些@Enable注解的源碼可以看出,所有@Enable注解里面都有一個@Import注解,而@Import是用來導入配置類的,所以@Enable自動開啟的實現原理其實就是導入了一些自動配置的Bean。

@Import注解的用法

@Import只允許放到類上面,不能放到方法上。
@Import注解允許導入@Configuration類,ImportSelector和ImportBeanDefinitionRegistrar的實現類,普通的Bean。

有以下三種使用方式

直接導入配置類

@EnableEurekaServer使用了這種方式,注解源碼如下:

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

可以看到@EnableEurekaServer注解直接導入了配置類EurekaServerMarkerConfiguration,而這個配置類中向spring容器中注冊了一個EurekaServerMarkerConfiguration的Bean。

EurekaServerMarkerConfiguration的源碼如下:

@Configuration
public class EurekaServerMarkerConfiguration {
    public EurekaServerMarkerConfiguration() {
    }

    @Bean
    public EurekaServerMarkerConfiguration.Marker eurekaServerMarkerBean() {
        return new EurekaServerMarkerConfiguration.Marker();
    }

    class Marker {
        Marker() {
        }
    }
}

依據條件選擇配置類

@EnableAsync使用了這種方式,注解源碼如下:

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

EnableAsync注解中導入了AsyncConfigurationSelector,AsyncConfigurationSelector通過條件來選擇需要導入的配置類,繼承AdviceModeImportSelector又實現了ImportSelector接口,接口重寫selectImports方法進行事先條件判斷PROXY或者ASPECTJ選擇不同的配置類。

AsyncConfigurationSelector源碼如下:

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

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


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

@EnableAspectJAutoProxy使用了這種方式,注解源碼如下:

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

	boolean proxyTargetClass() default false;
	 
	boolean exposeProxy() default false;
}

EnableAspectJAutoProxy注解中導入了AspectJAutoProxyRegistrar,AspectJAutoProxyRegistrar實現了ImportBeanDefinitionRegistrar接口,在運行時把Bean注冊到spring容器中。

AspectJAutoProxyRegistrar的源碼如下:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * Register, escalate, and configure the AspectJ auto proxy creator based on the value
	 * of the @{@link EnableAspectJAutoProxy#proxyTargetClass()} attribute on the importing
	 * {@code @Configuration} class.
	 */
	@Override
	public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {

		AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);

		AnnotationAttributes enableAspectJAutoProxy =
				AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
		if (enableAspectJAutoProxy != null) {
			if (enableAspectJAutoProxy.getBoolean("proxyTargetClass")) {
				AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
			}
			if (enableAspectJAutoProxy.getBoolean("exposeProxy")) {
				AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
			}
		}
	}

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM