• 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()方法,从而阻塞对通知方法的访问。

  • 相关阅读:
    MFC 控件RadioButton和CheckBox区别
    python的传递实参
    python的返回值
    Machine Learning的定义
    pythion的定义函数和传递实参
    python的用户输入和while循环
    python的字典
    python的if语句
    python的元组及其书写规矩
    python中操作列表
  • 原文地址:https://www.cnblogs.com/ustc-anmin/p/10159612.html
Copyright © 2020-2023  润新知