zoukankan      html  css  js  c++  java
  • 【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

    都说酒是陈的香。
  • 相关阅读:
    发现个atan2的正确使用方式
    Forward+ Shading架构
    fatal: unable to connect to gitee.com: gitee.com[0: 180.97.125.228]: errno=Unknown error 解决方案
    HDFS HA(高可用性)集群规划
    如何使用RTP引擎对语音编码进行转码
    关于 Angular 应用 tsconfig.json 中的 target 属性
    浅谈 Orbeon form builder 的权限控制
    关于 Angular 应用 tsconfig.json 中的 lib 属性
    orbeon form 通过 url 的方式同第三方应用集成的开发明细
    orbeon form 的配置介绍
  • 原文地址:https://www.cnblogs.com/yihangjou/p/12005497.html
Copyright © 2011-2022 走看看