使用注释的AspectJ中的SpringAOP简介

时间:2018-07-04 13:47:18

标签: java spring spring-boot aspectj spring-aop

我正在学习简介(在AspectJ中称为类型间声明)。我从SpringAOP introductions with AspectJ得到了一个使用xml的示例。 我正在尝试使用注释复制同样的内容,但我不知道如何进行。我在互联网上做了很多研究,但找不到任何样本。你能帮我这个忙吗?

PerformanceTest.class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = ConcertConfig.class)
public class PerformanceTest {

    @Autowired
    public Audience audience;

    @Autowired
    public Performance liveOpera;

    @Autowired
    public EncoreableIntroducer encoreable;

    @Test
    public void testPerformance(){
        liveOpera.perform();
    }
}

LiveOpera.class

public class LiveOpera implements Performance{
    @Override
    public void perform() {
        System.out.println("Live Opera Performance Started");   
    }}

Encoreable.interface

public interface Encoreable {
    public void performEncore();
}

DefaultEncoreable.class

public class DefaultEncoreable implements Encoreable {
    @Override
    public void performEncore() {
        System.out.println("WoW!! What an encore performance!!");
    }
}

ConcertConfig.class

@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {

    @Bean
    public Audience audience(){
        return new Audience();
    }

    @Bean
    public LiveOpera opera(){
        return new LiveOpera();
    }

    @Bean
    public EncoreableIntroducer encoreable(){
        return new EncoreableIntroducer();
    }

}

性能界面

public interface Performance {
    public void perform();
}

EncoreableIntroducer.class

@Aspect
public class EncoreableIntroducer {
    @DeclareParents(value="com.example.introduction.Performance+",
            defaultImpl=DefaultEncoreable.class)
    public static Encoreable encoreable;
}

Audience.class

@Aspect
public class Audience {

    @Pointcut("execution(** com.example.introduction.Performance.perform(..))")
    public void performance() {
    }

    public void silenceMobilePhones() {
        System.out.println("Silencing Mobile Phones");
    }

    public void takeSeats() {
        System.out.println("Taking seats");
    }

    public void applause() {
        System.out.println("CLAP CLAP CLAP!!");
    }

    public void demandRefund() {
        System.out.println("Need a Refund!!");
    }

    @Around("performance()")
    public void wrapPerformance(ProceedingJoinPoint jp) {
        try {
            silenceMobilePhones();
            takeSeats();
            jp.proceed();
            applause();
        } catch (Throwable e) {
            System.out.println(e);
            e.printStackTrace();
            demandRefund();
        }
    }
}

输出:在PerformanceTest.class中执行@Test方法时

Silencing Mobile Phones
Taking seats
Live Opera Performance Started
CLAP CLAP CLAP!!

请让我知道,如何使用AspectJ-Introductions使用EncoreableIntroducer.class中的方面,以便可以使用DefaultEncoreable.class中的perform()方法?

像使用AspectJ简介一样期望输出如下:

Silencing Mobile Phones
Taking seats
WoW!! What an encore performance!!
Live Opera Performance Started
CLAP CLAP CLAP!!

1 个答案:

答案 0 :(得分:0)

您在这里遇到几个问题:

  • 您正在使用两个接口(PerformanceEncoreable)来实现相同的方法。为什么?
  • 您正在尝试为LiveOpera引入一种已经存在的方法,即void perform()。可能您的意图是覆盖原始版本。这在Spring AOP和AspectJ中都不起作用。您只能介绍目标类中尚不存在的方法。
  • 您正在尝试拦截方面A在另一方面B中引入的方法。据我所知,这仅适用于AspectJ,不适用于Spring AOP。我不是Spring用户,但很快尝试了一下,但它不起作用。在AspectJ中复制您的情况时,它可以工作。因此,您可以做的是在Spring应用程序中激活AspectJ via LTW并修改您的代码以使其起作用,从而避免了我描述的前两个问题。

更新并回答评论中提出的问题:

首先,我摆脱了配置类中的手动@Bean方法,因为您始终启用了组件扫描。相反,我只是向@Component类和这两个方面添加了LiveOpera注释。您的方法也可以,但是我更好:

@Configuration
@EnableAspectJAutoProxy
@ComponentScan
public class ConcertConfig {}

看起来更干净,不是吗?只是不要忘记@Component注释所属的地方。

现在,真正的解决方案。在方面,将您的建议更改为:

@Around("performance() && this(encoreable)")
public void wrapPerformance(ProceedingJoinPoint jp, Encoreable encoreable) {
  try {
    silenceMobilePhones();
    takeSeats();
    encoreable.performEncore();
    jp.proceed();
    applause();
  } catch (Throwable e) {
    System.out.println(e);
    e.printStackTrace();
    demandRefund();
  }
}