1.springboot开启代理

1.概述

springboot声明式事务是通过动态代理实现的,本文通过@EnableTransactionManagement做为入口,跟踪spring代理的开启过程;

2.结论(重点)

开启动态代理的功能就是引入动态代理创建器的bean定义(@EnableTransactionManagement引入InfrastructureAdvisorAutoProxyCreator)。动态代理创建器负责生成代理对象的动态代理,增强代理对象;

3.原理

实现方式

spring声明式事务使用动态代理实现,实现有三种方式:

  • 如果类实现了接口,使用jdk提供的动态代理(默认);
  • 如果类没有实现接口,使用第三方库cglib,在运行时动态生成Java类的子类;
  • 使用AspectJ代理,在编译阶段生成AOP代理类,并将织入到Java字节码中。也称为静态代理;

开启过程

@EnableTransactionManagement

使用@Import引入TransactionManagementConfigurationSelector;

TransactionManagementConfigurationSelector

默认的代理模式为PROXY,TransactionManagementConfigurationSelector的selectImports方法引入AutoProxyRegistrar和ProxyTransactionManagementConfiguration。AutoProxyRegistrar负责生成类的动态代理,其它通过动态代理实现有注解同样会引入AutoProxyRegistrar。比如@EnableCaching。ProxyTransactionManagementConfiguration为动态代理事务相关的配置;

protected String[] selectImports(AdviceMode adviceMode) {
	switch (adviceMode) {
	 //**引入AutoProxyRegistrar和ProxyTransactionManagementConfiguration
		case PROXY:
			return new String[] {AutoProxyRegistrar.class.getName(),
					ProxyTransactionManagementConfiguration.class.getName()};
		case ASPECTJ:
			return new String[] {determineTransactionAspectClass()};
		default:
			return null;
	}
}

AutoProxyRegistrar

负责注册动态代理相关的bean定义(InfrastructureAdvisorAutoProxyCreator)。如果启用了CGLIB(proxyTargetClass=true)代理,在代理bean定义中添加属性proxyTargetClass=true;

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	boolean candidateFound = false;
	//**获取@EnableTransactionManagement注册所在类的所有注解(一般都是项目的启动类SpringdemoApplication)
	Set<String> annTypes = importingClassMetadata.getAnnotationTypes();
	for (String annType : annTypes) {
		AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
		if (candidate == null) {
			continue;
		}
		Object mode = candidate.get("mode");
		Object proxyTargetClass = candidate.get("proxyTargetClass");
		//**获取需启用动态代理的注解
		if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() &&
				Boolean.class == proxyTargetClass.getClass()) {
			candidateFound = true;
			//**注册动态代理的bean定义(InfrastructureAdvisorAutoProxyCreator)
			if (mode == AdviceMode.PROXY) {
				AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
				//**如果启用了CGLIB(proxyTargetClass=true),在代理bean定义中添加属性(definition.getPropertyValues().add("proxyTargetClass", Boolean.TRUE);)
				if ((Boolean) proxyTargetClass) {
				    AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
					return;
				}
			}
		}
	}
	...
}

AopConfigUtils.registerAutoProxyCreatorIfNecessary

注册动态代理的bean定义InfrastructureAdvisorAutoProxyCreator。InfrastructureAdvisorAutoProxyCreator是基础设施自动代理创建器,只考虑基础设施(role=BeanDefinition.ROLE_INFRASTRUCTURE)的Advisor(Advisor:顾问,动态代理额外执行逻辑的抽象),不考虑自定义的Advisor;

  • BeanDefinition的role有三种类型:
    • ROLE_APPLICATION:表示这个Bean是用户自己定义的Bean,最常用的角色类型;
    • ROLE_SUPPORT:表示这个Bean是某些复杂配置的支撑部分。通常用于支持其他Bean的配置,例如一些中间件或者服务。
    • ROLE_INFRASTRUCTURE:表示这是一个Spring内部的Bean。通常用于实现Spring框架的核心功能,例如数据源、事务管理器等;
  • InfrastructureAdvisorAutoProxyCreator的作用
    • 创建代理对象,增强目标对象的功能。InfrastructureAdvisorAutoProxyCreator利用后置处理器机制,在对象创建以后,包装对象并返回代理对象。同时,通过拦截器链对代理对象执行的方法进行调用。
@Nullable
public static BeanDefinition registerAutoProxyCreatorIfNecessary(
		BeanDefinitionRegistry registry, @Nullable Object source) {
    //**注册动态代理的bean定义InfrastructureAdvisorAutoProxyCreator
	return registerOrEscalateApcAsRequired(InfrastructureAdvisorAutoProxyCreator.class, registry, source);
}

//*获取动态代理的bean定义(名称为org.springframework.aop.config.internalAutoProxyCreator)
//**如果当前的动态代理的bean定义不是InfrastructureAdvisorAutoProxyCreator,则根据优先级设置bean定义;
//**InfrastructureAdvisorAutoProxyCreator优先级最低,并且没有提供修改优先级的方法;
@Nullable
private static BeanDefinition registerOrEscalateApcAsRequired(
		Class<?> cls, BeanDefinitionRegistry registry, @Nullable Object source) {
	if (registry.containsBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME)) {
		BeanDefinition apcDefinition = registry.getBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME);
		if (!cls.getName().equals(apcDefinition.getBeanClassName())) {
			int currentPriority = findPriorityForClass(apcDefinition.getBeanClassName());
			int requiredPriority = findPriorityForClass(cls);
			if (currentPriority < requiredPriority) {
				apcDefinition.setBeanClassName(cls.getName());
			}
		}
		return null;
	}

	RootBeanDefinition beanDefinition = new RootBeanDefinition(cls);
	beanDefinition.setSource(source);
	beanDefinition.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
	beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
	registry.registerBeanDefinition(AUTO_PROXY_CREATOR_BEAN_NAME, beanDefinition);
	return beanDefinition;
}

//**动态代理bean的优先顺序,InfrastructureAdvisorAutoProxyCreator优先级最低
static {
	APC_PRIORITY_LIST.add(InfrastructureAdvisorAutoProxyCreator.class);
	APC_PRIORITY_LIST.add(AspectJAwareAdvisorAutoProxyCreator.class);
	APC_PRIORITY_LIST.add(AnnotationAwareAspectJAutoProxyCreator.class);
}

4.默认配置

实际上项目中通常是使用AnnotationAwareAspectJAutoProxyCreator创建cglib动态代理。因为spring有配置类AopAutoConfiguration,使用@EnableAspectJAutoProxy引入AnnotationAwareAspectJAutoProxyCreator,并默认proxyTargetClass=true;

  • 只要没有明确配置spring.aop.auto=false,就会使用AnnotationAwareAspectJAutoProxyCreator;
  • 只要没有明确配置spring.aop.proxy-target-class=false,就会使用cglib动态代理;
@AutoConfiguration
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnClass(Advice.class)
	static class AspectJAutoProxyingConfiguration {

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = false)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false")
		static class JdkDynamicAutoProxyConfiguration {

		}

		@Configuration(proxyBeanMethods = false)
		@EnableAspectJAutoProxy(proxyTargetClass = true)
		@ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true",
				matchIfMissing = true)
		static class CglibAutoProxyConfiguration {

		}

	}
}

如果在声明式事务中想使用InfrastructureAdvisorAutoProxyCreator创建jdk动态代理,需加入以下配置;

spring.aop.auto=false
spring.aop.proxy-target-class=false

你可能感兴趣的:(#,spring代理,spring,boot,后端,java)