fix @DSTransactional 无法获取类|接口|接口方法的注解属性 (#543)

Co-authored-by: zhangpeng <xinniankuailezp@163.com>
This commit is contained in:
Z.P 2023-08-11 16:10:53 +08:00 committed by GitHub
parent a71a54bd13
commit d9f2bd000d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 112 additions and 33 deletions

View File

@ -85,7 +85,8 @@ public class DynamicDataSourceAopConfiguration {
@Bean @Bean
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "seata", havingValue = "false", matchIfMissing = true) @ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "seata", havingValue = "false", matchIfMissing = true)
public Advisor dynamicTransactionAdvisor() { public Advisor dynamicTransactionAdvisor() {
DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor(); DynamicDatasourceAopProperties aopProperties = properties.getAop();
DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor(aopProperties.getAllowedPublicOnly());
return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class); return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class);
} }

View File

@ -85,7 +85,8 @@ public class DynamicDataSourceAopConfiguration {
@Bean @Bean
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "seata", havingValue = "false", matchIfMissing = true) @ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "seata", havingValue = "false", matchIfMissing = true)
public Advisor dynamicTransactionAdvisor() { public Advisor dynamicTransactionAdvisor() {
DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor(); DynamicDatasourceAopProperties aopProperties = properties.getAop();
DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor(aopProperties.getAllowedPublicOnly());
return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class); return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class);
} }

View File

@ -0,0 +1,19 @@
package com.baomidou.dynamic.datasource.annotation;
import lombok.AllArgsConstructor;
import lombok.Data;
/**
* The base kind all dynamicDatasource annotation attribute.
*
* @author zp
* @since 4.1.3
*/
@Data
@AllArgsConstructor
public class BasicAttribute<T> {
/**
* dataOperation
*/
private T dataOperation;
}

View File

@ -16,6 +16,7 @@
package com.baomidou.dynamic.datasource.aop; package com.baomidou.dynamic.datasource.aop;
import com.baomidou.dynamic.datasource.processor.DsProcessor; import com.baomidou.dynamic.datasource.processor.DsProcessor;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.support.DataSourceClassResolver; import com.baomidou.dynamic.datasource.support.DataSourceClassResolver;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder; import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInterceptor;
@ -66,7 +67,7 @@ public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor
* @return dsKey * @return dsKey
*/ */
private String determineDatasourceKey(MethodInvocation invocation) { private String determineDatasourceKey(MethodInvocation invocation) {
String key = dataSourceClassResolver.findKey(invocation.getMethod(), invocation.getThis()); String key = dataSourceClassResolver.findKey(invocation.getMethod(), invocation.getThis(), DS.class);
return key.startsWith(DYNAMIC_PREFIX) ? dsProcessor.determineDatasource(invocation, key) : key; return key.startsWith(DYNAMIC_PREFIX) ? dsProcessor.determineDatasource(invocation, key) : key;
} }
} }

View File

