• AOP的实现


    AOP基于xml配置方式实现

    Spring基于xml开发AOP

    •     定义目标类(接口及实现类)
     1 /**
     2  * 目标类
     3  */
     4 public interface UserService {
     5     //业务方法
     6     public void getById();    
     7     public void add();    
     8     public void delete();    
     9     public String update();
    10     public void batch();    
    11 }
     1 public class UserServiceImpl implements UserService {
     2     @Override
     3     public void getById() {
     4         System.out.println("UserServiceImpl类的getById方法被调用...");
     5         //抛出异常
     6         System.out.println(1/0);
     7     }
     8     @Override
     9     public void add() {
    10         System.out.println("UserServiceImpl类的add方法被调用...");
    11     }
    12     @Override
    13     public void delete() {
    14         System.out.println("UserServiceImpl类的delete方法被调用...");
    15 //        System.out.println(1/0);
    16     }
    17     @Override
    18     public String update() {
    19         System.out.println("UserServiceImpl类的update方法被调用...");
    20 //        System.out.println(1/0);
    21         return "update的返回值";
    22     }
    23     @Override
    24     public void batch() {
    25         System.out.println("UserServiceImpl类的batch方法被调用...");
    26     }
    27 }
    •     定义切面类
     1 /**
     2  * 切面
     3  */
     4 public class UserAspect {
     5     //前置通知
     6     public void beforeAdvice(JoinPoint jp){
     7         //获取切入点的方法的名称
     8         String name = jp.getSignature().getName();
     9         System.out.println("前置通知切入点的方法的名称:"+name);                
    10         System.out.println("前置通知");
    11     }
    12     
    13     //后置通知
    14     public void afterAdvice(JoinPoint jp){
    15         //获取切入点的方法的名称
    16         String name = jp.getSignature().getName();
    17         System.out.println("后置通知切入点的方法的名称:"+name);                
    18         System.out.println("后置通知");
    19     }
    20         
    21     //返回通知
    22     //可以获取object类型的返回值
    23     //注意:result名称必须和配置文件中的returning的名称保持一致
    24     public void afterReturningAdvice(JoinPoint jp,Object result){
    25         //获取切入点的方法的名称
    26         String name = jp.getSignature().getName();
    27         System.out.println("返回通知切入点的方法的名称:"+name);        
    28         //打印返回值
    29         System.out.println(result);
    30         System.out.println("返回通知");
    31     }
    32         
    33     //异常通知
    34     public void exceptionAdvice(JoinPoint jp,Exception ex){
    35         //获取切入点的方法的名称
    36         String name = jp.getSignature().getName();
    37         System.out.println("异常通知切入点的方法的名称:"+name);    
    38         //打印异常信息
    39         System.out.println(ex.getMessage());
    40         System.out.println("异常通知");
    41     }
    42         
    43     //环绕通知
    44     //必须有一个参数:ProceedingJoinPoint
    45     //有返回值:Object
    46     public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
    47         System.out.println("环绕通知前");
    48         //执行业务逻辑方法
    49         Object result = pjp.proceed();        
    50         //获取切入点的方法的名称
    51         String name = pjp.getSignature().getName();
    52         System.out.println("环绕通知切入点的方法的名称:"+name);        
    53         System.out.println("环绕通知后");
    54         return result;
    55     }
    56 }
    •     配置spring核心配置文件
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">    
        <!-- 把切面和业务对象放到容器中 -->
        <bean id="userAspect" class="spring.aop.xml.UserAspect"></bean>
        <bean id="userServiceImpl" class="spring.aop.xml.UserServiceImpl"></bean>
            
        <!-- 配置aop的实现 -->
        <aop:config>
            <!-- 
                切入点的配置
                expression(切入点表达式):指定切哪个方法
             -->
             <aop:pointcut expression="execution(* *.add*(..))" id="pointCut01"/>         
             <aop:pointcut expression="execution(* *.delete*(..))" id="pointCut02"/>
             <aop:pointcut expression="execution(* *.update*(..))" id="pointCut03"/>
             <aop:pointcut expression="execution(* *.getById*(..))" id="pointCut04"/>
             <aop:pointcut expression="execution(* *.batch*(..))" id="pointCut05"/>
                     
             <!-- 切面的配置 -->
             <aop:aspect ref="userAspect">
                 <!-- 
                     前置通知的配置:在pointCut01切入点的位置添加beforeAdvice的通知
                  -->
                  <aop:before method="beforeAdvice" pointcut-ref="pointCut01"/>              
                  
                 <!-- 
                     后置通知的配置:在pointCut02切入点的位置添加afterAdvice的通知
                  -->
                  <aop:after method="afterAdvice" pointcut-ref="pointCut02"/>
                                
                 <!-- 
                     返回通知的配置:在pointCut03切入点的位置添加afterReturningAdvice的通知
                     returning:返回值的参数名称
                  -->
                  <aop:after-returning method="afterReturningAdvice" pointcut-ref="pointCut03" returning="result"/>
                                
                 <!-- 
                     异常通知的配置:在pointCut04切入点的位置添加exceptionAdvice的通知
                     throwing:抛出异常的名称,必须和通知上的形参名称一致
                  -->
                  <aop:after-throwing method="exceptionAdvice" pointcut-ref="pointCut04" throwing="ex"/>
                                
                 <!-- 
                     环绕通知的配置:在pointCut05切入点的位置添加aroundAdvice的通知
                  -->
                  <aop:around method="aroundAdvice" pointcut-ref="pointCut05"/>
             </aop:aspect>    
        </aop:config>    
    </beans>
    •     测试
     1 //使用xml方式配置AOP
     2 @RunWith(SpringJUnit4ClassRunner.class)
     3 @ContextConfiguration("classpath:applicationContext-aop-xml.xml")
     4 public class XmlAopTest {
     5     //注入业务对象
     6     @Autowired
     7     private UserService userService;
     8     
     9     //测试AOP,对切入点进行增强
    10     @Test
    11     public void test(){
    12         //前置通知的测试
    13 //        userService.add();
    14                 
    15         //后置通知的测试(无论有没有异常都会执行)
    16 //        userService.delete();
    17                 
    18         //返回通知的测试(只有业务方法正常执行时,才会执行的通知)
    19 //        userService.update();
    20                 
    21         //异常通知的测试
    22 //        userService.getById();
    23                 
    24         //环绕通知的测试
    25         userService.batch();
    26     }
    27 }

        

    AOP的切入点表达式execution

        表达式的写法:修饰关键词   返回值类型   包名.类名.方法名(..)

    修饰关键词:protected ,  public  ,  private ….一般都省略不写

    返回值类型:一般返回值类型用 * 号代替,表示任意的返回值都可以

    方法名中的两个点:表示所带的参数的个数。

            举例如下:

      任意以public修饰的方法都可以

    execution(public * *(..))

      任何以set开头的方法都可以

    execution(* set*(..))

      任何在AccountService 这个接口下面的方法都可以

    execution(* com.xyz.service.AccountService.*(..))

      任何在com.xyz.service 这个包下面的所有类的所有方法都可以

    execution(* com.xyz.service.*.*(..))

      任何在com.xyz.service 这个包以及整个包下面的所有子包的所有类的所有方法都可以

    execution(* com.xyz.service..*.*(..))

      ..代表这个包及这个包下面的所有子包

    Spring中的5种通知类型及参数

        •   前置通知:在目标方法开始之前进行执行的通知

              参数:JoinPoint

        •   后置通知:在目标方法执行之后,无论是否发生异常,都进行执行的通知

              参数:JoinPoint

        •   返回通知:在目标方法正常结束时,才执行的通知

              参数:JoinPoint,Object

        •   异常通知:在目标方法出现异常时才会进行执行的通知

              参数:JoinPoint,Exception

        •   环绕通知:在目标方法执行之前、 之后都会执行的通知

              参数:ProceedingJoinPoint(必须有)

     



     

    AOP基于注解方式的实现

    xml配置中开启spring注解扫描及开启aop注解的自动代理

        

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:aop="http://www.springframework.org/schema/aop"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        <!-- 开启spring的注解驱动 -->
        <context:component-scan base-package="spring.aop.annotation"></context:component-scan>
        
        <!-- 开启aop的自动代理:使用注解实现AOP,这个必须配置 -->
        <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    </beans>

        定义接口及接口实现类

        

     此处省略,同xml配置方式相同

        通过注解的方式定义切面类

     1 /**
     2  * 切面
     3  */
     4 @Component
     5 @Aspect
     6 public class UserAspect {
     7     //前置通知
     8     @Before(value = "execution(* *.add*(..))")
     9     public void beforeAdvice(JoinPoint jp){
    10         String name = jp.getSignature().getName();
    11         System.out.println("前置通知的切入点的方法名:" + name);        
    12         System.out.println("前置通知...");
    13     }
    14         
    15     //后置通知
    16     @After(value = "execution(* *.delete*(..))")
    17     public void afterAdvice(JoinPoint jp){
    18         String name = jp.getSignature().getName();
    19         System.out.println("后置通知的切入点的方法名:" + name);        
    20         System.out.println("后置通知...");
    21     }
    22         
    23     //返回通知
    24     @AfterReturning(value = "execution(* *.update*(..))",returning="result")
    25     public void afterReturningAdvice(JoinPoint jp,Object result){
    26         String name = jp.getSignature().getName();
    27         System.out.println("返回通知的切入点的方法名:" + name);        
    28         System.out.println(result);        
    29         System.out.println("返回通知...");
    30     }
    31         
    32     //异常通知
    33     @AfterThrowing(value = "execution(* *.getById*(..))",throwing="ex")
    34     public void exceptionAdvice(JoinPoint jp,Exception ex){
    35         String name = jp.getSignature().getName();
    36         System.out.println("异常通知的切入点的方法名:" + name);        
    37         System.out.println(ex.getMessage());
    38         System.out.println("异常通知...");
    39     }
    40         
    41     //环绕通知
    42     @Around(value = "execution(* *.batch*(..))")
    43     public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
    44         System.out.println("环绕通知前...");        
    45         Object result = pjp.proceed();
    46         String name = pjp.getSignature().getName();
    47         System.out.println("环绕通知的切入点的方法名:" + name);        
    48         System.out.println("环绕通知后...");        
    49         return result;
    50     }
    51 }

        测试

     1 /**
     2  * 注解形式的AOP的单元测试类
     3  */
     4 @RunWith(SpringJUnit4ClassRunner.class)
     5 @ContextConfiguration("classpath:applicationContext-aop-annotation.xml")
     6 public class AnnotationAopTest {
     7     @Autowired
     8     private UserService userService;
     9     
    10     @Test
    11     public void test(){
    12         //注解:前置通知的测试
    13 //        userService.add();
    14         
    15         //后置通知的测试
    16 //        userService.delete();
    17         
    18         //返回通知
    19 //        userService.update();
    20         
    21         //异常通知
    22 //        userService.getById();
    23         
    24         //环绕通知
    25         userService.batch();
    26     }
    27 }


  • 相关阅读:
    byvoid
    soa文章摘抄
    也谈设计模式,架构,框架和类库的区别
    GoF设计模式三作者15年后再谈模式
    陈梓涵:我们为什么要学习设计模式
    陈梓涵:关于编程的胡扯
    hung task机制
    iscsi target tgt架构
    iscsi target IET架构
    ISCSI工作流程target和initiator
  • 原文地址:https://www.cnblogs.com/jifengblog/p/9239029.html
Copyright © 2020-2023  润新知