zoukankan      html  css  js  c++  java
  • 解析Spring第三天(面向切面AOP)

    面向切面:AOP

    在不修改源代码的基础上,对方法进行增强。AOP的底层原理就是代理技术(第一种:jdk的动态代理(编写程序必须要有接口)。第二种:cglib代理技术(生成类的子类)。如果编写的程序有借口,则spring框架会自动使用jdk的动态代理技术增强,)。

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

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

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

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

    Weaving(织入)-- 是指把增强应用到目标对象来创建新的代理对象的过程

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

    Aspect(切面)-- 是切入点和通知的结合,以后自己来编写和配置的

     创建一个普通的Maven项目工程引入坐标

     1 <dependencies>
     2     <dependency>
     3         <groupId>org.springframework</groupId>
     4         <artifactId>spring-context</artifactId>
     5         <version>5.0.2.RELEASE</version>
     6     </dependency>
     7     <dependency>
     8         <groupId>commons-logging</groupId>
     9         <artifactId>commons-logging</artifactId>
    10         <version>1.2</version>
    11     </dependency>
    12     <dependency>
    13         <groupId>log4j</groupId>
    14         <artifactId>log4j</artifactId>
    15         <version>1.2.12</version>
    16     </dependency>
    17     <dependency>
    18         <groupId>org.springframework</groupId>
    19         <artifactId>spring-test</artifactId>
    20         <version>5.0.2.RELEASE</version>
    21     </dependency>
    22     <dependency>
    23         <groupId>junit</groupId>
    24         <artifactId>junit</artifactId>
    25         <version>4.12</version>
    26     </dependency>
    27   
    28         <!-- AOP联盟 -->
    29         <dependency>
    30             <groupId>aopalliance</groupId>
    31             <artifactId>aopalliance</artifactId>
    32             <version>1.0</version>
    33         </dependency>
    34         <!-- Spring Aspects -->
    35         <dependency>
    36             <groupId>org.springframework</groupId>
    37             <artifactId>spring-aspects</artifactId>
    38             <version>5.0.2.RELEASE</version>
    39         </dependency>
    40         <!-- aspectj -->
    41         <dependency>
    42             <groupId>org.aspectj</groupId>
    43             <artifactId>aspectjweaver</artifactId>
    44             <version>1.8.3</version>
    45         </dependency>
    46   </dependencies>
    • 创建Spring的配置文件,引入具体的AOP的schema约束

       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:context="http://www.springframework.org/schema/context"
       5        xmlns:aop="http://www.springframework.org/schema/aop"
       6        xsi:schemaLocation="
       7                 http://www.springframework.org/schema/beans
       8                 http://www.springframework.org/schema/beans/spring-beans.xsd
       9                 http://www.springframework.org/schema/context
      10                 http://www.springframework.org/schema/context/spring-context.xsd
      11                 http://www.springframework.org/schema/aop
      12                 http://www.springframework.org/schema/aop/spring-aop.xsd">
      13     
      14 </beans>
    • 创建包结构,编写具体的接口和实现类
      1 package cn.tx.demo2;
      2 public class UserServiceImpl implements UserService {
      3 4     @Override
      5     public void save() {
      6         System.out.println("业务层:保存用户...");
      7     }
      8 9 }
    • 将目标类配置到Spring中
      <bean id="userService" class="cn.tx.demo2.UserServiceImpl"/>
    • 自定义切面类
       1 package cn.tx.demo2;
       2  3 /**
       4  * 自定义切面类 = 切入点(表达式) + 通知(增强的代码)
       5  */
       6 public class MyXmlAspect {
       7  8     /**
       9      * 通知
      10      */
      11     public void log(){
      12         // 发送手机短信
      13         // 发送邮件/记录日志/事务管理
      14 15         System.out.println("增强的方法执行了...");
      16     }
      17 18 }
    • 在配置文件中定义切面类

      1 <bean id="myXmlAspect" class="cn.tx.demo2.MyXmlAspect"/>
    • 在配置文件中完成aop的配置

      1   <!--配置AOP的增强-->
      2     <aop:config>
      3         <!--配置切面 = 切入点 + 通知组成-->
      4         <aop:aspect ref="myXmlAspect">
      5             <!--前置通知:UserServiceImpl的save方法执行前,会增强-->
      6             <aop:before method="log" pointcut="execution(public void cn.tx.demo2.UserServiceImpl.save())" />
      7         </aop:aspect>
      8     </aop:config>
    • 对增强进行测试
      package cn.tx.test;
      ​
      import cn.tx.demo2.UserService;
      import org.junit.Test;
      import org.junit.runner.RunWith;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.test.context.ContextConfiguration;
      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      
      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:applicationContext_demo2.xml")
      public class Demo2 {
      ​
          @Autowired
          private UserService userService;
      ​
          /**
           * 测试
           */
          @Test
          public void run1(){
              userService.save();
          }
      ​
      }
    • 切入点的表达式格式:
      • execution([修饰符] 返回值类型 包名.类名.方法名(参数))

      • 修饰符可以省略不写,不是必须要出现的。

      • 返回值类型是不能省略不写的,根据你的方法来编写返回值。可以使用 * 代替。

      • 包名例如:com.tx.demo3.BookDaoImpl

        • 首先com是不能省略不写的,但是可以使用 * 代替
        • 中间的包名可以使用 * 号代替
        • 如果想省略中间的包名可以使用 ..
      • 类名也可以使用 * 号代替,也有类似的写法:*DaoImpl

      • 方法也可以使用 * 号代替

      • 参数如果是一个参数可以使用 * 号代替,如果想代表任意参数使用 ..

    • AOP的通知方式
       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:context="http://www.springframework.org/schema/context"
       5        xmlns:aop="http://www.springframework.org/schema/aop"
       6        xsi:schemaLocation="
       7                 http://www.springframework.org/schema/beans
       8                 http://www.springframework.org/schema/beans/spring-beans.xsd
       9                 http://www.springframework.org/schema/context
      10                 http://www.springframework.org/schema/context/spring-context.xsd
      11                 http://www.springframework.org/schema/aop
      12                 http://www.springframework.org/schema/aop/spring-aop.xsd">
      13 
      14     <!--bean管理-->
      15     <bean id="userService" class="cn.tx.demo1.UserServiceImpl" />
      16 
      17     <!--=================编写AOP配置文件====================-->
      18     <!--先配置切面类-->
      19     <bean id="myXmlAspect" class="cn.tx.demo1.MyXmlAspect" />
      20 
      21     <!--配置AOP的增强-->
      22     <aop:config>
      23         <!--正在配置切面,引入真正切面对象-->
      24         <aop:aspect ref="myXmlAspect">
      25             <!--配置的是前置通知:目标对象方法执行前,先增强。method="切面类中通知的方法" pointcut="切入点的表达式"-->
      26             <!--
      27                 切入点的表达式
      28                     execution() 写法是固定的
      29                     public  可以省略不写的
      30                     方法返回值   void int String * 通用的写法
      31                     包名  * 通用的写法
      32                     类名  * 推荐的写法 *ServiceImpl 例如:UserServiceImpl DeptServiceImpl
      33                     方法名称    *  推荐写法:save*
      34                     方法参数列表  .. == Object... obj Object类型的可变参数
      35                     <aop:before method="log" pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      36             -->
      37 
      38             <!--
      39                 通知类型
      40                     前置通知:目标对象方法执行前,先增强。
      41                     <aop:before method="log" pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      42 
      43                     最终通知:目标对象方法执行成功或者失败,都会增强。finally
      44                     <aop:after method="log" pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      45 
      46                     后置通知:目标对象方法执行成功,才会增强。
      47                     <aop:after-returning method="log"  pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      48 
      49                     异常通知:目标对象方法执行失败,才会增强。
      50                     <aop:after-throwing method="log"  pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      51 
      52                     <aop:before method="begin" pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      53                     <aop:after-returning method="commit"  pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      54                     <aop:after-throwing method="rollback"  pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      55                     <aop:after method="close" pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      56 
      57                     环绕通知:自己决定增强的位置。使用了环绕通知,目标对象的方法默认没有执行的,需要自己手动执行目标对象方法。
      58             -->
      59 
      60             <aop:around method="logAroud"  pointcut="execution(* cn.tx.*.*ServiceImpl.save*(..))" />
      61 
      62         </aop:aspect>
      63     </aop:config>
      64 
      65 </beans>

      Spring的AOP技术-注解方式

    • 同样创建一个普通的Maven工程,导入坐标,编写接口,同上
    • 编写一个切面类,给切面类添加注解 @Aspect,编写增强的方法,使用通知类型注解声明
       1 package cn.tx.demo3;
       2  3 import org.aspectj.lang.annotation.Aspect;
       4 import org.aspectj.lang.annotation.Before;
       5 import org.springframework.stereotype.Component;
       6 
      12 @Component  // 把该类交给IOC去管理
      13 @Aspect     // 声明是切面类  == <aop:aspect ref="myXmlAspect">
      14 public class MyAnnoAspect {
      15 16     /**
      17      * 通知的方法
      18      */
      19     // @Before(value = "切入点的表达式")
      20     @Before(value = "execution(public * cn.tx.demo3.OrderServiceImpl.save(..))")
      21     public void log(){
      22         System.out.println("增强了...");
      23     }
      24 25 }
      26
    • 配置文件中开启自动代理

      <aop:aspectj-autoproxy/>
    • 测试方法

       1  
       2 package cn.tx.test;
       3  4 import cn.tx.demo2.UserService;
       5 import cn.tx.demo3.OrderService;
       6 import org.junit.Test;
       7 import org.junit.runner.RunWith;
       8 import org.springframework.beans.factory.annotation.Autowired;
       9 import org.springframework.test.context.ContextConfiguration;
      10 import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      11 
      12 
      13 @RunWith(SpringJUnit4ClassRunner.class)
      14 @ContextConfiguration("classpath:applicationContext_demo3.xml")
      15 public class Demo3 {
      16 17     @Autowired
      18     private OrderService orderService;
      19 20     /**
      21      * 测试
      22      */
      23     @Test
      24     public void run1(){
      25         orderService.save();
      26     }
      27 28 }
      • @RunWith(SpringJUnit4ClassRunner.class)    //在使用所有注释前必须使用@RunWith(SpringJUnit4ClassRunner.class),让测试运行于spring测试环境
      •   @ContextConfiguration 用来指定加载的Spring配置文件位置,会加载默认配置文件。

           @ContextConfiguration有两个常用的属性,locations、inheritLocations

           locations:可以通过该属性手工指定spring配置文件所在的位置,可以指定一个或多个spring的配置文件,要使用【,】隔开。 例如:@ContextConfiguration(locations={“aa/aa.xml”,” aa/bb.xml”})

              inheritLocations:是否要继承父测试用例中的Spring 配置文件,默认是true。

      • 拓展注解解析:
      • @DirtiesContext(classMode = ClassMode.AFTER_CLASS): //@DirtiesContext 在测试方法上出现这个注解时,表明底层Spring容器在该方法的执行中被“污染”,从而必须在方法执行结束后重新创建(无论该测试是否通过)。
      • @TransactionConfiguration( transactionManager = "transactionManager" , defaultRollback = false) 

          @TransactionConfiguration为配置事物性测试定义了类级别的元数据。PlatformTransactionManager默认的实例叫transactionManager,如果需要的PlatformTransactionManager不                                   是“transactionManager”的话,那么可以显示配置驱动事物的PlatformTransactionManager的bean的名字。此外,可以将defaultRollback标志改为false,表示不回滚。通常,                               @TransactionConfiguration与@ContextConfiguration搭配使用。

          @ContextConfiguration
          @TransactionConfiguration(transactionManager="transactionManager", defaultRollback=false)】

    • 通知类型注解

      1 @Before    -- 前置通知
      2 
      3 ​    @AfterReturing    -- 后置通知
      4 
      5 ​    @Around    -- 环绕通知(目标对象方法默认不执行的,需要手动执行)
      6 
      7 ​    @After    -- 最终通知
      8 
      9 ​    @AfterThrowing    -- 异常抛出通知
    • 纯注解的方式

      package cn.tx.demo3;
      ​
      import org.springframework.context.annotation.ComponentScan;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.context.annotation.EnableAspectJAutoProxy;
      ​
      
      @Configuration      // 配置类
      @ComponentScan(value = "cn.tx.demo3")   // 扫描包
      @EnableAspectJAutoProxy     // 开启自动代理 == <aop:aspectj-autoproxy />
      public class SpringConfig {
          
      }
  • 相关阅读:
    当Django模型迁移时,报No migrations to apply 问题时
    django--各个文件的含义
    django--创建项目
    1013. Battle Over Cities (25)
    1011. World Cup Betting (20)
    1009. Product of Polynomials (25)
    1007. Maximum Subsequence Sum (25)
    1006. Sign In and Sign Out (25)
    1008. Elevator (20)
    1004. Counting Leaves (30)
  • 原文地址:https://www.cnblogs.com/LBJLAKERS/p/11750094.html
Copyright © 2011-2022 走看看