Spring(四)【AOP】

动态代理

  动态代理是指程序在整个运行过程中根本就不存在目标类的代理类,目标对象的代理对象只是由代理生成工具(非真实定义的类)在程序运行时由JVM根据反射机制等机制动态生成的。代理对象与目标对象的代理关系在程序运行时才确立

 

动态代理的方式:

  1)JDK动态代理:要求是目标类必须实现接口

      java语言通过java.lang.reflect包提供三个类支持代理模式:

        Proxy:Proxy.newProxyInstance()  创建目标对象的代理对象

 

        Method:method.invoke(target,args)  创建目标方法

        InvocationHandler接口:在接口的实现类中,重写invoke(),实现功能的增强

  2)cglib动态代理:cglib第三方的工具库,能够生成代理对象

      cglib创建代理对象的原理:继承。cglib能够创建目标类的子类,在子类中重写方法,实现功能的增强,该子类就是代理类

      cglib的使用要求:目标类不是final的,目标方法也不能是final的

 

AOP(Aspect Orient Programming):面向切面编程,是基于动态代理的,把动态代理的技术进行了规范,升华。

AOP中可以使用jdk动态代理,也可以使用cglib动态代理

  Aspect:切面,指需要增强的功能,包括:常见的事务、日志、方法参数的检查、权限、统计执行时间,切面有一个特点是非业务功能,一般是可以单独使用的

  JoinPoint:连接点,指业务方法,这个方法加入了切面的功能

  PointCut:切入点,连接点的集合,有0或多个连接点(方法),切入点表示切面执行的位置

  目标对象:需要被增强功能的类

  Advice:通知,通知表示切面执行的时间,通知也属于增强,是切面在程序中的表示,通知可以是接口也可以是注解

      例如:在方法前,或方法后,或方法前和方法后

 

  注意:一个切面执行需要有切入点和通知

 

 理解面向切面的开发:

    1)识别切面,从项目中找出能够作为切面的功能,形成单独的模块

    2)把切面加入合适的位置,合适的时间

 

AOP的好处:解耦合:业务功能和非业务功能的耦合,减少重复代码

 

实现AOP框架的工具

  1)Aspectj

    Aspectj实现AOP的两个重要概念

      a)通知:共分五种:前置、后置、环绕、异常、最终,每种通知都表示一次执行时间

      b)切入点表达式:execution(方法的定义),表示切面执行的位置

 

 

 

    Aspectj实现AOP的两种方式:

      a)使用注解表示通知

      b)使用xml配置文件(做事务时使用这种方式)

 

    Aspectj实现AOP的步骤

      a)新建Maven

      b)加入依赖:spring依赖和Aspectj依赖

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>4.3.16.RELEASE</version>
</dependency>

      c)新建业务接口和实现类,要给业务方法增强功能

      d)新建切面类

        d.1)在类的定义上@Aspect

        

        d.2)在类中自定义实现切面的自定义方法,在方法的上面加入@aspectj中的通知注解,例如@Before

 

       

      e)新建spring的配置文件  

        e.1)声明目标类对象

        e.2)声明切面类对象

        e.3)通过spring和aspectj创建目标对象的代理

      

      f)新建测试类,从spring容器中获取对象,通过这个对象执行业务方法,实现业务功能的增强

 

 

    通过JoinPoint获取doSome方法在执行时的信息

 

     注意:JoinPoint可以用在所有的通知方法中,但如果通知方法中有多个参数时,JoinPoint必须位于第一个

    

  @AfterReturning:后置通知

      属性:

        1)value:切入点表达式

        2)returning:自定义的变量,表示目标方法的返回值,变量的名称必须和通知方法的参数名一样

      特点:

        1)在目标方法之后执行的 

        2)能够获取到目标方法的执行结果

        3)修改目标方法不会影响最后的执行结果

   

  注意:当返回结果为基本数据类型和字符串时,在通知方法里对返回值进行修改,不会影响目标方法的返回结果,因为这个值是拷贝过来的。但是如果返回的是对象(如上图),那么返回结果就会发生改变,因为这里返回的是对象的引用,我们通过引用改变了堆内存中对象的属性,就会对目标方法中的返回结果产生影响

 

  @Around:环绕通知

    属性:value(切入点表达式)

    特点:

      1)在目标方法的前后都能增强功能

      2)控制目标方法是否执行

      3)修改目标方法的执行结果

 

    环绕通知方法的定义:

      1)有参数ProceedingJoinPoint,且因为ProceedingJoinPoint继承JoinPoint,因此可以通过pjp获取连接点方法的定义、方法的名称、参数等信息

      2)有返回值,推荐使用Object

 

   @AfterThrowing:异常通知

    属性:

      1)value:切入点表达式

      2)throwing:自定义的变量,表示目标方法抛出的异常对象,必须和通知方法参数名一样

    特点:

      1)在目标方法抛出异常时执行的,可以看作是对目标方法监控

      2)不是异常处理程序,异常还是抛出的

 

 

  @After:最终通知

    属性:value(切入点表达式)

    特点:

      1)在目标方法之后执行的

      2)总是会被执行的

 

 

  @Pointcut:定义和管理切入点

    属性:value(切入点表达式)

    作用:这个方法的名称就是切入点的别名,其他的通知注解的value属性可以使用方法名称,表示切入点

 

 

 

  当目标类有接口时,默认使用的是JDK动态代理,目标类没有接口,默认使用cglib动态代理。

  当目标类有接口时,也可以使用cglib动态代理,需要在声明自动代理生成器后边添加proxy-target-class="true",即可

 

 

    

  通过xml的方式来实现AOP

    1)新建一个类,类里面包含所需要的通知方法

    2)在配置文件中声明目标类与切面类对象

    3)配置AOP

      3.1)声明切入点的位置

      3.2)声明切面

      3.3)配置通知

 

 

 

  2)spring框架使用aop

    关键步骤:

      1)实现通知的接口,例如环绕通知MethodInterceptor

      2)在spring的配置文件中,声明ProxyFactoryBean,创建目标对象的代理,ProxyFactoryBean其作用等同于jdk动态代理中的Proxy

 

    具体步骤:

      1)新建Maven

      2)加入依赖,只需spring依赖

      3)新建业务接口和实现类,要给业务方法增强功能

      4)新建实现接口的类,在类中重写方法,实现功能的增强(相当于InvocationHandler)

        spring中AOP的可用接口:

          前置通知:MethodBeforeAdvice

          后置通知:AfterReturningAdvice

          环绕通知:MethodInterceptor

          异常通知:ThrowsAdvice  

      5)新建spring配置文件

        5.1)声明目标类和切面类对象

        5.2)声明ProxyFactoryBean,创建目标对象的代理对象

      6)新建测试类,从spring容器中获取对象,通过这个对象执行业务方法,实现功能的增强

 

posted @ 2020-04-27 00:22  Rhettttt  阅读(122)  评论(0)    收藏  举报