fix @DSTransactional 无法获取类|接口|接口方法的注解属性 (#543)
Co-authored-by: zhangpeng <xinniankuailezp@163.com>
This commit is contained in:
parent
a71a54bd13
commit
d9f2bd000d
@ -85,7 +85,8 @@ public class DynamicDataSourceAopConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "seata", havingValue = "false", matchIfMissing = true)
|
||||
public Advisor dynamicTransactionAdvisor() {
|
||||
DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor();
|
||||
DynamicDatasourceAopProperties aopProperties = properties.getAop();
|
||||
DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor(aopProperties.getAllowedPublicOnly());
|
||||
return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class);
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,8 @@ public class DynamicDataSourceAopConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = DynamicDataSourceProperties.PREFIX, name = "seata", havingValue = "false", matchIfMissing = true)
|
||||
public Advisor dynamicTransactionAdvisor() {
|
||||
DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor();
|
||||
DynamicDatasourceAopProperties aopProperties = properties.getAop();
|
||||
DynamicLocalTransactionInterceptor interceptor = new DynamicLocalTransactionInterceptor(aopProperties.getAllowedPublicOnly());
|
||||
return new DynamicDataSourceAnnotationAdvisor(interceptor, DSTransactional.class);
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
package com.baomidou.dynamic.datasource.aop;
|
||||
|
||||
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.toolkit.DynamicDataSourceContextHolder;
|
||||
import org.aopalliance.intercept.MethodInterceptor;
|
||||
@ -66,7 +67,7 @@ public class DynamicDataSourceAnnotationInterceptor implements MethodInterceptor
|
||||
* @return dsKey
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
@ -16,6 +16,7 @@
|
||||
package com.baomidou.dynamic.datasource.aop;
|
||||
|
||||
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.TransactionalInfo;
|
||||
import com.baomidou.dynamic.datasource.tx.TransactionalTemplate;
|
||||
@ -32,12 +33,17 @@ import java.lang.reflect.Method;
|
||||
*/
|
||||
@Slf4j
|
||||
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
|
||||
public Object invoke(final MethodInvocation methodInvocation) throws Throwable {
|
||||
Method method = methodInvocation.getMethod();
|
||||
final DSTransactional dsTransactional = method.getAnnotation(DSTransactional.class);
|
||||
final Method method = methodInvocation.getMethod();
|
||||
|
||||
TransactionalExecutor transactionalExecutor = new TransactionalExecutor() {
|
||||
@Override
|
||||
@ -47,11 +53,7 @@ public class DynamicLocalTransactionInterceptor implements MethodInterceptor {
|
||||
|
||||
@Override
|
||||
public TransactionalInfo getTransactionInfo() {
|
||||
TransactionalInfo transactionInfo = new TransactionalInfo();
|
||||
transactionInfo.setPropagation(dsTransactional.propagation());
|
||||
transactionInfo.setNoRollbackFor(dsTransactional.noRollbackFor());
|
||||
transactionInfo.setRollbackFor(dsTransactional.rollbackFor());
|
||||
return transactionInfo;
|
||||
return dataSourceClassResolver.findTransactionalInfo(method, methodInvocation.getThis(), DSTransactional.class);
|
||||
}
|
||||
};
|
||||
return transactionalTemplate.execute(transactionalExecutor);
|
||||
|
@ -15,15 +15,18 @@
|
||||
*/
|
||||
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.DSTransactional;
|
||||
import com.baomidou.dynamic.datasource.tx.TransactionalInfo;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.aop.framework.AopProxyUtils;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.MethodClassKey;
|
||||
import org.springframework.core.annotation.AnnotatedElementUtils;
|
||||
import org.springframework.core.annotation.AnnotationAttributes;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@ -70,7 +73,20 @@ public class DataSourceClassResolver {
|
||||
* 缓存方法对应的数据源
|
||||
*/
|
||||
private final Map<Object, String> dsCache = new ConcurrentHashMap<>();
|
||||
/**
|
||||
* 缓存事务信息
|
||||
*/
|
||||
private final Map<Object, TransactionalInfo> dsTransactionalCache = new ConcurrentHashMap<>();
|
||||
private final boolean allowedPublicOnly;
|
||||
/**
|
||||
* 默认事务属性
|
||||
*/
|
||||
private static final TransactionalInfo NULL_TRANSACTION_ATTRIBUTE = new TransactionalInfo() {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "null";
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 加入扩展, 给外部一个修改aop条件的机会
|
||||
@ -88,22 +104,49 @@ public class DataSourceClassResolver {
|
||||
* @param targetObject 目标对象
|
||||
* @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) {
|
||||
return "";
|
||||
}
|
||||
Object cacheKey = new MethodClassKey(method, targetObject.getClass());
|
||||
String ds = this.dsCache.get(cacheKey);
|
||||
if (ds == null) {
|
||||
ds = computeDatasource(method, targetObject);
|
||||
if (ds == null) {
|
||||
BasicAttribute<String> dsOperation = computeDatasource(method, targetObject, annotation);
|
||||
if (dsOperation == null) {
|
||||
ds = "";
|
||||
} else {
|
||||
ds = dsOperation.getDataOperation();
|
||||
}
|
||||
this.dsCache.put(cacheKey, 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. 当前方法
|
||||
@ -115,12 +158,12 @@ public class DataSourceClassResolver {
|
||||
* @param targetObject 目标对象
|
||||
* @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())) {
|
||||
return null;
|
||||
}
|
||||
//1. 从当前方法接口中获取
|
||||
String dsAttr = findDataSourceAttribute(method);
|
||||
BasicAttribute<T> dsAttr = findDataSourceAttribute(method, annotation);
|
||||
if (dsAttr != null) {
|
||||
return dsAttr;
|
||||
}
|
||||
@ -130,19 +173,19 @@ public class DataSourceClassResolver {
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, userClass);
|
||||
|
||||
specificMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
//2. 从桥接方法查找
|
||||
dsAttr = findDataSourceAttribute(specificMethod);
|
||||
//2. 从实现类的方法找
|
||||
dsAttr = findDataSourceAttribute(specificMethod, annotation);
|
||||
if (dsAttr != null) {
|
||||
return dsAttr;
|
||||
}
|
||||
// 从当前方法声明的类查找
|
||||
dsAttr = findDataSourceAttribute(userClass);
|
||||
dsAttr = findDataSourceAttribute(userClass, annotation);
|
||||
if (dsAttr != null && ClassUtils.isUserLevelMethod(method)) {
|
||||
return dsAttr;
|
||||
}
|
||||
//since 3.4.1 从接口查找,只取第一个找到的
|
||||
for (Class<?> interfaceClazz : ClassUtils.getAllInterfacesForClassAsSet(userClass)) {
|
||||
dsAttr = findDataSourceAttribute(interfaceClazz);
|
||||
dsAttr = findDataSourceAttribute(interfaceClazz, annotation);
|
||||
if (dsAttr != null) {
|
||||
return dsAttr;
|
||||
}
|
||||
@ -150,17 +193,17 @@ public class DataSourceClassResolver {
|
||||
// 如果存在桥接方法
|
||||
if (specificMethod != method) {
|
||||
// 从桥接方法查找
|
||||
dsAttr = findDataSourceAttribute(method);
|
||||
dsAttr = findDataSourceAttribute(method, annotation);
|
||||
if (dsAttr != null) {
|
||||
return dsAttr;
|
||||
}
|
||||
// 从桥接方法声明的类查找
|
||||
dsAttr = findDataSourceAttribute(method.getDeclaringClass());
|
||||
dsAttr = findDataSourceAttribute(method.getDeclaringClass(), annotation);
|
||||
if (dsAttr != null && ClassUtils.isUserLevelMethod(method)) {
|
||||
return dsAttr;
|
||||
}
|
||||
}
|
||||
return getDefaultDataSourceAttr(targetObject);
|
||||
return getDefaultDataSourceAttr(targetObject, annotation);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,13 +212,13 @@ public class DataSourceClassResolver {
|
||||
* @param targetObject 目标对象
|
||||
* @return ds
|
||||
*/
|
||||
private String getDefaultDataSourceAttr(Object targetObject) {
|
||||
private <T> BasicAttribute<T> getDefaultDataSourceAttr(Object targetObject, Class<? extends Annotation> annotation) {
|
||||
Class<?> targetClass = targetObject.getClass();
|
||||
// 如果不是代理类, 从当前类开始, 不断的找父类的声明
|
||||
if (!Proxy.isProxyClass(targetClass)) {
|
||||
Class<?> currentClass = targetClass;
|
||||
while (currentClass != Object.class) {
|
||||
String datasourceAttr = findDataSourceAttribute(currentClass);
|
||||
BasicAttribute<T> datasourceAttr = findDataSourceAttribute(currentClass, annotation);
|
||||
if (datasourceAttr != null) {
|
||||
return datasourceAttr;
|
||||
}
|
||||
@ -186,12 +229,12 @@ public class DataSourceClassResolver {
|
||||
if (mpEnabled) {
|
||||
final Class<?> clazz = getMapperInterfaceClass(targetObject);
|
||||
if (clazz != null) {
|
||||
String datasourceAttr = findDataSourceAttribute(clazz);
|
||||
BasicAttribute<T> datasourceAttr = findDataSourceAttribute(clazz, annotation);
|
||||
if (datasourceAttr != null) {
|
||||
return datasourceAttr;
|
||||
}
|
||||
// 尝试从其父接口获取
|
||||
return findDataSourceAttribute(clazz.getSuperclass());
|
||||
return findDataSourceAttribute(clazz.getSuperclass(), annotation);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@ -222,15 +265,27 @@ public class DataSourceClassResolver {
|
||||
}
|
||||
|
||||
/**
|
||||
* 通过 AnnotatedElement 查找标记的注解, 映射为 DatasourceHolder
|
||||
* 通过 AnnotatedElement 查找标记的注解, 映射为BasicAttribute
|
||||
*
|
||||
* @param ae AnnotatedElement
|
||||
* @return 数据源映射持有者
|
||||
*/
|
||||
private String findDataSourceAttribute(AnnotatedElement ae) {
|
||||
AnnotationAttributes attributes = AnnotatedElementUtils.getMergedAnnotationAttributes(ae, DS.class);
|
||||
if (attributes != null) {
|
||||
return attributes.getString("value");
|
||||
private <T> BasicAttribute<T> findDataSourceAttribute(AnnotatedElement ae, Class<? extends Annotation> annotation) {
|
||||
if (annotation.isAssignableFrom(DS.class)) {
|
||||
//AnnotatedElementUtils.findMergedAnnotation()会委托给findMergedAnnotationAttributes()
|
||||
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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user