自定义注解
自定义 DistributeExceptionHandler
注解,该注解接收一个参数 attachmentId
。
该注解用在方法上,使用该注解作为切点,实现标注该注解的方法抛异常后的统一处理。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DistributeExceptionHandler {
String attachmentId();
}
注解使用方法
代码语言:javascript复制@DistributeExceptionHandler(attachmentId = "#test.id")
public void test(Test test){
}
Aspect代码
拦截 DistributeExceptionHandler
注解作为切点
使用 @AfterThrowing
处理异常情况
@Component
@Aspect
@Slf4j
public class DistributeExceptionAspect {
@Autowired
private AttachmentContentClient attachmentContentClient;
@Autowired
private DistTaskService distTaskService;
private ExpressionEvaluator evaluator = new ExpressionEvaluator<>();
@Pointcut("@annotation(DistributeExceptionHandler)")
private void exceptionHandleMethod() {
}
@AfterThrowing(value = "exceptionHandleMethod()", throwing = "ex")
public void doThrowing(JoinPoint joinPoint, Throwable ex) {
log.error("捕获异常");
String attachmentId = getAttachmentId(joinPoint); // 获取
// 处理异常情况下的业务
}
private DistributeExceptionHandler getDistributeExceptionHandler(JoinPoint joinPoint){
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
return method.getAnnotation(DistributeExceptionHandler.class);
}
private String getAttachmentId(JoinPoint joinPoint) {
DistributeExceptionHandler handler = getDistributeExceptionHandler(joinPoint);
if (joinPoint.getArgs() == null) {
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(handler.attachmentId(), methodKey, evaluationContext, String.class);
}
}
为注解添加Spring EL支持
ExpressionRootObject
代码语言:javascript复制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;
}
}
ExpressionEvaluator
代码语言:javascript复制public class ExpressionEvaluator extends CachedExpressionEvaluator {
private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
private final Map conditionCache = new ConcurrentHashMap<>(64);
private final Map 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 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;
}
}
参考:stackoverflow。
SPEL表达式计算引擎
代码语言:javascript复制import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.expression.AnnotatedElementKey;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.context.expression.CachedExpressionEvaluator;
import org.springframework.context.expression.MethodBasedEvaluationContext;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class SimpleExpressionEvaluator extends CachedExpressionEvaluator {
private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<ExpressionKey, Expression>(64);
public EvaluationContext createMethodBasedEvaluationContext(Method method, Object[] args, BeanFactory beanFactory) {
MethodBasedEvaluationContext evaluationContext =
new MethodBasedEvaluationContext(null, method, args, getParameterNameDiscoverer());
if (beanFactory != null) {
evaluationContext.setBeanResolver(new BeanFactoryResolver(beanFactory));
}
return evaluationContext;
}
public <T> T eval(String expression, AnnotatedElementKey elementKey, EvaluationContext evalContext) {
return (T) getExpression(elementKey, expression).getValue(evalContext);
}
public Expression getExpression(AnnotatedElementKey elementKey, String expression) {
return getExpression(this.conditionCache, elementKey, expression);
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.context.expression;
import java.util.Map;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
public abstract class CachedExpressionEvaluator {
private final SpelExpressionParser parser;
private final ParameterNameDiscoverer parameterNameDiscoverer;
protected CachedExpressionEvaluator(SpelExpressionParser parser) {
this.parameterNameDiscoverer = new DefaultParameterNameDiscoverer();
Assert.notNull(parser, "SpelExpressionParser must not be null");
this.parser = parser;
}
protected CachedExpressionEvaluator() {
this(new SpelExpressionParser());
}
protected SpelExpressionParser getParser() {
return this.parser;
}
protected ParameterNameDiscoverer getParameterNameDiscoverer() {
return this.parameterNameDiscoverer;
}
protected Expression getExpression(Map<CachedExpressionEvaluator.ExpressionKey, Expression> cache, AnnotatedElementKey elementKey, String expression) {
CachedExpressionEvaluator.ExpressionKey expressionKey = this.createKey(elementKey, expression);
Expression expr = (Expression)cache.get(expressionKey);
if (expr == null) {
expr = this.getParser().parseExpression(expression);
cache.put(expressionKey, expr);
}
return expr;
}
private CachedExpressionEvaluator.ExpressionKey createKey(AnnotatedElementKey elementKey, String expression) {
return new CachedExpressionEvaluator.ExpressionKey(elementKey, expression);
}
protected static class ExpressionKey implements Comparable<CachedExpressionEvaluator.ExpressionKey> {
private final AnnotatedElementKey element;
private final String expression;
protected ExpressionKey(AnnotatedElementKey element, String expression) {
this.element = element;
this.expression = expression;
}
public boolean equals(Object other) {
if (this == other) {
return true;
} else if (!(other instanceof CachedExpressionEvaluator.ExpressionKey)) {
return false;
} else {
CachedExpressionEvaluator.ExpressionKey otherKey = (CachedExpressionEvaluator.ExpressionKey)other;
return this.element.equals(otherKey.element) && ObjectUtils.nullSafeEquals(this.expression, otherKey.expression);
}
}
public int hashCode() {
return this.element.hashCode() (this.expression != null ? this.expression.hashCode() * 29 : 0);
}
public String toString() {
return this.element (this.expression != null ? " with expression "" this.expression : """);
}
public int compareTo(CachedExpressionEvaluator.ExpressionKey other) {
int result = this.element.toString().compareTo(other.element.toString());
if (result == 0 && this.expression != null) {
result = this.expression.compareTo(other.expression);
}
return result;
}
}
}
核心接口
EvaluationContext
代码语言:javascript复制//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.expression;
import java.util.List;
public interface EvaluationContext {
TypedValue getRootObject();
List<ConstructorResolver> getConstructorResolvers();
List<MethodResolver> getMethodResolvers();
List<PropertyAccessor> getPropertyAccessors();
TypeLocator getTypeLocator();
TypeConverter getTypeConverter();
TypeComparator getTypeComparator();
OperatorOverloader getOperatorOverloader();
BeanResolver getBeanResolver();
void setVariable(String var1, Object var2);
Object lookupVariable(String var1);
}
StandardEvaluationContext
代码语言:javascript复制package org.springframework.expression.spel.support;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.ConstructorResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.MethodFilter;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.OperatorOverloader;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypeComparator;
import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypeLocator;
import org.springframework.expression.TypedValue;
import org.springframework.util.Assert;
public class StandardEvaluationContext implements EvaluationContext {
private TypedValue rootObject;
private List<ConstructorResolver> constructorResolvers;
private List<MethodResolver> methodResolvers;
private BeanResolver beanResolver;
private ReflectiveMethodResolver reflectiveMethodResolver;
private List<PropertyAccessor> propertyAccessors;
private TypeLocator typeLocator;
private TypeConverter typeConverter;
private TypeComparator typeComparator = new StandardTypeComparator();
private OperatorOverloader operatorOverloader = new StandardOperatorOverloader();
private final Map<String, Object> variables = new HashMap();
public StandardEvaluationContext() {
this.setRootObject((Object)null);
}
public StandardEvaluationContext(Object rootObject) {
this.setRootObject(rootObject);
}
public void setRootObject(Object rootObject, TypeDescriptor typeDescriptor) {
this.rootObject = new TypedValue(rootObject, typeDescriptor);
}
public void setRootObject(Object rootObject) {
this.rootObject = rootObject != null ? new TypedValue(rootObject) : TypedValue.NULL;
}
public TypedValue getRootObject() {
return this.rootObject;
}
public void setPropertyAccessors(List<PropertyAccessor> propertyAccessors) {
this.propertyAccessors = propertyAccessors;
}
public List<PropertyAccessor> getPropertyAccessors() {
this.ensurePropertyAccessorsInitialized();
return this.propertyAccessors;
}
public void addPropertyAccessor(PropertyAccessor accessor) {
this.ensurePropertyAccessorsInitialized();
this.propertyAccessors.add(this.propertyAccessors.size() - 1, accessor);
}
public boolean removePropertyAccessor(PropertyAccessor accessor) {
return this.propertyAccessors.remove(accessor);
}
public void setConstructorResolvers(List<ConstructorResolver> constructorResolvers) {
this.constructorResolvers = constructorResolvers;
}
public List<ConstructorResolver> getConstructorResolvers() {
this.ensureConstructorResolversInitialized();
return this.constructorResolvers;
}
public void addConstructorResolver(ConstructorResolver resolver) {
this.ensureConstructorResolversInitialized();
this.constructorResolvers.add(this.constructorResolvers.size() - 1, resolver);
}
public boolean removeConstructorResolver(ConstructorResolver resolver) {
this.ensureConstructorResolversInitialized();
return this.constructorResolvers.remove(resolver);
}
public void setMethodResolvers(List<MethodResolver> methodResolvers) {
this.methodResolvers = methodResolvers;
}
public List<MethodResolver> getMethodResolvers() {
this.ensureMethodResolversInitialized();
return this.methodResolvers;
}
public void addMethodResolver(MethodResolver resolver) {
this.ensureMethodResolversInitialized();
this.methodResolvers.add(this.methodResolvers.size() - 1, resolver);
}
public boolean removeMethodResolver(MethodResolver methodResolver) {
this.ensureMethodResolversInitialized();
return this.methodResolvers.remove(methodResolver);
}
public void setBeanResolver(BeanResolver beanResolver) {
this.beanResolver = beanResolver;
}
public BeanResolver getBeanResolver() {
return this.beanResolver;
}
public void setTypeLocator(TypeLocator typeLocator) {
Assert.notNull(typeLocator, "TypeLocator must not be null");
this.typeLocator = typeLocator;
}
public TypeLocator getTypeLocator() {
if (this.typeLocator == null) {
this.typeLocator = new StandardTypeLocator();
}
return this.typeLocator;
}
public void setTypeConverter(TypeConverter typeConverter) {
Assert.notNull(typeConverter, "TypeConverter must not be null");
this.typeConverter = typeConverter;
}
public TypeConverter getTypeConverter() {
if (this.typeConverter == null) {
this.typeConverter = new StandardTypeConverter();
}
return this.typeConverter;
}
public void setTypeComparator(TypeComparator typeComparator) {
Assert.notNull(typeComparator, "TypeComparator must not be null");
this.typeComparator = typeComparator;
}
public TypeComparator getTypeComparator() {
return this.typeComparator;
}
public void setOperatorOverloader(OperatorOverloader operatorOverloader) {
Assert.notNull(operatorOverloader, "OperatorOverloader must not be null");
this.operatorOverloader = operatorOverloader;
}
public OperatorOverloader getOperatorOverloader() {
return this.operatorOverloader;
}
public void setVariable(String name, Object value) {
this.variables.put(name, value);
}
public void setVariables(Map<String, Object> variables) {
this.variables.putAll(variables);
}
public void registerFunction(String name, Method method) {
this.variables.put(name, method);
}
public Object lookupVariable(String name) {
return this.variables.get(name);
}
public void registerMethodFilter(Class<?> type, MethodFilter filter) throws IllegalStateException {
this.ensureMethodResolversInitialized();
if (this.reflectiveMethodResolver != null) {
this.reflectiveMethodResolver.registerMethodFilter(type, filter);
} else {
throw new IllegalStateException("Method filter cannot be set as the reflective method resolver is not in use");
}
}
private void ensurePropertyAccessorsInitialized() {
if (this.propertyAccessors == null) {
this.initializePropertyAccessors();
}
}
private synchronized void initializePropertyAccessors() {
if (this.propertyAccessors == null) {
List<PropertyAccessor> defaultAccessors = new ArrayList();
defaultAccessors.add(new ReflectivePropertyAccessor());
this.propertyAccessors = defaultAccessors;
}
}
private void ensureConstructorResolversInitialized() {
if (this.constructorResolvers == null) {
this.initializeConstructorResolvers();
}
}
private synchronized void initializeConstructorResolvers() {
if (this.constructorResolvers == null) {
List<ConstructorResolver> defaultResolvers = new ArrayList();
defaultResolvers.add(new ReflectiveConstructorResolver());
this.constructorResolvers = defaultResolvers;
}
}
private void ensureMethodResolversInitialized() {
if (this.methodResolvers == null) {
this.initializeMethodResolvers();
}
}
private synchronized void initializeMethodResolvers() {
if (this.methodResolvers == null) {
List<MethodResolver> defaultResolvers = new ArrayList();
this.reflectiveMethodResolver = new ReflectiveMethodResolver();
defaultResolvers.add(this.reflectiveMethodResolver);
this.methodResolvers = defaultResolvers;
}
}
}
MethodBasedEvaluationContext
代码语言:javascript复制//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package org.springframework.context.expression;
import java.lang.reflect.Method;
import java.util.Arrays;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.ObjectUtils;
public class MethodBasedEvaluationContext extends StandardEvaluationContext {
private final Method method;
private final Object[] arguments;
private final ParameterNameDiscoverer parameterNameDiscoverer;
private boolean argumentsLoaded = false;
public MethodBasedEvaluationContext(Object rootObject, Method method, Object[] arguments, ParameterNameDiscoverer parameterNameDiscoverer) {
super(rootObject);
this.method = method;
this.arguments = arguments;
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
public Object lookupVariable(String name) {
Object variable = super.lookupVariable(name);
if (variable != null) {
return variable;
} else {
if (!this.argumentsLoaded) {
this.lazyLoadArguments();
this.argumentsLoaded = true;
variable = super.lookupVariable(name);
}
return variable;
}
}
protected void lazyLoadArguments() {
if (!ObjectUtils.isEmpty(this.arguments)) {
String[] paramNames = this.parameterNameDiscoverer.getParameterNames(this.method);
int paramCount = paramNames != null ? paramNames.length : this.method.getParameterTypes().length;
int argsCount = this.arguments.length;
for(int i = 0; i < paramCount; i) {
Object value = null;
if (argsCount > paramCount && i == paramCount - 1) {
value = Arrays.copyOfRange(this.arguments, i, argsCount);
} else if (argsCount > i) {
value = this.arguments[i];
}
this.setVariable("a" i, value);
this.setVariable("p" i, value);
if (paramNames != null) {
this.setVariable(paramNames[i], value);
}
}
}
}
}