避免递归AOP

时间:2013-12-31 09:54:05

标签: spring aop spring-aop

我有一个Aspect拦截用注释@Foo修饰的方法a()。这种方法 调用另一个方法b()也用注释@Foo修饰。我希望我的方面能够拦截 只有a()而不是b()。我怎样才能做到这一点?

我已尝试过()但没有成功。使用ThreadLocal它可以工作,但我很想知道 如果有一个Spring解决方案。

@Component
@Order(value = 2)
@Aspect
public class FooAspect {

   @Around(value = "@annotation(Foo)")
   public Object aroundAdvice(ProceedingJoinPoint pjp, Foo foo) {
      ...
   }

}

2 个答案:

答案 0 :(得分:2)

我认为只有Aspects才能做到这一点。无论如何都会发生拦截。

但是,一种解决方案是使用ThreadLocal Byte标记您已经应用了建议。

private ThreadLocal<Byte> flag = new ThreadLocal<>();

@Around(value = "@annotation(Foo)")
public Object aroundAdvice(ProceedingJoinPoint pjp, Foo foo) throws Throwable {
    if (flag.get() == null) {
        try {
            flag.set((byte) 1); // or 0, whatever
            // apply advice
            return pjp.proceed();
        } finally {
            flag.remove();
        }
    } else {
        // don't apply advice
        return pjp.proceed();
    }
}

您需要catchthrows Throwable引发proceed()

答案 1 :(得分:0)

框架中有cflowpoincut,但Aspectj风格不支持它。

但是,您可以将其与aop-schema配置方法一起使用。

例如:

public class NotInFlowPoincut extends  AspectJExpressionPointcut {

    private ControlFlowPointcut cflow;
    private Class<?> flowClass;
    private String methodName;

    public NotInFlowPoincut() {
    }

    @PostConstruct
    public void init() {
        cflow = new ControlFlowPointcut(flowClass, methodName);
    }

    @Override
    public boolean matches(Method method, Class targetClass, Object[] args) {
        return super.matches(method, targetClass, args) && ! cflow.matches(method, targetClass, args);
    }

    public Class<?> getFlowClass() {
        return flowClass;
    }

    public void setFlowClass(Class<?> flowClass) {
        this.flowClass = flowClass;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

}

public class FooAspect {

     public Object aroundAdvice(ProceedingJoinPoint pjp, Foo foo) throws Throwable {
            System.out.println("in aroundAdvice");
            return pjp.proceed();
       }

     public static void main(String[] args) {
         ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("/context.xml");
         A a = ctx.getBean(A.class);
         a.a();

         B b = ctx.getBean(B.class);
         b.b();
     }

}

public class A {
    @Autowired B b;

    @Foo
    public void a() {
        System.out.println("In a()");
        b.b();
    }
}

public class B {

    @Foo
    public void b() {
        System.out.println("In b()");
    }

}

最后

<bean id="cflow" class="test.NotInFlowPoincut">
    <property name="expression" value="@annotation(foo) " />
    <property name="methodName" value="aroundAdvice" />
    <property name="flowClass" value="test.FooAspect" />
</bean>

<bean id="foo" class="test.FooAspect" />

<bean id="a" class="test.A" />
<bean id="b" class="test.B" />

<aop:config proxy-target-class="true">
    <aop:aspect ref="foo" >
        <aop:around method="aroundAdvice" pointcut-ref="cflow" />
    </aop:aspect>
</aop:config>

将输出:

in aroundAdvice
In a()
In b()
in aroundAdvice
In b()

这似乎就是你要找的东西。

请注意,cflow poincut很慢,请参阅javadoc。