Spring 之 Enable* 注解的工作原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_29689487/article/details/82895348

    通过简单的@Enable* 来开启一项功能的支持,从而避免自己配置大量的代码降低使用的难度. 通过观察@Enable*注解的源码,发现所有的注解都有一个@Import注解,它是用来导入配置类的,这也就意味着这些自动开启的实现其实是导入了一些自动配置的 bean, 这些导入的配置方式主要分为以下三种类型.

第一类:直接导入配置类

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

}

直接导入 SchedulingConfiguration,这个类注解了 @Configuration,且注册了一个 scheduledAnnotationProcessor 的 bean, 源码如下:

@Configuration
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class SchedulingConfiguration {

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

}

第二类:依据条件选择配置类

@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 通过条件来选择需要导入的配置类, AsyncConfigurationSelector的根接口为 ImportSelector,这个接口需要重写 selectImports 方法,在此方法内进行条件判断.此例中,若 adviceMode 为 PROXY, 则返回 ProxyAsyncConfiguration,若 adviceMode 为ASPECTJ , 则返回 AspectJAsyncConfiguration.源码如下:

package org.springframework.scheduling.annotation;

import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.AdviceModeImportSelector;
import org.springframework.lang.Nullable;

public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {

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

	@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

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

	boolean proxyTargetClass() default false;

	boolean exposeProxy() default false;

}

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

public void registerBeanDefinitions(
			AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);

其中, AnnotationMetadata 参数用来获得当前配置类上的注解;BeanDefinitionRegistry 参数用来注册 bean; 源码如下:

class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {

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

}

猜你喜欢

转载自blog.csdn.net/qq_29689487/article/details/82895348
今日推荐