1、创建ValidateTask切面
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidateTask {
String expression() default "";
}
2、前置通知执行过程(前置通知、环绕通知)
import com.demo.qm.aop.parser.CachedExpParser;
import com.demo.aop.parser.ExpEvalContext;
import com.demo.aop.parser.MapperRouterInvocation;
import com.demo.validate.JMException;
import java.lang.reflect.Method;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Slf4j
@Aspect
@Order(1)
@Component
@AllArgsConstructor
public class ValidateTaskAspect {
@Pointcut("@annotation(com.lachesis.windranger.qm.aop.ValidateTask)")
public void pointCut() {
}
@Before(value = "pointCut()")
public void validateTask(JoinPoint joinPoint) {
try {
MapperRouterInvocation invocation = MapperRouterInvocation.newInstance(joinPoint);
CachedExpParser cachedExpParser = CachedExpParser.newInstance(invocation);
ExpEvalContext evalContext = cachedExpParser.createEvalContext(invocation);
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
ValidateTask task = method.getAnnotation(ValidateTask.class);
// String exp = "@taskValidateService.validatePlanTask(#p0,#p1,#p2)";
// String exp = "@taskValidateService.validatePlanTask(#p0.taskCode,#p0.status,#p0.level)";
// 从注解获取表达式,执行表达式
cachedExpParser.parse(evalContext, task.expression());
} catch (JMException jmException){
throw jmException;
}catch (Exception exception) {
log.error("执行异常 error:", exception);
throw new JMException("校验失败");
}
}
@Around("pointCut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
try {
MapperRouterInvocation invocation = MapperRouterInvocation.newInstanceProceed(joinPoint);
CachedExpParser cachedExpParser = CachedExpParser.newInstance(invocation);
ExpEvalContext evalContext = cachedExpParser.createEvalContext(invocation);
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
ValidateTask task = method.getAnnotation(ValidateTask.class);
// String exp = "@taskValidateService.validatePlanTask(#p0,#p1,#p2)";
// String exp = "@taskValidateService.validatePlanTask(#p0.taskCode,#p0.status,#p0.level)";
// 从注解获取表达式,执行表达式
cachedExpParser.parse(evalContext, task.expression());
return invocation.doInvoke();
} catch (Throwable throwable) {
log.error("执行异常", throwable);
throw throwable;
}
}
}
3、核心解析部分代码
3.1 CachedExpParser
import cn.hutool.extra.spring.SpringUtil;
import org.springframework.context.expression.AnnotatedElementKey;
public class CachedExpParser {
private final EnhancedCachedExpEvaluator evaluator;
private final AnnotatedElementKey elementKey;
private CachedExpParser(MapperRouterInvocation invocation) {
this.evaluator = SpringUtil.getBean(EnhancedCachedExpEvaluator.class);
this.elementKey = invocation.getElementKey();
}
public static CachedExpParser newInstance(MapperRouterInvocation invocation) {
return new CachedExpParser(invocation);
}
public Object parse(ExpEvalContext evalContext, String exp) {
return evaluator.doParseExp(exp, elementKey, evalContext);
}
public <T> T parse(ExpEvalContext evalContext, String exp, Class<T> clazz) {
return evaluator.doParseExp(exp, elementKey, evalContext, clazz);
}
public ExpEvalContext createEvalContext(MapperRouterInvocation invocation) {
return evaluator.createEvalContext(invocation);
}
}
3.2 EnhancedCachedExpEvaluator
import com.demo.validate.JMException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.CachedExpressionEvaluator;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class EnhancedCachedExpEvaluator extends CachedExpressionEvaluator implements BeanFactoryAware {
private static final Map<ExpressionKey, Expression> KEY_CACHE = new ConcurrentHashMap<>();
private BeanFactory beanFactory;
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
public ExpEvalContext createEvalContext(MapperRouterInvocation invocation) {
ExpEvalContext context = new ExpEvalContext(invocation, super.getParameterNameDiscoverer());
if (beanFactory != null) {
context.setBeanResolver(new BeanFactoryResolver(beanFactory));
}
return context;
}
public Object doParseExp(String exp, AnnotatedElementKey methodKey, EvaluationContext evalContext) {
try {
Expression expression = getExpression(KEY_CACHE, methodKey, exp);
return expression.getValue(evalContext);
} catch (JMException jmException) {
throw jmException;
} catch (Exception e) {
log.error("表达式解析异常:expression={},method={}", exp, methodKey.toString(), e);
throw e;
}
}
public <T> T doParseExp(String exp, AnnotatedElementKey methodKey, EvaluationContext evalContext, Class<T> clazz) {
try {
Expression expression = getExpression(KEY_CACHE, methodKey, exp);
return expression.getValue(evalContext, clazz);
} catch (JMException jmException) {
throw jmException;
} catch (Exception e) {
log.error("表达式解析异常:expression={},method={}", exp, methodKey.toString(), e);
throw e;
}
}
}
3.3 ExpEvalContext
import lombok.Getter;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.core.ParameterNameDiscoverer;
@Getter
public class ExpEvalContext extends MethodBasedEvaluationContext {
private final MapperRouterInvocation invocation;
public ExpEvalContext(MapperRouterInvocation invocation, ParameterNameDiscoverer parameterNameDiscoverer) {
super(invocation.getTarget(), invocation.getMethod(), invocation.getArgs(), parameterNameDiscoverer);
this.invocation = invocation;
}
}
3.4 MapperRouterInvocation
import java.lang.reflect.Method;
import lombok.Data;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.context.expression.AnnotatedElementKey;
@Data
public class MapperRouterInvocation {
private ProceedingJoinPoint joinPoint;
private Object target;
private Class<?> declaringClass;
private Method method;
private Object[] args;
public static MapperRouterInvocation newInstance(JoinPoint joinPoint) {
MapperRouterInvocation invocation = new MapperRouterInvocation();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
Object[] args = joinPoint.getArgs();
Object target = joinPoint.getTarget();
invocation.setTarget(target);
invocation.setArgs(args);
invocation.setMethod(method);
Class<?> declaringClass = method.getDeclaringClass();
invocation.setDeclaringClass(declaringClass);
return invocation;
}
public static MapperRouterInvocation newInstanceProceed(ProceedingJoinPoint joinPoint) {
MapperRouterInvocation invocation = new MapperRouterInvocation();
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
Object[] args = joinPoint.getArgs();
Object target = joinPoint.getTarget();
invocation.setTarget(target);
invocation.setJoinPoint(joinPoint);
invocation.setArgs(args);
Class<?> declaringClass = method.getDeclaringClass();
invocation.setDeclaringClass(declaringClass);
invocation.setMethod(method);
return invocation;
}
// 后置通知
public Object doInvoke() throws Throwable {
return joinPoint.proceed();
}
public AnnotatedElementKey getElementKey() {
return new AnnotatedElementKey(method, declaringClass);
}
}
4、公共内容
4.1 JMException
public class JMException extends RuntimeException {
private int errCode = 1002;
private String msgZ;
private String msgE;
public JMException() {
super();
}
public JMException(String msgZ) {
super(msgZ);
this.msgZ = msgZ;
}
public JMException(int errCode) {
this.errCode = errCode;
}
public JMException(int errCode, String msgZ) {
super(msgZ);
this.errCode = errCode;
this.msgZ = msgZ;
}
public JMException(int errCode, String msgZ, String msgE) {
super(msgZ);
this.errCode = errCode;
this.msgZ = msgZ;
this.msgE = msgE;
}
public int getErrCode() {
return errCode;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
public String getMsgZ() {
return msgZ;
}
public void setMsgZ(String msgZ) {
this.msgZ = msgZ;
}
public String getMsgE() {
return msgE;
}
public void setMsgE(String msgE) {
this.msgE = msgE;
}
}
4.2 pom.xml 引入hutool 工具
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.18</version>
</dependency>
5、执行的service层方法
public interface ITaskValidateService {
void validatePlanTask(String taskCode,Integer status,String controlLevel);
// 用法 @taskValidateService.validatePlanTaskByIds(T(com.google.common.collect.Lists).newArrayList(#p0), #p1, #p2);
void validatePlanTaskByIds(List<Long> seqIds, Integer status, String controlLevel);
void rejectValidate(Long seqId, Integer status, String controlLevel);
void temporaryStorageValidate(String taskCode, String controlLevel);
}