多次代理的效果如下图所示:
为什么该类会被二次代理呢?
@Configuration
@EnableTransactionManagement //注册了一个自动代理器
public class DefaultAdvisorAutoProxyCreatorConfig {
//目标类
@Bean("tService")
public TService tService() {
return new TService();
}
//注册了一个自动代理器
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true); //启用cglib代理
return defaultAdvisorAutoProxyCreator;
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(DefaultAdvisorAutoProxyCreatorConfig.class);
//可以使用@Primary指定元素,或直接使用name名获取。
TService bean = (TService) applicationContext.getBean("tService");
bean.say();
}
上述代码实际上注册了两个自动代理器
,而他们均是继承于org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator
。
而AbstractAutoProxyCreator
类作用是为Bean生成代理对象,如何获取到bean
的Advisor
。它是交由了子类去实现。
AbstractAdvisorAutoProxyCreator
作为子类,实现了自动获取Advisor
的逻辑(实现了getAdvicesAndAdvisorsForBean
)。
1. 自动代理含义
- 获取整个Spring容器Advisor类型的bean,由
生成器
决定是否处理该Advisor。(若多个生成器均决定处理一个Advisor,可能存在二次代理)。
- 每个生成器开始遍历自己决定处理的Advisor。通过Advisor的pointcut查看是否能切入bean。返回所有能够切入的Advisor。
- 创建Proxy时,将能切入的Advisor传入,即完成自动代理。
解决上述二次代理的问题,即不要去注册defaultAdvisorAutoProxyCreator
。
2. 事务增强器织入bean
首先解析类/方法上的事务注解,若存在则解析为属性对象。那么如何判断注解是否存在?且如何解析为属性对象?
2.1 解析自定义标签
自定义注解:
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyTransaction {
String value() default "";
}
public class TService {
@MyTransaction("解析自定义注解")
public void run1() {
System.out.println("This is a run1() Method!");
}
@Transactional
public void say() {
log.info("说话...");
}
}
解析注解:
@Test
public void test4() throws NoSuchMethodException {
Method method = TService.class.getMethod("run1");
//读取事务注解
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
method, MyTransaction.class, false, false);
System.out.println(attributes);
}
2.2 解析事务标签
得到的AnnotationAttributes
对象,如何转化为一个我们自定义的属性对象呢
?
public void test1() throws NoSuchMethodException {
Method say = TService.class.getMethod("say");
//读取事务注解
AnnotationAttributes attributes = AnnotatedElementUtils.findMergedAnnotationAttributes(
say, Transactional.class, false, false);
//脱离Spring
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
//解析事务注解
//获取注解的枚举对象
Propagation propagation = attributes.getEnum("propagation");
rbta.setPropagationBehavior(propagation.value());
Isolation isolation = attributes.getEnum("isolation");
rbta.setIsolationLevel(isolation.value());
rbta.setTimeout(attributes.getNumber("timeout").intValue());
rbta.setReadOnly(attributes.getBoolean("readOnly"));
rbta.setQualifier(attributes.getString("value"));
//定义回滚策略
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
rbta.setRollbackRules(rollbackRules);
System.out.println(JSON.toJSONString(rbta));
}
有小伙伴此时一定会好奇RollbackRuleAttribute
对象是干啥的。
@Test
public void test3() {
RollbackRuleAttribute rollbackRuleAttribute = new RollbackRuleAttribute(ArithmeticException.class);
try {
throw new BusinessException("业务异常");
} catch (Exception e) {
//判断抛出的e(及其父类)是否是ArithmeticException异常
int depth = rollbackRuleAttribute.getDepth(e);
System.out.println(depth);
}
}
也就是说,若异常(及其父类)符合指定的异常,返回正数;否则返回-1;
这样的话,就能决定是否是回滚的异常。
此时,注解标签解析为了属性对象。
2.3 Spring的事务切点
判断方法是否匹配时,会遍历bean中所有访问权限的方法。Spring会遍历public
方法,判断该method/class上是否存在Transactional
注解。若存在,解析为属性对象
,且通过匹配。
3. Spring解析事务注解
3.1 增强器的注册
注意:BeanFactoryTransactionAttributeSourceAdvisor
实现的是PointcutAdvisor
接口,既可以设置Advice,又可以设置Pointcut。
但是下面代码中只配置了Adice
,而pointcut
是由BeanFactoryTransactionAttributeSourceAdvisor
类完成的配置。
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
//注册了Advisor
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE) //声明的role为基础类(Spring内部使用的类)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
//配置Advice
advisor.setAdvice(transactionInterceptor());
if (this.enableTx != null) {
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
}
return advisor;
}
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
//注册了Advice
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
public class BeanFactoryTransactionAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor {
@Nullable
private TransactionAttributeSource transactionAttributeSource;
//pointcut 是TransactionAttributeSourcePointcut 的子类,实现了TransactionAttributeSource 方法。
//该方法的作用,是用户可以配置`解析器`。
private final TransactionAttributeSourcePointcut pointcut = new TransactionAttributeSourcePointcut() {
@Override
@Nullable
protected TransactionAttributeSource getTransactionAttributeSource() {
return transactionAttributeSource;
}
};
}
3.2 方法匹配
自动代理器会遍历bean的所有方法,判断是否与MethodMatcher
匹配。实际上会调用TransactionAttributeSourcePointcut
的matches
方法。
abstract class TransactionAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable {
@Override
public boolean matches(Method method, Class<?> targetClass) {
TransactionAttributeSource tas = getTransactionAttributeSource();
//若TransactionAttributeSource 对象不为空,那么获取方法上的事务属性对象。
return (tas == null || tas.getTransactionAttribute(method, targetClass) != null);
}
//抽象方法,但是注册的Advisor中的pointcut是TransactionAttributeSourcePointcut 子类。
//实际上获取的是TransactionAttributeSource 对象
@Nullable
protected abstract TransactionAttributeSource getTransactionAttributeSource();
}
3.3 事务属性获取
实际上TransactionAttributeSource
为3.1配置的AnnotationTransactionAttributeSource
对象。
当然这个类实现的只是特有的方法,而算法骨干由其父类AbstractFallbackTransactionAttributeSource
实现。
注意getTransactionAttribute
方法返回null,则证明pointcut不匹配bean的某方法。
public abstract class AbstractFallbackTransactionAttributeSource implements TransactionAttributeSource {
@Override
@Nullable
public TransactionAttribute getTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
//若是Object的方法,直接返回null
if (method.getDeclaringClass() == Object.class) {
return null;
}
// 首先看缓存是否存在
Object cacheKey = getCacheKey(method, targetClass);
TransactionAttribute cached = this.attributeCache.get(cacheKey);
if (cached != null) {
if (cached == NULL_TRANSACTION_ATTRIBUTE) {
return null;
}
else {
return cached;
}
}
else {
//获取TransactionAttribute 对象的核心方法(如下所示)
TransactionAttribute txAttr = computeTransactionAttribute(method, targetClass);
//填充缓存
if (txAttr == null) {
this.attributeCache.put(cacheKey, NULL_TRANSACTION_ATTRIBUTE);
}
else {
String methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
if (txAttr instanceof DefaultTransactionAttribute) {
((DefaultTransactionAttribute) txAttr).setDescriptor(methodIdentification);
}
if (logger.isTraceEnabled()) {
logger.trace("Adding transactional method '" + methodIdentification + "' with attribute: " + txAttr);
}
this.attributeCache.put(cacheKey, txAttr);
}
return txAttr;
}
}
@Nullable
protected TransactionAttribute computeTransactionAttribute(Method method, @Nullable Class<?> targetClass) {
// 该方法是否要求必须是public级别(因为自动代理会对所有方法进行代匹配)
if (allowPublicMethodsOnly() && !Modifier.isPublic(method.getModifiers())) {
return null;
}
//获取明确类的方法(处理桥接方法)
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
//由子类实现(获取方法上的事务配置)
TransactionAttribute txAttr = findTransactionAttribute(specificMethod);
if (txAttr != null) {
return txAttr;
}
//由子类实现(获取类上的事务配置)
txAttr = findTransactionAttribute(specificMethod.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
//获取原始方法上的事务配置
if (specificMethod != method) {
// Fallback is to look at the original method.
txAttr = findTransactionAttribute(method);
if (txAttr != null) {
return txAttr;
}
// Last fallback is the class of the original method.
txAttr = findTransactionAttribute(method.getDeclaringClass());
if (txAttr != null && ClassUtils.isUserLevelMethod(method)) {
return txAttr;
}
}
return null;
}
}
下图的两个抽象方法,由子类实现。
还需要注意的一个细节,AnnotationTransactionAttributeSource
是其唯一子类。
public class AnnotationTransactionAttributeSource extends AbstractFallbackTransactionAttributeSource
implements Serializable {
public AnnotationTransactionAttributeSource(boolean publicMethodsOnly) {
this.publicMethodsOnly = publicMethodsOnly;
if (jta12Present || ejb3Present) {
this.annotationParsers = new LinkedHashSet<>(4);
this.annotationParsers.add(new SpringTransactionAnnotationParser());
if (jta12Present) {
this.annotationParsers.add(new JtaTransactionAnnotationParser());
}
if (ejb3Present) {
this.annotationParsers.add(new Ejb3TransactionAnnotationParser());
}
}
else {
//通用模式下,为SpringTransactionAnnotationParser解析器
this.annotationParsers = Collections.singleton(new SpringTransactionAnnotationParser());
}
}
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Class<?> clazz) {
return determineTransactionAttribute(clazz);
}
@Override
@Nullable
protected TransactionAttribute findTransactionAttribute(Method method) {
return determineTransactionAttribute(method);
}
//遍历解析器,获取事务注解(方法如2.2所示)
@Nullable
protected TransactionAttribute determineTransactionAttribute(AnnotatedElement element) {
for (TransactionAnnotationParser parser : this.annotationParsers) {
TransactionAttribute attr = parser.parseTransactionAnnotation(element);
if (attr != null) {
return attr;
}
}
return null;
}
}
parseTransactionAnnotation()
方法如2.2所示,遍历方法/类上的事务注解。获取到TransactionAttribute
对象。