简体   繁体   English

方面与实例方法中的类getName()行为

[英]Class getName() behavior in aspect vs instance method

In a Spring 3 webapp, I have a DAO that looks something like this: 在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());
        ...
    }

   ...
}

That log prints what I'm looking for, let's say com.xyz.Customer . 该日志打印出我正在寻找的内容,例如com.xyz.Customer

But that logging line above is just for illustration. 但是上面的那条测井线只是为了说明。 In the app, I'm using an aspect to handle logging. 在应用程序中,我正在使用一个方面来处理日志记录。 And in that aspect, I'm recording arguments. 在这方面,我正在记录参数。 So in my @Before advice, I have some code like this: 所以在我的@Before建议中,我有一些像这样的代码:

...
Object[] args = joinPoint.getArgs();
for (Object o : args) {
    ...
    log.debug("class name: " + o.getClass().getName());
    ...

And when that runs against clazz in BaseDAOImlp's doSomething() , it logs as java.lang.Class . 并且在BaseDAOImlp的doSomething()clazz冲突时,它将记录为java.lang.Class

So, while understanding that generics are implemented via type erasure, I don't understand why I see com.xyz.Customer with the getName() call in doSomething() , but java.lang.Class in the aspect. 因此,虽然理解泛型是通过类型擦除实现的,但我不理解为什么我在doSomething()看到带有getName()调用的com.xyz.Customer ,但是在方面是java.lang.Class

In the second example the instance has been upcasted to an Object , while in your first example the actual Class is provided. 在第二个示例中,实例已被转换为Object ,而在第一个示例中,则提供了实际的Class During that upcast the fact that o was some other type is lost. 在那次混乱中, o是其他类型的事实丢失了。

The generics parameters are not considered when calling clazz.getName() since the code prints the actual type of the class. 调用clazz.getName()时不考虑泛型参数,因为代码将打印类的实际类型。

List<String> list is still a List no matter what genric type arguments the parameterized type contains. 无论参数化类型包含什么泛型类型参数, List<String> list仍然是List The fact that we cannot determine List has a generic argument of type String supplied demonstrates the concept of type erause. 我们无法确定List具有提供的String类型的泛型参数的事实说明了类型erause的概念。 Regardless of type erasure calling list.getClass().getName() returns the raw type java.util.List regardless of the generic parameters supplied. 无论类型擦除如何,调用list.getClass().getName()返回原始类型java.util.List而与提供的通用参数无关。

To log the information I wanted, I use two different pointcuts. 要记录所需的信息,我使用两个不同的切入点。 One of the pointcuts recognizes when java.lang.Class is the first argument to a method in our DAOs, and passes the argument to the advice. 其中一个切入点可以识别java.lang.Class何时是我们DAO中方法的第一个参数,并将该参数传递给建议。

(Luckily, by convention in our codebase, when a DAO takes a class argument it always comes first. This is not a terrifically general solution.) (幸运的是,按照我们代码库中的约定,当DAO接受类参数时,它总是排在最前面。这不是一个可怕的通用解决方案。)

Here's what the pointcuts look like: 切入点如下所示:

@Pointcut("execution(* com.xyz.dao..*.*(..)) && args(clazz,..)")
public void classyDAOMethods(Class<?> clazz) { ... }

@Pointcut("execution(* com.xyz.dao..*.*(..)) && !args(java.lang.Class,..)")
public void unclassyDAOMethods() { ... }

And this advice handles each cut slightly differently: 这个建议对每个剪切的处理略有不同:

@Before("classyDAOMethods(clazz)")
public void classyAdvice(JoinPoint joinPoint, Class<?> clazz) {
    logMethodEntry(joinPoint, clazz);
}

@Before("unclassyDAOMethods()")
public void logMethodEntry(JoinPoint joinPoint) {
    logMethodEntry(joinPoint, null);
}

That clazz passed in the first @Before has the class name I need for the logs. clazz中率先通过@Before具有类的名字,我需要的日志。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM