Search code examples
javaloggingaspectjaspect

AspectJ - method @around not called


I want to use AspetcJ to plug in to log4J method that is located in org.apache.log4j.Category.java file.

protected void forcedLog(String fqcn, Priority level, Object message, Throwable t) {
    callAppenders(new LoggingEvent(fqcn, this, level, message, t));
  }

so finally that

@Around("execution(protected void org.apache.log4j.Category.*(..))

would work.

What problem do i have?

My aspect dont get called.

So i made easier example - and it also does not get called.

core.xml

<?xml version="1.0" encoding="UTF-8"?>

<beans 
    xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:context="http://www.springframework.org/schema/context"    
    xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/aop 
    http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- <aop:aspectj-autoproxy /> -->

    <context:load-time-weaver/>


    <!-- Aspect -->
    <!--  
    <bean id="beanName"  class="class.sth.ClazzName" />
    <bean id="beanName2"  class="class.sth.Clazz2Name" />
    -->

<!-- other beans - not aspects -->
    </beans>

aop.xml

<!DOCTYPE aspectj PUBLIC "-//AspectJ//DTD//EN" "http://www.eclipse.org/aspectj/dtd/aspectj.dtd">
<aspectj>

    <weaver>
        <!-- only weave classes in our application-specific packages -->
         <include within="*"/>
    <exclude within="org.jibx*"/>
    </weaver>

    <aspects>
        <!-- weave in just this aspect -->
        <aspect name="class.sth.ClazzName"/>
        <aspect name="class.sth.Clazz2Name"/>
    </aspects>

</aspectj>

Example java class which should be invoked when i run JUnit test - in which clearly i see that this line of code is executed:

System.out.println("test");

Still i don't see my aspect getting called.

@Aspect
@Order(3)
public class ClazzName {

    @Around("call(* *println(..))")
    public void testMethod(ProceedingJoinPoint joinPoint) {
        Object o = joinPoint.getArgs();
        System.out.println("test");
    }
}

In my app in the same JUnit test other aspect is called. That can tell Us that we have good dependencies in the project.

@Aspect
@Order(2)
public class Clazz2Name {


    @Around("@annotation(loggable)")
    public Object doStuff(ProceedingJoinPoint joinPoint, Clazz2Name log) throws Throwable{
        ...
    }

    ...

My classes are not always marked as @Component and i want to leave it that way.

JUnit VM arguments

-javaagent:C:\aspectjWeaver\spring-instrument-3.0.4.jar

The question is how i can achieve my goal and make my aspect get called when i want it to ?


Solution

  • You actually have at least the following problems:

    1. You did not read the Spring AOP documentation. (Sorry, couldn't resist.)
    2. You are using Spring AOP, not full AspectJ. The difference is that the former only works for Spring components, but Log4J is not a Spring component. So if you want to make it work you need to use full AspectJ via load-time weaving as described by chapter 11.8 of the Spring manual, secsion Using AspectJ with Spring applications.
    3. Even when using full AspectJ you need to know that you cannot hook into executions of JDK methods because those have already been loaded before the aspect weaver is instantiated. Thus, you should hook into method calls via call(* println(..)), not into method executions.

    What I do not understand is why you want to hook into Log4J and JDK methods anyway. Do you want to redirect the calls to some other channel? Maybe it would be better to describe what you actually want to achieve, not how you think the problem should be solved.