Sping——使用注解创建切面

为讲解例子,我们首先定义一个Performance接口:

1 package aoptest;
2 
3 public interface Performance {
4     public void perform();
5 }
View Code

再定义一个该接口的实现:

 1 package aoptest;
 2 
 3 public class PianoPerform implements Performance {
 4 
 5     @Override
 6     public void perform() {
 7         // TODO Auto-generated method stub
 8         System.out.println("i am playing piano");
 9     }
10 
11 }
View Code

在创建切面之前,我们先来看一下切点表达式的用法,如图所示:

关于切点表达式的更多用法,可查看相关文档。

接着,我们使用注解定义一个切面,Audience类会在perform方法执行前后织入指定的方法

 1 package aoptest;
 2 
 3 import org.aspectj.lang.annotation.Aspect;
 4 import org.aspectj.lang.ProceedingJoinPoint;
 5 import org.aspectj.lang.annotation.*;
 6 
 7 @Aspect
 8 public class Audience {
 9 
10     
11     @Pointcut("execution(** aoptest.Performance.perform(..))")
12     public void performance() {}
13     //performance()方法的实际内容并不重要,在这里它是空的。
14     //其实该方法本身只是一个标识,供@Pointcut注解依附
15     //不这样做的话,就需要在每个方法前都使用这个长点的表达式
16     
17     @Before("performance()")
18     public void silenceCellPhones() {
19         System.out.println("Slience cell phones");
20     }
21     
22     @Before("performance()")
23     public void takeSeats() {
24         System.out.println("takeSeats");
25     }
26     
27     @AfterReturning("performance()")
28     public void applause() {
29         System.out.println("applause");
30     }
31     
32     @AfterThrowing("performance()")
33     public void demandRefund() {
34         System.out.println("demandRefund");
35     }
36 }
View Code
  • @Before:通知方法会在目标方法调用之前调用
  • @AfterReturning:通知方法在目标方法成功返回后调用
  • @AfterThrowing:通知方法在目标方法抛出异常后调用
  • @Around:通知方法会将目标方法封装起来



接着,进行测试,首先使用JavaConfig进行相关bean的配置:

 1 package aoptest;
 2 
 3 import org.springframework.context.annotation.Bean;
 4 import org.springframework.context.annotation.ComponentScan;
 5 import org.springframework.context.annotation.Configuration;
 6 import org.springframework.context.annotation.EnableAspectJAutoProxy;
 7 
 8 @Configuration
 9 @EnableAspectJAutoProxy   //启用aspectJ自动代理
10 @ComponentScan
11 public class AopConfig {
12     @Bean
13     public Audience audience() {
14         return new Audience();
15     }
16     
17     @Bean 
18     Performance performance() {
19         return new PianoPerform();
20     }
21 }
View Code

然后,创建测试类:

 1 package aoptest;
 2 
 3 import org.junit.Test;
 4 import org.junit.runner.RunWith;
 5 import org.springframework.beans.factory.annotation.Autowired;
 6 import org.springframework.test.context.ContextConfiguration;
 7 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
 8 
 9 //用于在测试开始时自动创建Spring上下文
10 @RunWith(SpringJUnit4ClassRunner.class)
11 //告诉上下文需要在AopConfig中加载配置
12 @ContextConfiguration(classes = { AopConfig.class })
13 public class PerformTest {
14     @Autowired
15     public Audience audience;
16     @Autowired
17     public Performance performance;
18         @Test
19         public void play() {
20             performance.perform();
21     }
22 }
View Code

测试结果,符合预期:

现在,我们利用@Around创建环绕通知,重新实现切面,可以达到相同的效果:

package aoptest;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

@Aspect
public class Audience {

    
    @Pointcut("execution(** aoptest.Performance.perform(..))")
    public void performance() {}
    //performance()方法的实际内容并不重要,在这里它是空的。
    //其实该方法本身只是一个标识,供@Pointcut注解依附
    //不这样做的话,就需要在每个方法前都使用这个长点的表达式
    
    @Around("performance()")
        //ProceedingJoinPoint这个对象是必须有的,因为需要通过它来调用被通知的方法,使用proceed()方法
    public void watchPerformance(ProceedingJoinPoint jp) {
        System.out.println("Slience cell phones");
        System.out.println("takeSeats");
        try {
            jp.proceed();
        } catch (Throwable e) {
            System.out.println("demandRefund");
        }
        System.out.println("applause");
    }
}
View Code

当然,你也可以不调用proceed()方法,从而阻塞对通知方法的访问。

猜你喜欢

转载自www.cnblogs.com/ustc-anmin/p/10159612.html
今日推荐