• 【Spring学习随笔】4. Spring AOP


    4. Spring AOP

    4.1 Spring AOP的基本概念

    4.1.1 AOP的概念

    AOP ( Aspect-Oriented Programming )面向切面编程,它与OOP (Object-Oriented Programming , 面向对象编程) 相辅相成,提供了与OOP 不同的抽象软件结构的视角。在OOP 中,以类作为程序的基本单元,而AOP 中的基本单元是Aspect (切面)。Struts2的拦截器设计就是基于AOP 的思想,是个比较经典的应用。

    4.1.2 AOP的术语

    • 切面
      切面(Aspect)是指封装横切到系统功能(例如事务处理)的类。
    • 连接点
      连接点(Joinpoint)是指程序运行中的一些时间点,例如方法的调用或异常的抛出。
    • 切人点
      切入点(Pointcut)是指需要处理连接点。在Spring AOP 中,所有的方法执行都是连接点,而切入点是一个描述信息,它修饰的是连接点,通过切入点确定哪些连接点需要被处理。

    image-20191123225950652

    • 通知
      通知(Advice)是由切面添加到特定的连接点(满足切入点规则)的一段代码,即在定义好的切入点处所要执行的程序代码,可以将其理解为切面开启后切面的方法,因此通知是切面的具体实现
    • 引人
      引入(Introduction)允许在现有的实现类中添加自定义的方法和属性
    • 目标对象
      目标对象(Target Object)是指所有被通知的对象。如果AOP 框架使用运行时代理的方式(动态的AOP )来实现切面,那么通知对象总是一个代理对象。
    • 代理
      代理(Proxy)是通知应用到目标对象之后被动态创建的对象
    • 织人
      织入(Weaving)是将切面代码插入到目标对象上,从而生成代理对象的过程。根据不同的实现技术, AOP 织入有3 种方式:编译期织入, 需要有特殊的Java 编译器;类装载期织入, 需要有特殊的类装载器;动态代理织入,在运行期为目标类添加通知生成子类的方式。SpringAOP 框架默认采用动态代理织入,而AspectJ(基于Java 语言的AOP 框架)采用编译期织入和类装载期织入

    4.2 动态代理

    ​ 在Java中有多种动态代理技术,例如JDK、CGLIB、Javassist、ASM,其中最常用的动态代理技术是JDK和CGLIB。目前,在Spring AOP中常用JDK和CGLIB两种动态代理技术

    4.2.1 JDK动态代理

    ​ JDK 动态代理是java.lang . reflect. *包提供的方式,它必须借助一个接口才能产生代理对象。因此,对于使用业务接口的类, Spring 默认使用JDK 动态代理实现AOP

    实例演示:

    • 创建应用,创建接口及实现类,在src的目录下创建一个dynamic.jdk包,在该包中创建接口TestDao和接口实现类TestDaoImpl。该实现类作为目标类,在代理类中对其方法进行增强处理。

      TestDao的代码如下:

      package dynamic.jdk;
      
      public interface TestDao {
          public void save();
          public void modify();
          public void delete();
      }
      

      TestDaoImpl的代码如下:

      package dynamic.jdk;
      
      public class TestDaoImpl implements TestDao {
          @Override
          public void save() {
              System.out.println("保存");
          }
      
          @Override
          public void modify() {
              System.out.println("修改");
          }
      
          @Override
          public void delete() {
              System.out.println("删除");
          }
      }
      
    • 创建切面类

      在src目录下创建一个aspect包,在该包下创建切面类MyAspect,注意在该类中可以定义多个通知(增强处理的功能方法)。

      MyAspect的代码如下:

      package aspect;
      
      /**
       * 切面类,可以定义多个通知,即增强处理的方法
       */
      public class MyAspect {
          public void check() {
              System.out.println("模拟权限控制");
          }
      
          public void except() {
              System.out.println("模拟一场处理");
          }
      
          public void log() {
              System.out.println("模拟日志记录");
          }
      
          public void monitor() {
              System.out.println("性能检测");
          }
      }
      
    • 创建代理类

      在dynamic.jdk包中创建代理类JDKDynamicProxy。在JDK动态代理中代理类必须实现java.lang.reflect.InvocationHandler接口,并编写代理方法,在代理方法中需要通过Proxy实现动态代理。

      JDKDynamicProxy的代码如下:

      package dynamic.jdk;
      
      import aspect.MyAspect;
      
      import java.lang.reflect.InvocationHandler;
      import java.lang.reflect.Method;
      import java.lang.reflect.Proxy;
      
      public class JDKDynamicProxy implements InvocationHandler {
      //    声明目标类接口对象(真实对象)
          private TestDao testDao;
      //    创建代理的方法,建立代理对象和真实对象的代理关系,并返回代理对象
          public Object createProxy(TestDao testDao) {
              this.testDao = testDao;
      //        1. 类加载器
              ClassLoader cld = JDKDynamicProxy.class.getClassLoader();
      //        2. 被代理对象实现的所有接口
              Class[] clazz = testDao.getClass().getInterfaces();
      //        3. 使用代理类进行增强,返回代理后的对象
              return Proxy.newProxyInstance(cld, clazz, this);
          }
      
          /**
           * 代理的逻辑方法,所有动态代理类的方法调用都交给该方法处理
           * proxy是被代理对象
           * method是将要被执行的方法
           * args是执行方法时需要的参数
           * return指返回代理结果
           *
           * @param proxy
           * @param method
           * @param args
           * @return
           * @throws Throwable
           */
          @Override
          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      //        创建一个切面
              MyAspect myAspect = new MyAspect();
      //        前增强
              myAspect.check();
              myAspect.except();
      //        在目标类上调用方法标并传入参数,相当于调用testDao中的方法
              Object obj = method.invoke(testDao, args);
      //        后增强
              myAspect.log();
              myAspect.monitor();
              return obj;
          }
      }
      
    • 创建测试类

      在dynamic.jdk包中创建测试类JDKDynamicTest。在主方法中创建代理对象和目标对象,然后从代理对象中获取对目标对象增强后的对象,最后调用该对象的添加、修改和删除方法。

      JDKDynamicTest的代码如下:

      package dynamic.jdk;
      
      public class JDKDynamicTest {
          public static void main(String[] args) {
      //        创建代理对象
              JDKDynamicProxy jdkProxy = new JDKDynamicProxy();
      //        创建目标对象
              TestDao testDao = new TestDaoImpl();
      //        从代理对象中获取增强后的目标对象,该对象是一个被代理的对象,它会进入代理的逻辑方法invoke中
              TestDao testDaoAdvice = (TestDao) jdkProxy.createProxy(testDao);
      //        执行方法
              testDaoAdvice.save();
              System.out.println("===============");
              testDaoAdvice.modify();
              System.out.println("===============");
              testDaoAdvice.delete();
          }
      }
      
    • 运行效果:

      image-20191125173616991

    4.2.2 CGLIB动态代理

    JDK 动态代理必须提供接口才能使用,对于没有提供接口的类,只能采用CGLIB 动态代理

    ​ CGLIB (Code Generation Library ) 是一个高性能开源的代码生成包,采用非常底层字节码技术,对指定的目标类生成一个子类,并对子类进行增强。在Spring Core 包中己经集成了CGLIB 所需要的JAR 包,不需要另外导入JAR 包。

    实例演示:

    • 创建目标类

      在src目录下创建一个dynamic.cglib包,在该包中创建目标类TestDao,注意该类不需要实现任何接口。

      TestDao的代码如下:

      
      

    4.3 基于代理类的AOP实现

    在Spring中默认使用JDK动态代理实现AOP编程。使用org.springframework.aop.framwork.ProxyFactoryBean创建代理是Spring AOP实现的最基本方式。

    4.3.1 通知类型

    根据Spring中通知在目标类方法中的连接点位置,通知可以分为6种类型。

    4.3.1.1 环绕通知

    ​ 环绕通知(org.aopallicance.intercept.MethodIntercerptor)是在目标方法执行前和执行后实施增强,可应用于日志记录、事务处理等功能

    4.3.1.2 前置通知

    ​ 前置通知(org.springframework.aop.MethodBeforeAdvice)实在目标方法执行前实施增强,可应用于权限管理等功能

    4.3.1.3 后置返回通知

    ​ 后置返回通知(org.springframework.aop.AfterReturningAdvice)是在目标方法成功执行后实施增强,可应用于关闭流、删除临时文件等功能

    4.1.3.5 后置(最终)通知

    ​ 后置通知(org.springframework.aop.AfterAdvice)是在目标方法执行后实施增强,与后置返回通知不同的是,不管是否发生异常都要执行该类通知,该类通知可应用于释放资源

    4.1.3.6 引入通知

    ​ 引入通知(org.springframework.aop.IntroductionInterceptor)是在目标类中添加一些新的方法和属性,可应用于修改目标类(增强类)

    4.3.2 ProxyFactoryBean

    ​ ProxyFactoryBean是org.springframework.beans.factory.FactoryBean接口的实现类,FactoryBean负责实例化一个Bean实例,ProxyFactoryBean负责为其他Bean实例创建代理实例。

    *** ProxyFactoryBean类的常用属性**:

    4.4 基于XML配置开发AspectJ

    ​ AspectJ是一个基于Java语言的AOP框架。使用AspectJ实现Spring AOP的方式有两种,一是基于XML配置开发AspectJ,二是基于注解开发AspectJ。

    ​ 基于XML配置开发AspectJ是指通过XML配置文件定义切面、切入点及通知,所有这些定义都必须在<aop:config>元素内。<aop:config>元素及其子元素如下表所示:

    image-20191126124023343

    各类型通知与目标方法的执行过程,具体过程如图所示:

    image-20191126124203736

    4.5 基于注解开发AspectJ

    ​ 基于注解开发AspectJ要比基于XML配置开发AspectJ便捷许多,所以在实际开发中推荐使用注解方法。

    AspectJ注解,如下表所示:

    image-20191126124359161

    都说酒是陈的香。
  • 相关阅读:
    easyui struts后台实现tree返回json数据
    jquery扩展方法
    EasyUI tree扩展获取实心节点
    Hibernate之AbstractEntityPersister
    No CurrentSessionContext configured 异常解决
    Dubbo远程调用服务框架原理与示例
    mongodb高级操作及在Java企业级开发中的应用
    Java和MongoDB之Hello World
    Vmware 虚拟的Linux系统如何与宿主主机共享上网
    VM VirtualBox 上安装 CentOs6.4(详细)
  • 原文地址:https://www.cnblogs.com/yihangjou/p/12005497.html
Copyright © 2020-2023  润新知