• Spring 之AOP 面向切面编程


    AOP相关术语:

    Joinpoint (连接点):所谓连接点是指那些被拦截到的点,在spring中,这些点指的是方法,因为spring 只支持方法类型的连接点。

    Pointcut(切入点):所谓切入点是指我们要对那些Joinpoint进行拦截的定义。

    Adevice(通知/增强):所谓通知是指拦截到Joinpoint之后要做的事,分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

    Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,Introduction可以在运行期为类动态的添加一些方法或Field

    Target(目标对象):代理的目标对象

    Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。spring 采用动态代理织入,而AspectJ采用编译器织入和类装载期织入

    Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

    Aspect(切面):是切入点和通知(引介)的结合

    通知类型:

    • 前置通知:在目标方法执行前执行
    • 后置通知:在目标方法执行后执行
    • 环绕通知:在目标方法执行前和执行后通知
    • 异常抛出通知:在目标方法出现异常时执行
    • 最终通知:无论目标方法是否出现异常,最终通知都会执行

    引入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" xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

     

    第一种方式我们可以在Xml文件中进行配置:

    编写目标对象:

    public interface PersonDao {
         public String savePerson();
    }

     

    1 public class PersonDaoImpl implements PersonDao {
    2     @Override
    3     public String savePerson() {
    4         System.out.println("save person");
    5         return "return SavePerson";
    6     }
    7 }

     

     

    编写切面类 进行事务管理:

     1 package com.person;
     2 
     3 import javax.persistence.criteria.Join;
     4 
     5 import org.aspectj.lang.JoinPoint;
     6 import org.aspectj.lang.ProceedingJoinPoint;
     7 
     8 public class Transaction {
     9 /**
    10  * 前置通知
    11  *  JoinPoint 
    12  *      连接点,代表一个方法,客户端调用哪个方法那个方法就是连接点
    13  *  通过该参数,可以获取到连接点的一些信息
    14  * @param joinPoint
    15  */
    16     public void beginTransaction(JoinPoint joinPoint){
    17         //获取目标类
    18         System.out.println("targetClass   " + joinPoint.getTarget());
    19         //获取连接点的参数
    20         System.out.println("args  " + joinPoint.getArgs());
    21         //获取连接点的名称
    22         System.out.println("methodName  " + joinPoint.getSignature().getName());
    23         System.out.println("开启事务");
    24     }
    25     /**
    26      * 后置通知  方法遇到异常  不执行
    27      * JoinPoint 连接点
    28      * Object val 接受目标方法的返回值 与配置文件中参函数名一致
    29      * @param joinPoint
    30      */
    31 public void commit(JoinPoint joinPoint,Object val){
    32     System.out.println(val);
    33     System.out.println("事务提交");
    34     
    35 }
    36 /**
    37  * 最终通知  无论是否发生异常都会执行
    38  * @param joinPoint
    39  */
    40 public void finalyMethod(JoinPoint joinPoint){
    41     System.out.println("finally method");
    42 } 
    43 /**
    44  * 异常通知
    45  * @param joinPoint    连接点
    46  * @param ex     接收异常   在文件中配置 参数名一致
    47  */
    48 public void throwingMethod(JoinPoint joinPoint,Throwable ex) {
    49     System.out.println(ex.getMessage());    
    50 }
    51 /**
    52  *  环绕通知  在方法前后执行 能够控制方法是否执行
    53  *      其主要在于,
    54  *      如果使用around 来作为切入面,连接点的方法就嵌套在around中来执行,
    55  *      如果around中不获取连接点来执行方法,那么原本的方法不会执行
    56  *  
    57  *      如果在around执行时同样使用了aftereturning来拦截return就必须,
    58  *      在around中执行方法的哪一行就行return的获取,再由around再次进行return,
    59  *      否则afterreturning是拦截不到return的,因为return在around已经断掉了
    60  *  
    61  *  注意在around 中使用的是 ProceedingJoinPoint
    62  * @param joinPoint
    63  * @throws Throwable
    64  */
    65 public Object aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{
    66     System.out.println("aaaaaa");
    67     Object val = joinPoint.proceed();//执行目标方法
    68     System.out.println("bbbbbb");
    69     return val;
    70 }
    71 //public void aroundMethod(ProceedingJoinPoint joinPoint) throws Throwable{
    72 //    System.out.println("aaaaaa");
    73 ////    Object val = joinPoint.proceed();//执行目标方法
    74 //    System.out.println("bbbbbb");
    75 ////    return val;
    76 //}
    77 }

     

    修改Xml配置文件进行注册:

     

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
     7 <bean id="personDao" class="com.person.PersonDaoImpl"></bean>
     8     <bean id="transaction" class="com.person.Transaction"></bean>
     9     <aop:config>
    10         <aop:pointcut 
    11             expression="execution(* com.person.PersonDaoImpl.*(..))" 
    12             id="perform"/>
    13         <!--  切面 -->
    14         <aop:aspect ref="transaction">
    15             <!--    前置通知 -->
    16               <aop:before method="beginTransaction" pointcut-ref="perform"/>
    17             <!-- 后置通知
    18           1、在目标方法执行之后执行 2、能够获取到目标方法的返回值 returning="val"   val:和后置通知方法的接收参数名一样 3、如果目标方法遇到异常,则后置通知将不执行 -->  
    19                 <aop:after-returning method="commit" pointcut-ref="perform" returning="val"/>
    20             <!-- 最终通知 不管目标方法是否遇到异常,最终通知都将执行 -->
    21             <aop:after method="finalyMethod" pointcut-ref="perform"/>
    22             <!--  异常通知 获取目标方法抛出的异常 throwing="ex"和方法中的第二个参数的名称一致 -->
    23             <aop:after-throwing method="throwingMethod" pointcut-ref="perform" throwing="ex"/>
    24             <!--   环绕通知  能够控制目标方法的执行 -->
    25           <!--   <aop:around method="aroundMethod" pointcut-ref="perform"/> -->
    26         </aop:aspect>
    27     </aop:config>
    28 
    29 </beans>    

     

     

     

     

    测试代码:

     

     1 import org.springframework.context.ApplicationContext;
     2 import org.springframework.context.support.ClassPathXmlApplicationContext;
     3 
     4 public class PersonTest {
     5 
     6     public static void main(String[] args) {
     7         ApplicationContext context = new ClassPathXmlApplicationContext("person.xml");
     8         PersonDao personDao = (PersonDao) context.getBean("personDao");
     9         
    10         personDao.savePerson();
    11     }
    12 }

     

     

     输出结果如下:

    targetClass   com.person.PersonDaoImpl@713055ba
    args  [Ljava.lang.Object;@20a07db0
    methodName  savePerson
    开启事务
    save person
    return SavePerson
    事务提交
    finally method

     第二种方式我们可以利用注解来配置

    编写目标对象:

     1 public class Book {
     2 
     3     public String add() {
     4         System.out.println("add....books.....");
     5         return "return Save";
     6     }
     7     public void query() {
     8         System.out.println("query.........");        
     9     }
    10     public void delete () {
    11         System.out.println("delete....books.....");
    12         
    13     }
    14 }

     

    编写切面类:

     1 import org.aspectj.lang.JoinPoint;
     2 import org.aspectj.lang.ProceedingJoinPoint;
     3 import org.aspectj.lang.annotation.After;
     4 import org.aspectj.lang.annotation.AfterReturning;
     5 import org.aspectj.lang.annotation.AfterThrowing;
     6 import org.aspectj.lang.annotation.Around;
     7 import org.aspectj.lang.annotation.Aspect;
     8 import org.aspectj.lang.annotation.Before;
     9 //声明切入面
    10 @Aspect
    11 public class BookAspect {
    12 
    13     //在方法上面使用注解完成增强配置
    14     @Before(value="execution(* cn.aop.Book.*(..))")
    15     public void before(JoinPoint joinPoint) {
    16         //获取目标类 
    17         System.out.println("target :" + joinPoint.getTarget());
    18         //获取连接点的参数
    19         System.out.println("args  :" + joinPoint.getArgs());
    20         //获取链接点的名称
    21         System.out.println("methodName  :" + joinPoint.getSignature().getName());
    22         System.out.println("before..............");
    23     }
    24     
    25     @After(value="execution(* cn.aop.Book.*(..))" )    
    26     public void after() {
    27         System.out.println("after..............");
    28     }
    29 //    @AfterReturning(pointcut="pointcut1",returning="val")
    30 //    @AfterReturning(value="execution(* cn.aop.Book.*(..))",returning="val")
    31     public void afterReturning(Object val){
    32         System.out.println(val);
    33         System.out.println("afterReturning....");
    34         
    35     }
    36     @AfterThrowing(value = "execution(* cn.aop.Book.*(..))")
    37     public void afterThrowing(){
    38         System.out.println("afterThrowing.....");
    39         
    40     }
    41     @Around(value="execution(* cn.aop.Book.*(..))")
    42     public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
    43         System.out.println("aaaaaa");
    44         Object val = joinPoint.proceed();
    45         System.out.println("bbbbbb");    
    46         return val;
    47     }
    48     
    49 }

    Xml文件稍作修改:

     1 <?xml version="1.0" encoding="UTF-8"?>
     2 <beans xmlns="http://www.springframework.org/schema/beans"
     3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     4     xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
     5         http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
     6         http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
     7     
     8     <!-- 开启aop操作 -->
     9     <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    10     <!-- 1  配置对象 -->
    11     <bean id="book" class="cn.aop.Book"></bean>
    12     <bean id="BookAspect" class="cn.aop.BookAspect"></bean>
    13     
    14 <!--     <aop:config>
    15         <aop:pointcut expression="execution(* cn.aop.Book.*(..))" id="pointcut1"/>
    16     </aop:config> -->
    17 </beans>

     

    编写测试类:

     1 import javax.sound.midi.Soundbank;
     2 import org.springframework.beans.BeansException;
     3 import org.springframework.context.ApplicationContext;
     4 import org.springframework.context.support.ClassPathXmlApplicationContext;
     5 
     6 public class TestBook {
     7 
     8     public void testDemo(){
     9             ApplicationContext context = 
    10                     new ClassPathXmlApplicationContext("book.xml");
    11             Book book = (Book) context.getBean("book");
    12             book.add();
    13             System.out.print("
    ");
    14                 book.delete();    
    15 //        System.out.println("
    ");
    16 //        System.out.println(book.query());
    17         }
    18     public static void main(String[] args)  {
    19         TestBook  test = new TestBook();            
    20                 test.testDemo();
    21     }
    22 }

     

    测试结果:

    aaaaaa
    target :cn.aop.Book@61fc0ce6
    args  :[Ljava.lang.Object;@55a19181
    methodName  :add
    before..............
    add....books.....
    bbbbbb
    after..............
    
    aaaaaa
    target :cn.aop.Book@61fc0ce6
    args  :[Ljava.lang.Object;@1b6cdb87
    methodName  :delete
    before..............
    delete....books.....
    bbbbbb
    after..............

     

  • 相关阅读:
    mysql学习【第4篇】:数据库之数据类型
    mysql学习【第3篇】:数据库之增删改查操作
    mysql学习【第2篇】:基本操作和存储引擎
    mysql学习【第1篇】:数据库安装
    模块
    面向对象 之 反射 内置方法
    面向对象 的属性 类方法 静态方法
    python day
    day 18 面向对象的 继承
    python day
  • 原文地址:https://www.cnblogs.com/the-wang/p/7663272.html
Copyright © 2020-2023  润新知