应用多个方面是否安全?

时间:2015-05-28 13:26:33

标签: java aspectj aspect

假设我们有两个方面:

public aspect TestAspect {
    pointcut publicMethodExecuted(): execution(public !static * *(..));

    int around() : publicMethodExecuted() {
        System.out.println("Test string");
        Object[] args = thisJoinPoint.getArgs();
        System.out.println(args[0]);
        int original_return_value = proceed();
        return original_return_value * 100;
    }
}

public aspect AnotherTestAspect {
    pointcut anotherPublicMethodExecuted(): execution(public !static * *(..));

    int around() : anotherPublicMethodExecuted() {
        System.out.println("Another Test string");
        Object[] args = thisJoinPoint.getArgs();
        System.out.println(args[0]);
    }
}

正如你所看到的,这两个方面完全相同。因此,他们会拦截相同的方法调用。这样做是否安全?

请不要建议我把所有这些都放在同一个方面。我询问AspectJ工作原则和潜在可能性。

2 个答案:

答案 0 :(得分:1)

简单的答案是“是的,但......”

保持简单,AspectJ所做的基本上是切入点切割并搜索如何编织它,然后,编织它。对于相同方法的两个切入点的情况,其中一个切入点将编织,然后另一个将编织并且将基本上覆盖第一次编织。 除非第二次切入点继续进行!

让我用一个简短的例子解释一下。假设您有以下类:

public class TestClass {

     public static void main(String... args) {
        new TestClass().x();
     }

     public void x() {
         System.out.println("Hello, world!");
     }
}

现在让我们定义一个方面:

public aspect FirstAspect {

     public pointcut hello1() : execution(void mypackage.TestClass.x());
     void around() : hello1() {
         System.out.println("first");
     }

}

会发生的方面是方法将编织方法x,基本上用AspectJ创建的方法替换对x的调用。

现在让我们假设我们有另一个方面:

public aspect SecondAspect {

     public pointcut hello2() : execution(void mypackage.TestClass.x());
     void around() : hello2() {
         System.out.println("second");
     }

}

由于失去了一般性并保持一致,我们假设FirstAspect首先被编织。那时,我们得到了与以前相同的结果。但现在 AspectJ继续并编织SecondAspect。它找到方法x()并用 new 方法替换它的'执行(或调用,取决于切入点类型),有效地覆盖先前的编织并使其过时(具有讽刺意味的是,第一个编织的代码)仍然存在,但没用。)

但是,如果SecondAspect的建议在任何时候调用proceed(),那么它将要进行的部分实际上是第一次编织。那是因为因为它编织了,就AspectJ而言,这正是x所做的。

试一试。您只会看到其中一个切入点实际上已被编织:您只能获得一个打印件:firstsecond,但不能同时打印两者,除非您继续执行此操作:

 System.out.println("second");
 proceed();

只要你这样做proceed(),它就没关系了:

 proceed();
 System.out.println("second");

如果您想确保首先编织哪个切入点,您可以查看AspectJ precedence declaration

答案 1 :(得分:1)

假设你有这个课程:

public class TestClass
{
public static void main( String[] args )
{
    new TestClass().print();
}

public void print()
{
    System.out.println("Hello World");
}
}

这些方面:

public aspect FirstAspect
{
public pointcut hello1() : execution(void TestClass.print());
void around() : hello1() {
    System.out.println("first");
    proceed();
    System.out.println("first after");
}
}

public aspect SecondAspect
{

    public pointcut hello2() : execution(void TestClass.print());
    void around() : hello2() {
        System.out.println("second");
        proceed();
        System.out.println("second after");
    }
}

运行时,会生成以下输出:

first
second
Hello World
second after
first after