简体   繁体   中英

AspectJ: matching GenericServlet.init() call of an annotated subclass instance

I'm deriving from GenericServlet and annotate that derived class with @Tx. I want to use the GenericServlet.init() method call during servlet startup to trigger some initialization outside the servlet via aop. The first two lines don't match at all, the third one matches obviously all servlets, and the fourth matches all servlets despite using the annotation to specify the target.

@Before("@this(com.github.jjYBdx4IL.aop.tx.Tx)
    && execution(* javax.servlet.GenericServlet+.init()) && this(foo)")
@Before("@target(com.github.jjYBdx4IL.aop.tx.Tx)
    && execution(* javax.servlet.GenericServlet+.init()) && this(foo)")

@Before("execution(* javax.servlet.GenericServlet+.init()) && this(foo)")
@Before("target(@com.github.jjYBdx4IL.aop.tx.Tx Object)
    && execution(* javax.servlet.GenericServlet+.init()) && this(foo)")

This first line works if I replace GenericServlet+.init() with GenericServlet.init(..)

@Before("@this(com.github.jjYBdx4IL.aop.tx.Tx) 
    && execution(* javax.servlet.GenericServlet.init(..)) && this(foo)")

which is strange because, using a debugger, GenericServlet.init() definitely gets called from GenericServlet.init(ServletConfig)...

Can someone please clarify, what's going on here? I would expect that the first line should do the trick, but it doesn't.

My best guess is that it has to do with the separation of class loaders used by the Jetty instance itself and the webapp's class loaders... I managed to make the following at least weave the init() method (according to maspectj's debug output):

@After("@this(com.github.jjYBdx4IL.aop.tx.Tx
    && target(javax.servlet.GenericServlet+)
    && execution(* init()) && this(foo)")

but it does not trigger.

Update

I traced the problem down to this: URLClassLoader loads Annotation as com.sun.$Proxy$27

Basically, foo.getClass().isAnnotationPresent(Tx.class) always returns false. Now the question is: what is this nonsense? And how can I disable it?

Turns out those com.sun.proxy.$Proxy instances are being used by the classloader when a parent classloader already defined the same class/annotation. Because I want to weave system classes like javax.servlet.GenericServlet, I need to load my annotations/aspects using the parent classloader, ie with Jetty itself. Setting the annotation-containing dependency for my webapp to the maven scope "provided" solved the issue.

"Solved" means: the proxy for the annotation is still there, but calls to "isAnnotationPresent" actually return true and not false now, which was the reason behind AspectJ's failure to identify the annotation pointcuts at runtime.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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