在Spring 3 webapp中,我有一个DAO,看起来像这样:
public class BaseDAOImpl<T extends AbstractEntity> implements BaseDAO<T> {
...
public void doSomething(Class<T> clazz) {
log.debug("class name: " + clazz.getName());
...
}
...
}
该日志打印我要查找的内容,例如com.xyz.Customer。
但是上面的日志线只是为了说明。在应用程序中,我使用一个方面来处理日志。在这方面,我记录了争论。所以在我的@Before
建议中,我有一些这样的代码:
...
Object[] args = joinPoint.getArgs();
for (Object o : args) {
...
log.debug("class name: " + o.getClass().getName());
...
并且当它运行在BaseDAOImlp的doSomething()
中的clazz
时,它记录为java.lang.Class。
doSomething()
中的getName()
调用,但java.lang.Class在方面。
在第二个示例中,实例已被升级为Object
,而在第一个示例中,提供了实际的Class
。在这个上升过程中,o
是其他类型的事实丢失了。
调用clazz.getName()
时不考虑泛型参数,因为代码打印类的实际类型。
List<String> list
仍然是List
。我们不能确定List
是否有提供的类型为String
的泛型参数,这一事实证明了类型消除的概念。不管类型擦除,调用list.getClass().getName()
返回原始类型java.util.List
,而不管提供的泛型参数。
为了记录我想要的信息,我使用了两个不同的切入点。其中一个切入点识别出java.lang.Class
是dao中方法的第一个参数,并将参数传递给通知。
(幸运的是,根据我们代码库中的约定,当DAO接受类参数时,它总是首先出现。这不是一个非常通用的解决方案。
切入点是这样的:
@Pointcut("execution(* com.xyz.dao..*.*(..)) && args(clazz,..)")
public void classyDAOMethods(Class<?> clazz) { ... }
@Pointcut("execution(* com.xyz.dao..*.*(..)) && !args(java.lang.Class,..)")
public void unclassyDAOMethods() { ... }
这个建议处理每个切口的方式略有不同:
@Before("classyDAOMethods(clazz)")
public void classyAdvice(JoinPoint joinPoint, Class<?> clazz) {
logMethodEntry(joinPoint, clazz);
}
@Before("unclassyDAOMethods()")
public void logMethodEntry(JoinPoint joinPoint) {
logMethodEntry(joinPoint, null);
}
在第一个@Before
中传递的clazz
具有我需要的日志的类名。