Search code examples
javaspringaopspring-aop

Something is wrong in my SpringAOP Demo code with a null


I am learning Spring AOP.I just write some very simple code to have a try.I cannot understand why the "re" is null after calling the ControllerImpl's login method in my test code.

I only know a few knowledge about how Spring AOP works,maybe it's the reason why I cannot understand the failure.

Maybe you can run the test in AopTest.java.I am using the newest STS as my IDE.

I used STS to debug my code,but Spring AOP using dynamic proxy,so I cannot see the details.

You will see something like this "result = null":

Click to see my test output.

This is my test code.At Github.

public class AopTest {

@Autowired
private Controller_ con;

@Test
public void testControllerWithCorrectUid(){
    System.out.println("==============================================");
    String re = con.login(123);
    System.out.println("result = " + re);
    System.out.println("==============================================");
    assertEquals("success",re);
}

@Test
public void testControllerWithWrongUid(){
    System.out.println("==============================================");
    String re = con.login(456);
    System.out.println("result = " + re);
    System.out.println("==============================================");
    assertEquals("fail",re);
}

}

Solution

  • I'll answer in two parts:

    I used STS to debug my code,but Spring AOP using dynamic proxy,so I cannot see the details.: wrong. First, you could load the sources from Spring framework and single step its inner classes until it reaches yours, but you can just put breakpoints in you advice and advised methods.

    Then the actual cause of you controller returning null when none of its return values are. After seeing your output, I assume that the login method did return a not null string value, probably success. But your around advice failed to pass it back to caller.

    Spring reference manual states that (emphasize mine):

    The invoke() method should return the invocation’s result: the return value of the join point.

    and even gives an example:

    public class DebugInterceptor implements MethodInterceptor {
    
        public Object invoke(MethodInvocation invocation) throws Throwable {
            System.out.println("Before: invocation=[" + invocation + "]");
            Object rval = invocation.proceed();
            System.out.println("Invocation returned");
            return rval;
        }
    }
    

    But your around advice is a void method and and such the caller gets nothing and sees a null. The advice should be:

    @Around("action()")
    public Object logWarn(ProceedingJoinPoint jp) { 
        Object ret;
        System.out.println("AroundAdvice -> LogAspectImpl ");   
        try {
            ret = jp.proceed(); // store the return value of the advised method
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("AroundAdvice -> LogAspectImpl ");
        return ret;  // and pass it back to caller
    }