【问题标题】:Spring AOP: Aspect not working on called methodSpring AOP:方面不适用于调用的方法
【发布时间】:2013-08-01 03:46:38
【问题描述】:

这是我第一次使用 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");
}

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;
    }
}

弹簧配置

<aop:aspectj-autoproxy />
<bean id="myAspect" class="com.pkg.MyAspect" />
<bean id="invalidSessionIdHandler" class="com.pkg.InvalidSessionIdHandler" />  
  1. 我的意图是当我调用myAspect.method1() 时,它又调用method2,如果method2 抛出InvalidSessionId 异常,那么只有method2 应该被重试。但是上面的代码似乎没有做任何事情。它只是在从方法 2 引发异常后立即返回。但是,如果我将@RetryOnInvalidSessionId 放在method1 上,那么整个method1 都会重试。

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

任何建议都会有所帮助。

谢谢

【问题讨论】:

    标签: java spring aop


    【解决方案1】:

    这在您当前的设置下是不可能的。使用 Spring 的 AOP 功能,您的类 InvalidSessionIdHandler 将被创建为 bean,然后扫描注释/方法签名/等。与您的 MyAspect 课程相关。它将找到method2() 并因此创建一个代理包装它已经创建的bean。代理将具有您建议的行为。

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

    public class MyClass {
       @Autowired
       private MyAspect aspect;
    
       public void callMethod2() {
           aspect.method2();
       }
    }
    

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

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

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

    在您的 MyAspect 类中。从技术上讲,这里发生的是method2()this 调用为this.method2()this 是对实际对象的引用,而不是代理。因此它不会执行任何额外的行为。

    AOP Spring documentation 对此进行了更详细的解释。

    这里的解决方法是重构 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 引用的是目标实例,而不是代理。
    • 除了在不同的类中重构出method2之外,是否可以使用任何其他设置?我的意思是我总是可以重构它,但方法 2 在逻辑上只属于当前类。它甚至是私有方法。
    • 我想,你可以有一个 @Component 注释的私有内部类,只有那个方法。和@Autowired 一个私有字段来调用该方法。
    • 我尝试创建内部私有类 MyAspectUtil,但它失败并出现错误 'No visible constructors in class com.pkg.MyAspect.MyAspectUtil
    猜你喜欢
    • 1970-01-01
    • 2012-11-13
    • 1970-01-01
    • 2021-07-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多