mirror of https://gitee.com/y_project/RuoYi.git
Pre Merge pull request !352 from 摸摸鼻子/master
commit
201576b5a1
|
@ -25,4 +25,10 @@ public @interface DataSource
|
|||
* 切换数据源名称
|
||||
*/
|
||||
public DataSourceType value() default DataSourceType.MASTER;
|
||||
|
||||
/**
|
||||
* 支持通过el表达式从参数获取切换名称
|
||||
* example: elValue="#field" (从参数获取) 或 "#pojo.field" (从对象获取)
|
||||
*/
|
||||
String elValue() default "";
|
||||
}
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package com.ruoyi.common.enums;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 数据源
|
||||
*
|
||||
|
@ -15,5 +19,16 @@ public enum DataSourceType
|
|||
/**
|
||||
* 从库
|
||||
*/
|
||||
SLAVE
|
||||
SLAVE;
|
||||
|
||||
private static final Set<String> DATA_SOURCE_TYPE_SET;
|
||||
|
||||
static {
|
||||
DATA_SOURCE_TYPE_SET = Arrays.stream(DataSourceType.values())
|
||||
.map(DataSourceType::name).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static boolean contains(String sourceType){
|
||||
return DATA_SOURCE_TYPE_SET.contains(sourceType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package com.ruoyi.common.utils.el;
|
||||
|
||||
import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.context.expression.AnnotatedElementKey;
|
||||
import org.springframework.context.expression.CachedExpressionEvaluator;
|
||||
import org.springframework.context.expression.MethodBasedEvaluationContext;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author : mudi
|
||||
* @date : Created in 2021/12/3 21:02
|
||||
* @description :
|
||||
* @modified By :
|
||||
*/
|
||||
public class ExpressionEvaluator<T> extends CachedExpressionEvaluator {
|
||||
private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
|
||||
private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);
|
||||
private final Map<AnnotatedElementKey, Method> targetMethodCache = new ConcurrentHashMap<>(64);
|
||||
|
||||
|
||||
public EvaluationContext createEvaluationContext(Object object, Class<?> targetClass, Method method, Object[] args) {
|
||||
Method targetMethod = getTargetMethod(targetClass, method);
|
||||
ExpressionRootObject root = new ExpressionRootObject(object, args);
|
||||
return new MethodBasedEvaluationContext(root, targetMethod, args, this.paramNameDiscoverer);
|
||||
}
|
||||
|
||||
|
||||
public T condition(String conditionExpression, AnnotatedElementKey elementKey, EvaluationContext evalContext, Class<T> clazz) {
|
||||
return getExpression(this.conditionCache, elementKey, conditionExpression).getValue(evalContext, clazz);
|
||||
}
|
||||
|
||||
private Method getTargetMethod(Class<?> targetClass, Method method) {
|
||||
AnnotatedElementKey methodKey = new AnnotatedElementKey(method, targetClass);
|
||||
Method targetMethod = this.targetMethodCache.get(methodKey);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = AopUtils.getMostSpecificMethod(method, targetClass);
|
||||
if (targetMethod == null) {
|
||||
targetMethod = method;
|
||||
}
|
||||
this.targetMethodCache.put(methodKey, targetMethod);
|
||||
}
|
||||
return targetMethod;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
package com.ruoyi.common.utils.el;
|
||||
|
||||
/**
|
||||
* @author : mudi
|
||||
* @date : Created in 2021/12/3 21:03
|
||||
* @description :
|
||||
* @modified By :
|
||||
*/
|
||||
public class ExpressionRootObject {
|
||||
private final Object object;
|
||||
private final Object[] args;
|
||||
|
||||
public ExpressionRootObject(Object object, Object[] args) {
|
||||
this.object = object;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
public Object getObject() {
|
||||
return object;
|
||||
}
|
||||
|
||||
public Object[] getArgs() {
|
||||
return args;
|
||||
}
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
package com.ruoyi.framework.aspectj;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
import com.ruoyi.common.enums.DataSourceType;
|
||||
import com.ruoyi.common.utils.el.ExpressionEvaluator;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
|
@ -8,8 +12,10 @@ import org.aspectj.lang.annotation.Pointcut;
|
|||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.expression.AnnotatedElementKey;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.stereotype.Component;
|
||||
import com.ruoyi.common.annotation.DataSource;
|
||||
import com.ruoyi.common.config.datasource.DynamicDataSourceContextHolder;
|
||||
|
@ -27,6 +33,8 @@ public class DataSourceAspect
|
|||
{
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private ExpressionEvaluator<String> evaluator = new ExpressionEvaluator<>();
|
||||
|
||||
@Pointcut("@annotation(com.ruoyi.common.annotation.DataSource)"
|
||||
+ "|| @within(com.ruoyi.common.annotation.DataSource)")
|
||||
public void dsPointCut()
|
||||
|
@ -34,6 +42,18 @@ public class DataSourceAspect
|
|||
|
||||
}
|
||||
|
||||
private String getValueByEl(DataSource dataSource, JoinPoint joinPoint)
|
||||
{
|
||||
if (Objects.equals(dataSource.elValue(), ""))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
EvaluationContext evaluationContext = evaluator.createEvaluationContext(joinPoint.getTarget(), joinPoint.getTarget().getClass(), ((MethodSignature) joinPoint.getSignature()).getMethod(), joinPoint.getArgs());
|
||||
AnnotatedElementKey methodKey = new AnnotatedElementKey(((MethodSignature) joinPoint.getSignature()).getMethod(), joinPoint.getTarget().getClass());
|
||||
return evaluator.condition(dataSource.elValue(), methodKey, evaluationContext, String.class);
|
||||
}
|
||||
|
||||
@Around("dsPointCut()")
|
||||
public Object around(ProceedingJoinPoint point) throws Throwable
|
||||
{
|
||||
|
@ -41,7 +61,9 @@ public class DataSourceAspect
|
|||
|
||||
if (StringUtils.isNotNull(dataSource))
|
||||
{
|
||||
DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
|
||||
String elValue = getValueByEl(dataSource, point);
|
||||
String value = DataSourceType.contains(elValue) ? elValue : dataSource.value().name();
|
||||
DynamicDataSourceContextHolder.setDataSourceType(value);
|
||||
}
|
||||
|
||||
try
|
||||
|
|
Loading…
Reference in New Issue