Spring AOP:方面不适用于所调用的方法

Ran*_*ion 3 java aop spring

这是我第一次使用AOP,所以这可能是一个新手问题。

public class MyAspect implements AspectI {

public void method1() throws AsyncApiException {
    System.out.println("In Method1. calling method 2");
    method2();
}

@RetryOnInvalidSessionId
public void method2() throws AsyncApiException {
    System.out.println("In Method2, throwing exception");
    throw new AsyncApiException("method2", AsyncExceptionCode.InvalidSessionId);
}

public void login() {
    System.out.println("Logging");
}
Run Code Online (Sandbox Code Playgroud)

InvalidSessionHandler看起来像这样。

@Aspect
public class InvalidSessionIdHandler implements Ordered {

    @Around("@annotation(com.pkg.RetryOnInvalidSessionId)")
    public void reLoginAll(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Hijacked call: " + joinPoint.getSignature().getName() + " Proceeding");
        try {
            joinPoint.proceed();
        } catch (Throwable e) {
            if (e instanceof AsyncApiException) {
                AsyncApiException ae = (AsyncApiException) e;
                if (ae.getExceptionCode() == AsyncExceptionCode.InvalidSessionId) {
                    System.out.println("invalid session id. relogin");
                    AspectI myAspect = (AspectI) joinPoint.getTarget();
                    myAspect.login();
                    System.out.println("Login done. Proceeding again now");
                    joinPoint.proceed();
                }
            }
        }
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
Run Code Online (Sandbox Code Playgroud)

弹簧配置

<aop:aspectj-autoproxy />
<bean id="myAspect" class="com.pkg.MyAspect" />
<bean id="invalidSessionIdHandler" class="com.pkg.InvalidSessionIdHandler" />  
Run Code Online (Sandbox Code Playgroud)
  1. 我的意图是当我依次myAspect.method1()调用时调用method2,如果method2抛出InvalidSessionIdException,则仅method2应重试。但是上面的代码似乎没有任何作用。从method2抛出异常后,它立即返回。但是,如果我穿上衣服@RetryOnInvalidSessionIdmethod1那么整体将method1被重试。

  2. 为了学习我一直method2是公开的,但实际上我希望是这样private。我在这里不知道如何重试私有方法。

任何的意见都将会有帮助。

谢谢

Sot*_*lis 5

您当前的设置无法做到这一点。借助Spring的AOP功能,您的类InvalidSessionIdHandler将作为Bean创建,然后扫描注释/方法签名/等。与您的MyAspect班级有关。它将找到method2()并因此创建一个包装已创建的bean的代理。代理将根据您的建议执行操作。

Spring将在需要的地方注入这个(代理)bean。例如:

public class MyClass {
   @Autowired
   private MyAspect aspect;

   public void callMethod2() {
       aspect.method2();
   }
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,MyClass对象具有对代理的引用。当它调用时aspect.method2(),将执行添加的行为。

但是,在您的代码中,您希望method2()method1()

public void method1() throws AsyncApiException {
    System.out.println("In Method1. calling method 2");
    method2();
}
Run Code Online (Sandbox Code Playgroud)

这是你MyAspect班上的 从技术上讲,这里发生了什么是method2()获取调用上thisthis.method2()this是对实际对象的引用,而不是对代理的引用。因此,它将不会执行任何其他行为。

AOP Spring文档更详细地解释这一点。

这里的解决方法是重构,使其method2()位于另一个类/对象中,或者从外部调用它,即。不是来自method1()

  • 这是对的。请注意,默认情况下,&lt;aop:aspectj-autoproxy /&gt;`将为包装在AOP中的bean /组件创建JDK代理(仅基于接口)。要为未由接口定义的方法引入AOP行为,您必须使用&lt;aop:aspectj-autoproxy proxy-target-class =“ true” /&gt;`,但是即使如此,您仍必须在代理上调用该方法利用AOP行为。在代理类中调用`this.someMethod()`将不会利用AOP,因为正如@Sotirios所描述的,`this`是引用目标实例,而不是代理。 (2认同)