Chr*_*ris 12 spring annotations aspectj spring-el
我正在尝试使用类似的东西org.springframework.cache.annotation.Cacheable:
自定义注释:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckEntity {
String message() default "Check entity msg";
String key() default "";
}
Run Code Online (Sandbox Code Playgroud)
方面:
@Component
@Aspect
public class CheckEntityAspect {
@Before("execution(* *.*(..)) && @annotation(checkEntity)")
public void checkEntity(JoinPoint joinPoint, CheckEntitty checkEntity) {
System.out.println("running entity check: " + joinPoint.getSignature().getName());
}
}
Run Code Online (Sandbox Code Playgroud)
服务:
@Service
@Transactional
public class EntityServiceImpl implements EntityService {
@CheckEntity(key = "#id")
public Entity getEntity(Long id) {
return new Entity(id);
}
}
Run Code Online (Sandbox Code Playgroud)
我的IDE(IntelliJ)没有看到任何与key = "#id"使用有关的特殊情况,与使用Cacheable不同颜色而不是纯文本的类似用法相比.我提到IDE部分只是作为一个提示,如果有帮助,看起来IDE预先知道这些注释或它只是意识到我的例子中不存在的一些连接.
checkEntity.key中的值为"#id"而不是预期的数字.我尝试使用ExpressionParser但可能不是以正确的方式.
在checkEntity注释中获取参数值的唯一方法是访问arguments数组,这不是我想要的,因为这个注释也可以在具有多个参数的方法中使用.
任何的想法?
感谢@StéphaneNicoll,我成功创建了工作解决方案的第一个版本:
方面
@Component
@Aspect
public class CheckEntityAspect {
protected final Log logger = LogFactory.getLog(getClass());
private ExpressionEvaluator<Long> evaluator = new ExpressionEvaluator<>();
@Before("execution(* *.*(..)) && @annotation(checkEntity)")
public void checkEntity(JoinPoint joinPoint, CheckEntity checkEntity) {
Long result = getValue(joinPoint, checkEntity.key());
logger.info("result: " + result);
System.out.println("running entity check: " + joinPoint.getSignature().getName());
}
private Long getValue(JoinPoint joinPoint, String condition) {
return getValue(joinPoint.getTarget(), joinPoint.getArgs(),
joinPoint.getTarget().getClass(),
((MethodSignature) joinPoint.getSignature()).getMethod(), condition);
}
private Long getValue(Object object, Object[] args, Class clazz, Method method, String condition) {
if (args == null) {
return null;
}
EvaluationContext evaluationContext = evaluator.createEvaluationContext(object, clazz, method, args);
AnnotatedElementKey methodKey = new AnnotatedElementKey(method, clazz);
return evaluator.condition(condition, methodKey, evaluationContext, Long.class);
}
}
Run Code Online (Sandbox Code Playgroud)
表达式评估器
public class ExpressionEvaluator<T> extends CachedExpressionEvaluator {
// shared param discoverer since it caches data internally
private final ParameterNameDiscoverer paramNameDiscoverer = new DefaultParameterNameDiscoverer();
private final Map<ExpressionKey, Expression> conditionCache = new ConcurrentHashMap<>(64);
private final Map<AnnotatedElementKey, Method> targetMethodCache = new ConcurrentHashMap<>(64);
/**
* Create the suitable {@link EvaluationContext} for the specified event handling
* on the specified method.
*/
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);
}
/**
* Specify if the condition defined by the specified expression matches.
*/
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;
}
}
Run Code Online (Sandbox Code Playgroud)
根对象
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;
}
}
Run Code Online (Sandbox Code Playgroud)
使用Spring Expression添加另一种更简单的方法。请参阅以下内容:
您的注释:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface CheckEntity {
String message() default "Check entity msg";
String keyPath() default "";
}
Run Code Online (Sandbox Code Playgroud)
您的服务:
@Service
@Transactional
public class EntityServiceImpl implements EntityService {
@CheckEntity(keyPath = "[0]")
public Entity getEntity(Long id) {
return new Entity(id);
}
@CheckEntity(keyPath = "[1].otherId")
public Entity methodWithMoreThanOneArguments(String message, CustomClassForExample object) {
return new Entity(object.otherId);
}
}
class CustomClassForExample {
Long otherId;
}
Run Code Online (Sandbox Code Playgroud)
您的观点:
@Component
@Aspect
public class CheckEntityAspect {
@Before("execution(* *.*(..)) && @annotation(checkEntity)")
public void checkEntity(JoinPoint joinPoint, CheckEntitty checkEntity) {
Object[] args = joinPoint.getArgs();
ExpressionParser elParser = new SpelExpressionParser();
Expression expression = elParser.parseExpression(checkEntity.keyPath());
Long id = (Long) expression.getValue(args);
// Do whatever you want to do with this id
// This works for both the service methods provided above and can be re-used for any number of similar methods
}
}
Run Code Online (Sandbox Code Playgroud)
PS:我添加此解决方案是因为与其他答案相比,这是一种更简单/更清晰的方法,这可能对某人有所帮助。
| 归档时间: |
|
| 查看次数: |
8081 次 |
| 最近记录: |