平。
我正在编写@Aspect来记录我的持久层。
首先可能会向有经验的开发人员显示错误的代码;)
/** Interface of the class to observe. */
public interface PersistenceService {
public Serializable save(Serializable serializable);
public List<Serializable> save(List<Serializable> list)
}
/** Actual class to observe. */
@Service
public class PersistenceService {
@Autowired
private SomeJpaRepository rep;
public Serializable save(Serializable serializable) {
return rep.save(serializable);
}
public List<Serializable> save(List<Serializable> list) {
return rep.save(list);
}
}
这里的方面:
/** The Aspect. */
@Aspect
@Component
public class PersistenceService {
/** A org.slf4j.Logger (using logback). */
private final Logger logger = LoggerFactory.getLogger(getClass());
/** Pointcut to define the classes to observe. */
@Pointcut("within(de.mypckg.myproject.persistence.*.*)")
public void inPersistanceLayer() {}
/** Pointcut for the first save-method. */
@Pointcut("execution(public * save(..)) && args(serializable)")
public void saveOperation(Serializable serializable) {}
/** Pointcut for the first save-method. */
@Pointcut("execution(public * save(..)) && args(list)")
public void saveOperation(List<Serializable> list) {}
/** Method for the first save-method. */
@Around("inPersistanceLayer() && saveOperation(serializable)")
public List<Serializable> logSave(ProceedingJoinPoint joinPoint, Serializable serializable) throws Throwable {
// log some stuff
Object saved = joinPoint.proceed();
// log somemore stuff
}
/** Method for the second save-method. */
@Around("inPersistanceLayer() && saveOperation(list)")
public List<Serializable> logSave(ProceedingJoinPoint joinPoint, List<Serializable> list) throws Throwable {
// log some stuff
Object saved = joinPoint.proceed();
// log somemore stuff
}
}
如果我只有一个切入点(以及它的方法),它可以工作,但如果我添加第二个,我会得到以下异常:
java.lang.IllegalArgumentException: warning no match for this type name: list [Xlint:invalidAbsoluteTypeName]
我改变了切入点的顺序,它总是排在第二位。关于如何解决这个问题的任何想法?
更新
一旦我发布了这个问题,我就有了一个想法。我改变了像这样的切入点:
/** The Aspect. */
@Aspect
@Component
public class PersistenceService {
/** A org.slf4j.Logger (using logback). */
private final Logger logger = LoggerFactory.getLogger(getClass());
/** Pointcut to define the classes to observe. */
@Pointcut("within(de.mypckg.myproject.persistence.*.*)")
public void inPersistanceLayer() {}
/** Pointcut for the save-method. */
@Pointcut("execution(public * save(..))")
public void saveOperation() {}
/** Pointcut for the serializable argument. */
@Pointcut("args(serializable)")
public void serializableArgument(Serializable serializable) {}
/** Pointcut for the list argument. */
@Pointcut("args(list)")
public void listArgument(List<Serializable> list) {}
/** Method for the first save-method. */
@Around("inPersistanceLayer() && saveOperation() && serializableArgument(serializable)")
public Object logSave(ProceedingJoinPoint joinPoint, Serializable serializable) throws Throwable {
// log some stuff
Object saved = joinPoint.proceed();
// log somemore stuff
return saved;
}
/** Method for the second save-method. */
@Around("inPersistanceLayer() && saveOperation(list) && listArgument(list)")
public Object logSave(ProceedingJoinPoint joinPoint, List<Serializable> list) throws Throwable {
// log some stuff
Object saved = joinPoint.proceed();
// log somemore stuff
return saved;
}
}
现在异常消失了,但仍然存在一个小问题(我猜这个问题要容易得多):由于ArrayList实现了Serializable,所以两个切入点都被执行,至少在我使用ArrayList的测试用例中。 /> 我将调查并发布我发现的内容,但也感谢帮助;)
更新2
更正了kriegaex声明的复制粘贴错误。谢谢!
方法logSave(..)的返回类型是Object。
更新3
我将代码更改为仅使用一个切入点和一个方法,并使用像kriegaex提议的instanceof进行检查。
/** The Aspect. */
@Aspect
@Component
public class PersistenceService {
/** A org.slf4j.Logger (using logback). */
private final Logger logger = LoggerFactory.getLogger(getClass());
/** Pointcut to define the classes to observe. */
@Pointcut("within(de.mypckg.myproject.persistence.*.*)")
public void inPersistanceLayer() {}
/** Pointcut for the save-method. */
@Pointcut("execution(public * save(*)) && args(serializable)")
public void saveOperation(Serializable serializable) {}
/** Method for the first save-method. */
@Around("inPersistanceLayer() && saveOperation() && serializableArgument(serializable)")
public Serializable logSave(ProceedingJoinPoint joinPoint, Serializable serializable) throws Throwable {
// log some stuff
Serializable saved = (Serializable) joinPoint.proceed();
if (saved instanceof List<?>) {
List<?> savedList = (List<?>) saved;
// log somemore stuff with a List
} else {
// log somemore stuff
}
return saved;
}
}
我仍然想知道为什么它不起作用。
答案 0 :(得分:1)
以下是两个选项:
申请类
package de.scrum_master.aspectj.sample;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
public class TestApp {
public static void main(String[] args) {
save(new HashSet<String>());
List<Serializable> arg = new ArrayList<Serializable>();
save(arg);
}
static Serializable save(Serializable arg) { return arg; }
static List<Serializable> save(List<Serializable> arg) { return arg; }
}
<强>方面强>
package de.scrum_master.aspectj.sample;
import java.io.Serializable;
import java.util.List;
public aspect TestAspect {
pointcut saveOperation(Object arg) : execution(* save(*)) && args(arg);
pointcut serializableArgument(Serializable serializable) : execution(* save(Serializable)) && args(serializable);
pointcut listArgument(List<Serializable> list) : execution(* save(List<Serializable>)) && args(list);
Object around(Object arg) : saveOperation(arg) {
if (arg instanceof List)
System.out.println("Global advice [List]: " + thisJoinPointStaticPart.getSignature());
else
System.out.println("Global advice [Serializable]: " + thisJoinPointStaticPart.getSignature());
return proceed(arg);
}
List<Serializable> around(List<Serializable> list) : listArgument(list) {
System.out.println("Specific advice [List]: " + thisJoinPointStaticPart.getSignature());
return proceed(list);
}
Serializable around(Serializable serializable) : serializableArgument(serializable) {
System.out.println("Specific advice [Serializable]: " + thisJoinPointStaticPart.getSignature());
return proceed(serializable);
}
}
正如您所看到的,返回类型Object
和使用简单切入点saveOperation(Object arg)
的第一个建议是通用的一站式购物解决方案。另外两个建议是特定于参数类型的,每个都使用单独的切入点。如果编织并运行应用程序类,则会产生以下输出:
Global advice [Serializable]: Serializable de.scrum_master.aspectj.sample.TestApp.save(Serializable)
Specific advice [Serializable]: Serializable de.scrum_master.aspectj.sample.TestApp.save(Serializable)
Global advice [List]: List de.scrum_master.aspectj.sample.TestApp.save(List)
Specific advice [List]: List de.scrum_master.aspectj.sample.TestApp.save(List)
使用切入点serializableArgument(Serializable serializable)
的建议只会触发一次,就像你想要的那样。
答案 1 :(得分:0)
如果将切入点写为
,则存在差异args(java.io.Serializable)
或
execution(* *(java.io.Serializable))
如果参数在运行时中为Serializable
,则前者匹配,后者仅与声明类型{{1}的单个参数的方法签名匹配}。在您的示例中,您使用Serializable
作为..
的参数,这意味着将匹配任意数量的方法参数。
查看Spring参考文档中的pointcut examples。特别是,我认为您会发现execution
讨论很有趣。
编辑:
请注意,您无法将args
变体用于绑定,但您可以轻松地使用execution
将两者结合起来,例如。
&&
和
@Pointcut("execution(public * save(java.io.Serializable)) && args(serializable)")
public void saveOperation(Serializable serializable) {}