Spring AOP的使用

Spring AOP使用原理

  1. AOP的相关术语

    1. Joinpoint(连接点) – 所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点
    2. Pointcut(切入点)– 所谓切入点是指我们要对哪些Joinpoint进行拦截的定义
    3. Advice(通知/增强)– 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知.通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)
    4. Introduction(引介)– 引介是一种特殊的通知在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field
    5. Target(目标对象)– 代理的目标对象
    6. Weaving(织入)– 是指把增强应用到目标对象来创建新的代理对象的过程
    7. Proxy(代理)– 一个类被AOP织入增强后,就产生一个结果代理类
    8. Aspect(切面)– 是切入点和通知的结合,以后咱们自己来编写和配置的
  2. 底层实现

    1. Srping框架的AOP技术底层也是采用的代理技术,代理的方式提供了两种

      1. 基于JDK的动态代理

        • 必须是面向接口的,只有实现了具体接口的类才能生成代理对象
      2. 基于CGLIB动态代理

        • 对于没有实现了接口的类,也可以产生代理,产生这个类的子类的方式
    2. Spring的传统AOP中根据类是否实现接口,来采用不同的代理方式

      1. 如果实现类接口,使用JDK动态代理完成AOP
      2. 如果没有实现接口,采用CGLIB动态代理完成AOP
  3. JDK代理动态代理

    1. 使用Proxy类来生成代理对象的一些代码如下:
    /**
     * 使用JDK的方式生成代理对象
     * @author Administrator
     */
    public class MyProxyUtils {
       public static UserDao getProxy(final UserDao dao) {
           // 使用Proxy类生成代理对象
           UserDao proxy = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(),
                   dao.getClass().getInterfaces(), new InvocationHandler() {           
                       // 代理对象方法一直线,invoke方法就会执行一次
                       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                           if("save".equals(method.getName())){
                               System.out.println("记录日志...");
                               // 开启事务
                           }
                           // 提交事务
                           // 让dao类的save或者update方法正常的执行下去
                           return method.invoke(dao, args);
                       }
                   });
           // 返回代理对象
           return proxy;
       }
    }
  4. CGLIB代理技术

    1. 使用Proxy类来生成代理对象的一些代码如下:
    /**
     * 使用JDK的方式生成代理对象
     * @author Administrator
     */
    public class MyProxyUtils {
       public static UserDao getProxy(final UserDao dao) {
           // 使用Proxy类生成代理对象
           UserDao proxy = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(),
                   dao.getClass().getInterfaces(), new InvocationHandler() {
    
                       // 代理对象方法一直线,invoke方法就会执行一次
                       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                           if("save".equals(method.getName())){
                               System.out.println("记录日志...");
                               // 开启事务
                           }
                           // 提交事务
                           // 让dao类的save或者update方法正常的执行下去
                           return method.invoke(dao, args);
                       }
                   });
           // 返回代理对象
           return proxy;
       }
    }
  5. 技术分析之AspectJ的XML方式完成AOP的开发

    1. 步骤一:创建JavaWEB项目,引入具体的开发的jar包

      • 先引入Spring框架开发的基本开发包
      • 再引入Spring框架的AOP的开发包
      • spring的传统AOP的开发的包

        • spring-aop-4.2.4.RELEASE.jar
        • com.springsource.org.aopalliance-1.0.0.jar
      • aspectJ的开发包

        • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
        • spring-aspects-4.2.4.RELEASE.jar
    2. 步骤二:创建Spring的配置文件,引入具体的AOP的schema约束

      <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">
    3. 步骤三:创建包结构,编写具体的接口和实现类

      • com.itheima.demo2
      • CustomerDao – 接口
        • CustomerDaoImpl – 实现类
    4. 步骤四:将目标类配置到Spring中
      < bean id=”customerDao” class=”com.itheima.demo3.CustomerDaoImpl”/>

    5. 步骤五:定义切面类

      public class MyAspectXml {
      // 定义通知
      public void log(){
      System.out.println("记录日志...");
      }
      }
    6. 步骤六:在配置文件中定义切面类
      < bean id=”myAspectXml” class=”com.itheima.demo3.MyAspectXml”/>

    7. 步骤七:在配置文件中完成aop的配置

      <aop:config>
         <!-- 引入切面类 -->
         <aop:aspect ref="myAspectXml">
             <!-- 定义通知类型:切面类的方法和切入点的表达式 -->
             <aop:before method="log" pointcut="execution(public * com.itheima.demo3.CustomerDaoImpl.save(..))"/>
         </aop:aspect>
      </aop:config>
    8. 完成测试

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:applicationContext.xml")
      public class Demo3 {
         @Resource(name="customerDao")
         private CustomerDao customerDao;
         @Test
         public void run1(){
             customerDao.save();
             customerDao.update();
             customerDao.delete();
         }
      }
  6. 切入点表达式

    1. 在配置切入点的时候,需要定义表达式,重点的格式如下:execution(public * *(..)),具体展开如下:

      • 切入点表达式的格式如下:
      • execution([修饰符] 返回值类型 包名.类名.方法名(参数))

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

      • 返回值类型是不能省略不写的,根据你的方法来编写返回值。可以使用 * 代替。
      • 包名例如:com.itheima.demo3.BookDaoImpl
      • 首先com是不能省略不写的,但是可以使用 * 代替
      • 中间的包名可以使用 * 号代替
      • 如果想省略中间的包名可以使用 ..

      • 类名也可以使用 * 号代替,也有类似的写法:*DaoImpl

      • 方法也可以使用 * 号代替
      • 参数如果是一个参数可以使用 * 号代替,如果想代表任意参数使用 ..
  7. AOP的通知类型

    1. 前置通知

      • 在目标类的方法执行之前执行。
      • 配置文件信息:< aop:after method=”before” pointcut-ref=”myPointcut3”/>
      • 应用:可以对方法的参数来做校验
    2. 最终通知

      • 在目标类的方法执行之后执行,如果程序出现了异常,最终通知也会执行。
      • 在配置文件中编写具体的配置:< aop:after method=”after” pointcut-ref=”myPointcut3”/>
      • 应用:例如像释放资源
    3. 后置通知

      • 方法正常执行后的通知。
      • 在配置文件中编写具体的配置:< aop:after-returning method=”afterReturning” pointcut-ref=”myPointcut2”/>
      • 应用:可以修改方法的返回值
    4. 异常抛出通知

      • 在抛出异常后通知
      • 在配置文件中编写具体的配置:< aop:after-throwing method=”afterThorwing” pointcut-ref=”myPointcut3”/>
      • 应用:包装异常的信息
    5. 环绕通知

      • 方法的执行前后执行。
      • 在配置文件中编写具体的配置:< aop:around method=”around” pointcut-ref=”myPointcut2”/>
      • 要注意:目标的方法默认不执行,需要使用ProceedingJoinPoint对来让目标对象的方法执行。
  8. AOP注解配置

    1. 步骤一:创建JavaWEB项目,引入具体的开发的jar包

      • 先引入Spring框架开发的基本开发包
      • 再引入Spring框架的AOP的开发包
      • spring的传统AOP的开发的包

        • spring-aop-4.2.4.RELEASE.jar
        • com.springsource.org.aopalliance-1.0.0.jar
      • aspectJ的开发包

        • com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
        • spring-aspects-4.2.4.RELEASE.jar
    2. 步骤二:创建Spring的配置文件,引入具体的AOP的schema约束

      <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">
      
      </beans>
    3. 步骤三:创建包结构,编写具体的接口和实现类

      • com.itheima.demo1
      • CustomerDao – 接口
        • CustomerDaoImpl– 实现类
    4. 步骤四:将目标类配置到Spring中
      < bean id=”customerDao” class=”com.itheima.demo1.CustomerDaoImpl”/>

    5. 步骤五:定义切面类

      • 添加切面和通知的注解
      • @Aspect – 定义切面类的注解

      • 通知类型(注解的参数是切入点的表达式)

        • @Before – 前置通知
        • @AfterReturing – 后置通知
        • @Around – 环绕通知
        • @After – 最终通知
        • @AfterThrowing – 异常抛出通知
      • 具体的代码如下

        @Aspect
        public class MyAspectAnno {
        @Before(value="execution(public void com.itheima.demo1.CustomerDaoImpl.save())")
        public void log(){
           System.out.println("记录日志...");
        }
        }
    6. 步骤六:在配置文件中定义切面类
      < bean id=”myAspectAnno” class=”com.itheima.demo1.MyAspectAnno”/>

    7. 步骤七:在配置文件中开启自动代理
      < aop:aspectj-autoproxy/>

    8. 完成测试

      @RunWith(SpringJUnit4ClassRunner.class)
      @ContextConfiguration("classpath:applicationContext.xml")
      public class Demo1 {
      
         @Resource(name="customerDao")
         private CustomerDao customerDao;
      
         @Test
         public void run1(){
             customerDao.save();
             customerDao.update();
         }
      }
  9. 通知注解配置

    1. 通知类型

      • @Before – 前置通知
      • @AfterReturing– 后置通知
      • @Around– 环绕通知(目标对象方法默认不执行的,需要手动执行)
      • @After– 最终通知
      • @AfterThrowing– 异常抛出通知
    2. 配置通用的切入点

      • 使用@Pointcut定义通用的切入点
        @Aspect
        public class MyAspectAnno {
        @Before(value="MyAspectAnno.fn()")
        public void log(){
           System.out.println("记录日志...");
        }
        @Pointcut(value="execution(public void com.itheima.demo1.CustomerDaoImpl.save())")
        public void fn(){}
        }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值