@ -16,6 +16,7 @@
package com.baomidou.dynamic.datasource.aop; package com.baomidou.dynamic.datasource.aop;
import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.support.DataSourceClassResolver;
import com.baomidou.dynamic.datasource.tx.TransactionalExecutor; import com.baomidou.dynamic.datasource.tx.TransactionalExecutor;
import com.baomidou.dynamic.datasource.tx.TransactionalInfo; import com.baomidou.dynamic.datasource.tx.TransactionalInfo;
import com.baomidou.dynamic.datasource.tx.TransactionalTemplate; import com.baomidou.dynamic.datasource.tx.TransactionalTemplate;
@ -32,12 +33,17 @@ import java.lang.reflect.Method;
*/ */
@Slf4j @Slf4j
public class DynamicLocalTransactionInterceptor implements MethodInterceptor { public class DynamicLocalTransactionInterceptor implements MethodInterceptor {
private final TransactionalTemplate transactionalTemplate = new TransactionalTemplate(); private final TransactionalTemplate transactionalTemplate;
private final DataSourceClassResolver dataSourceClassResolver;
public DynamicLocalTransactionInterceptor(Boolean allowedPublicOnly) {
transactionalTemplate = new TransactionalTemplate();
dataSourceClassResolver = new DataSourceClassResolver(allowedPublicOnly);
}
@Override @Override
public Object invoke(final MethodInvocation methodInvocation) throws Throwable { public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
Method method = methodInvocation.getMethod(); final Method method = methodInvocation.getMethod();
final DSTransactional dsTransactional = method.getAnnotation(DSTransactional.class);
TransactionalExecutor transactionalExecutor = new TransactionalExecutor() { TransactionalExecutor transactionalExecutor = new TransactionalExecutor() {
@Override @Override
@ -47,11 +53,7 @@ public class DynamicLocalTransactionInterceptor implements MethodInterceptor {
@Override @Override
public TransactionalInfo getTransactionInfo() { public TransactionalInfo getTransactionInfo() {
TransactionalInfo transactionInfo = new TransactionalInfo(); return dataSourceClassResolver.findTransactionalInfo(method, methodInvocation.getThis(), DSTransactional.class);
transactionInfo.setPropagation(dsTransactional.propagation());
transactionInfo.setNoRollbackFor(dsTransactional.noRollbackFor());
transactionInfo.setRollbackFor(dsTransactional.rollbackFor());
return transactionInfo;
} }
}; };
return transactionalTemplate.execute(transactionalExecutor); return transactionalTemplate.execute(transactionalExecutor);

View File

@ -15,15 +15,18 @@
*/ */
package com.baomidou.dynamic.datasource.support; package com.baomidou.dynamic.datasource.support;
import com.baomidou.dynamic.datasource.annotation.BasicAttribute;
import com.baomidou.dynamic.datasource.annotation.DS; import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.dynamic.datasource.tx.TransactionalInfo;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopProxyUtils; import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.core.BridgeMethodResolver; import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.MethodClassKey; import org.springframework.core.MethodClassKey;
import org.springframework.core.annotation.AnnotatedElementUtils; import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.util.ClassUtils; import org.springframework.util.ClassUtils;
import java.lang.annotation.Annotation;
import java.lang.reflect.*; import java.lang.reflect.*;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
@ -70,7 +73,20 @@ public class DataSourceClassResolver {
* 缓存方法对应的数据源 * 缓存方法对应的数据源
*/ */
private final Map<Object, String> dsCache = new ConcurrentHashMap<>(); private final Map<Object, String> dsCache = new ConcurrentHashMap<>();
/**
* 缓存事务信息
*/
private final Map<Object, TransactionalInfo> dsTransactionalCache = new ConcurrentHashMap<>();
private final boolean allowedPublicOnly; private final boolean allowedPublicOnly;
/**
* 默认事务属性
*/
private static final TransactionalInfo NULL_TRANSACTION_ATTRIBUTE = new TransactionalInfo() {
@Override
public String toString() {
return "null";
}
};
/** /**
* 加入扩展, 给外部一个修改aop条件的机会 * 加入扩展, 给外部一个修改aop条件的机会
@ -88,22 +104,49 @@ public class DataSourceClassResolver {
* @param targetObject 目标对象 * @param targetObject 目标对象
* @return ds * @return ds
*/ */
public String findKey(Method method, Object targetObject) { public String findKey(Method method, Object targetObject, Class<? extends Annotation> annotation) {
if (method.getDeclaringClass() == Object.class) { if (method.getDeclaringClass() == Object.class) {
return ""; return "";
} }
Object cacheKey = new MethodClassKey(method, targetObject.getClass()); Object cacheKey = new MethodClassKey(method, targetObject.getClass());
String ds = this.dsCache.get(cacheKey); String ds = this.dsCache.get(cacheKey);
if (ds == null) { if (ds == null) {
ds = computeDatasource(method, targetObject); BasicAttribute<String> dsOperation = computeDatasource(method, targetObject, annotation);
if (ds == null) { if (dsOperation == null) {
ds = ""; ds = "";
} else {
ds = dsOperation.getDataOperation();
} }
this.dsCache.put(cacheKey, ds); this.dsCache.put(cacheKey, ds);
} }
return ds; return ds;
} }
/**
* 从缓存获取事务属性
*
* @param method 方法
* @param targetObject 目标对象
* @return TransactionalInfo
*/
public TransactionalInfo findTransactionalInfo(Method method, Object targetObject, Class<? extends Annotation> annotation) {
if (method.getDeclaringClass() == Object.class) {
return NULL_TRANSACTION_ATTRIBUTE;
}
Object cacheKey = new MethodClassKey(method, targetObject.getClass());
TransactionalInfo dsTransactional = this.dsTransactionalCache.get(cacheKey);
if (dsTransactional == null) {
BasicAttribute<TransactionalInfo> dsTransactionalOperation = computeDatasource(method, targetObject, annotation);
if (dsTransactionalOperation == null) {
dsTransactional = NULL_TRANSACTION_ATTRIBUTE;
} else {
dsTransactional = dsTransactionalOperation.getDataOperation();
}
this.dsTransactionalCache.put(cacheKey, dsTransactional);
}
return dsTransactional;
}
/** /**
* 查找注解的顺序 * 查找注解的顺序
* 1. 当前方法 * 1. 当前方法
@ -115,12 +158,12 @@ public class DataSourceClassResolver {
* @param targetObject 目标对象 * @param targetObject 目标对象
* @return ds * @return ds
*/ */
private String computeDatasource(Method method, Object targetObject) { private <T> BasicAttribute<T> computeDatasource(Method method, Object targetObject, Class<? extends Annotation> annotation) {
if (allowedPublicOnly && !Modifier.isPublic(method.getModifiers())) { if (allowedPublicOnly && !Modifier.isPublic(method.getModifiers())) {
return null; return null;
} }
//1. 从当前方法接口中获取 //1. 从当前方法接口中获取
String dsAttr = findDataSourceAttribute(method); BasicAttribute<T> dsAttr = findDataSourceAttribute(method, annotation);
if (dsAttr != null) { if (dsAttr != null) {
return dsAttr; return dsAttr;
} }
@ -130,19 +173,19 @@ public class DataSourceClassResolver {
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass); Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod); specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
//2. 桥接方法查 //2. 实现类的方法
dsAttr = findDataSourceAttribute(specificMethod); dsAttr = findDataSourceAttribute(specificMethod, annotation);
if (dsAttr != null) { if (dsAttr != null) {
return dsAttr; return dsAttr;
} }
// 从当前方法声明的类查找 // 从当前方法声明的类查找
dsAttr = findDataSourceAttribute(userClass); dsAttr = findDataSourceAttribute(userClass, annotation);
if (dsAttr != null && ClassUtils.isUserLevelMethod(method)) { if (dsAttr != null && ClassUtils.isUserLevelMethod(method)) {
return dsAttr; return dsAttr;
} }
//since 3.4.1 从接口查找只取第一个找到的 //since 3.4.1 从接口查找只取第一个找到的
for (Class<?> interfaceClazz : ClassUtils.getAllInterfacesForClassAsSet(userClass)) { for (Class<?> interfaceClazz : ClassUtils.getAllInterfacesForClassAsSet(userClass)) {
dsAttr = findDataSourceAttribute(interfaceClazz); dsAttr = findDataSourceAttribute(interfaceClazz, annotation);
if (dsAttr != null) { if (dsAttr != null) {
return dsAttr; return dsAttr;
} }
@ -150,17 +193,17 @@ public class DataSourceClassResolver {
// 如果存在桥接方法 // 如果存在桥接方法
if (specificMethod != method) { if (specificMethod != method) {
// 从桥接方法查找 // 从桥接方法查找
dsAttr = findDataSourceAttribute(method); dsAttr = findDataSourceAttribute(method, annotation);
if (dsAttr != null) { if (dsAttr != null) {
return dsAttr; return dsAttr;
} }
// 从桥接方法声明的类查找 // 从桥接方法声明的类查找
dsAttr = findDataSourceAttribute(method.getDeclaringClass()); dsAttr = findDataSourceAttribute(method.getDeclaringClass(), annotation);
if (dsAttr != null && ClassUtils.isUserLevelMethod(method)) { if (dsAttr != null && ClassUtils.isUserLevelMethod(method)) {
return dsAttr; return dsAttr;
} }
} }
return getDefaultDataSourceAttr(targetObject); return getDefaultDataSourceAttr(targetObject, annotation);
} }
/** /**
@ -169,13 +212,13 @@ public class DataSourceClassResolver {
* @param targetObject 目标对象 * @param targetObject 目标对象
* @return ds * @return ds
*/ */
private String getDefaultDataSourceAttr(Object targetObject) { private <T> BasicAttribute<T> getDefaultDataSourceAttr(Object targetObject, Class<? extends Annotation> annotation) {
Class<?> targetClass = targetObject.getClass(); Class<?> targetClass = targetObject.getClass();
// 如果不是代理类, 从当前类开始, 不断的找父类的声明 // 如果不是代理类, 从当前类开始, 不断的找父类的声明
if (!Proxy.isProxyClass(targetClass)) { if (!Proxy.isProxyClass(targetClass)) {
Class<?> currentClass = targetClass; Class<?> currentClass = targetClass;
while (currentClass != Object.class) { while (currentClass != Object.class) {
String datasourceAttr = findDataSourceAttribute(currentClass); BasicAttribute<T> datasourceAttr = findDataSourceAttribute(currentClass, annotation);
if (datasourceAttr != null) { if (datasourceAttr != null) {
return datasourceAttr; return datasourceAttr;
} }
@ -186,12 +229,12 @@ public class DataSourceClassResolver {
if (mpEnabled) { if (mpEnabled) {
final Class<?> clazz = getMapperInterfaceClass(targetObject); final Class<?> clazz = getMapperInterfaceClass(targetObject);
if (clazz != null) { if (clazz != null) {
String datasourceAttr = findDataSourceAttribute(clazz); BasicAttribute<T> datasourceAttr = findDataSourceAttribute(clazz, annotation);
if (datasourceAttr != null) { if (datasourceAttr != null) {
return datasourceAttr; return datasourceAttr;
} }
// 尝试从其父接口获取 // 尝试从其父接口获取
return findDataSourceAttribute(clazz.getSuperclass()); return findDataSourceAttribute(clazz.getSuperclass(), annotation);
} }
} }
return null; return null;
@ -222,15 +265,27 @@ public class DataSourceClassResolver {
} }
/** /**
* 通过 AnnotatedElement 查找标记的注解, 映射为 DatasourceHolder * 通过 AnnotatedElement 查找标记的注解, 映射为BasicAttribute
* *
* @param ae AnnotatedElement * @param ae AnnotatedElement
* @return 数据源映射持有者 * @return 数据源映射持有者
*/ */
private String findDataSourceAttribute(AnnotatedElement ae) { private <T> BasicAttribute<T> findDataSourceAttribute(AnnotatedElement ae, Class<? extends Annotation> annotation) {
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, DS.class); if (annotation.isAssignableFrom(DS.class)) {
if (attributes != null) { //AnnotatedElementUtils.findMergedAnnotation()会委托给findMergedAnnotationAttributes()
return attributes.getString("value"); DS ds = AnnotatedElementUtils.findMergedAnnotation(ae, DS.class);
if (ds != null) {
return (BasicAttribute<T>) new BasicAttribute<>(ds.value());
}
} else if (annotation.isAssignableFrom(DSTransactional.class)) {
DSTransactional dsTransactional = AnnotatedElementUtils.findMergedAnnotation(ae, DSTransactional.class);
if (dsTransactional != null) {
TransactionalInfo transactionalInfo = new TransactionalInfo();
transactionalInfo.setPropagation(dsTransactional.propagation());
transactionalInfo.setRollbackFor(dsTransactional.rollbackFor());
transactionalInfo.setNoRollbackFor(dsTransactional.noRollbackFor());
return (BasicAttribute<T>) new BasicAttribute(transactionalInfo);
}
} }
return null; return null;
} }