zoukankan      html  css  js  c++  java
  • spring笔记3-AOP

    一.概述
    AOP:(Aspect Oriented Programming)即:面向切面编程。把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。

    二.术语
    Joinpoint(连接点):可以被代理增强的方法,即被spring拦截到的点,spring中点即方法,因为spring只支持方法类型的连接点;
    Pointcut(切入点):需要或已经被增强的Joinpoint;
    Advice(通知):拦截到Joinpoint之后要做的事情即为通知,即要增强的方法;
         通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
    Target(目标对象):代理的目标对象,或被增强的对象,或Pointcut所在对象;
    Proxy(代理对象):对目标对象进行增强后产生的对象;一个类被AOP织入增强后,就产生一个结果代理类。
    Weaver(织入):把增强应用到目标对象来创建新的代理对象的过程。将通知应用到切点的过程,称为Weaver;spring采用动态代理织入,而AspectJ采用编译期织入和类装载期织入。
    Aspect(切面):切点+通知
    Introduction(引介):引介是一种特殊的通知,在不修改类代码的前提下, Introduction可以在运行期为类动态地添加一些方法或Field。

    三.案例演示:xml--抽取UserServiceImpl中的公共代码
    1.导包-4+2/aspects/aop/aopalliance/aspectj.weaver/test
    2.建立工程结构:
         huguangqin.com.cnblogs.advice
         huguangqin.com.cnblogs.service
         huguangqin.com.cnblogs.service.serviceImpl
         huguangqin.com.cnblogs.test
    3.准备目标对象--要增强的方法所在类UserServiceImpl
        

      1 package huguangqin.com.cnblogs.service.serviceImpl;
      2     import huguangqin.com.cnblogs.service.UserService;
      3      public class UserServiceImpl implements UserService {
      4          @Override
      5          public void save() {
      6              System.out.println("客户保存了");
      7          }
      8 
      9         @Override
     10          public void delete() {
     11              System.out.println("客户删除了");
     12          }
     13 
     14         @Override
     15          public void find() {
     16              System.out.println("客户找到了");
     17          }
     18 
     19         @Override
     20          public void update() {
     21              System.out.println("客户更新了");
     22          }
     23      }
     24 
    4 .准备通知--增强的方法myAdvice
        
      1 package huguangqin.com.cnblogs.advice;
      2      import org.aspectj.lang.ProceedingJoinPoint;
      3      //通知类
      4     public class MyAdvice {
      5          // 前置
      6         public void before() {
      7              System.out.println("我是前置通知!");
      8          }
      9 
     10         // 环绕通知
     11         /*
     12          * spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数
     13          * 在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。
     14          * 该接口中有一个方法proceed(),此方法就相当于method.invoke()
     15           */
     16          public Object around(ProceedingJoinPoint pjp) throws Throwable {
     17              System.out.println("我是环绕通知,前半部分!");
     18              // 执行目标方法
     19             Object proceed = pjp.proceed();
     20              System.out.println("我是环绕通知,后半部分!");
     21              return proceed;
     22          }
     23 
     24         // 后置 => 出现异常就不执行的后置通知
     25         public void afterReturning() {
     26              System.out.println("我是后置通知,出现异常就不执行的后置通知!");
     27          }
     28 
     29         // 最终通知 => 无论是否出现异常都执行的后置通知
     30         public void after() {
     31              System.out.println("我是最终通知,出现异常仍然执行的后置通知!");
     32          }
     33 
     34         // 异常 => 出现异常才执行的通知
     35         public void afterThrowing() {
     36              System.out.println("我是异常通知,出现异常才执行的通知!");
     37          }
     38      }
     39 
    5 .编写配置对象applicationContext.xml(位置在src下)
       
      1  <?xml version="1.0" encoding="UTF-8"?>
      2 
      3     <beans
      4      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      5      xmlns="http://www.springframework.org/schema/beans"
      6      xmlns:context="http://www.springframework.org/schema/context"
      7      xmlns:aop="http://www.springframework.org/schema/aop"
      8      xsi:schemaLocation="http://www.springframework.org/schema/beans
      9                          http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
     10                          http://www.springframework.org/schema/context
     11                          http://www.springframework.org/schema/context/spring-context-4.2.xsd
     12                          http://www.springframework.org/schema/aop
     13                          http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
     14 
     15      <!--配置目标对象  -->
     16      <bean name="userService" class="huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl"></bean>
     17 
     18     <!--配置通知对象  -->
     19      <bean name="myAdvice" class="huguangqin.com.cnblogs.advice.MyAdvice"></bean>
     20 
     21     <!--将通知织入目标  -->
     22      <!-- 切点表达式
     23         public void huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl.save()
     24          * huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..):
     25              第一个*代表:返回值任意;
     26              第二个*代表:包内所有以ServiceImpl结尾的类;
     27              第三个*代表:类内所有方法
     28             括号内..代表:任意参数
     29      -->
     30      <aop:config>
     31          <!--配置切点  -->
     32          <aop:pointcut expression="execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))" id="mypc"></aop:pointcut>
     33          <!--配置切面  -->
     34          <aop:aspect ref="myAdvice">
     35              <!--前置通知  -->
     36              <aop:before method="before" pointcut-ref="mypc" />
     37              <!--环绕通知  -->
     38              <aop:around method="around" pointcut-ref="mypc" />
     39              <!--最终通知 :出现异常也执行 -->
     40              <aop:after method="after" pointcut-ref="mypc" />
     41              <!--异常通知  -->
     42              <aop:after-throwing method="afterThrowing" pointcut-ref="mypc" />
     43              <!--后置通知:出现异常不执行  -->
     44              <aop:after-returning method="afterReturning" pointcut-ref="mypc" />
     45          </aop:aspect>
     46      </aop:config>
     47      </beans>
     48 

    6.测试
        
      1 package huguangqin.com.cnblogs.test;
      2      import javax.annotation.Resource;
      3      import org.junit.Test;
      4      import org.junit.runner.RunWith;
      5      import org.springframework.test.context.ContextConfiguration;
      6      import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
      7      import huguangqin.com.cnblogs.service.UserService;
      8 
      9     @RunWith(SpringJUnit4ClassRunner.class)
     10      @ContextConfiguration("classpath:applicationContext.xml")
     11      public class Demo {
     12          @Resource(name = "userService")
     13          private UserService us;
     14 
     15         @Test
     16          public void save() {
     17              us.save();
     18          }
     19      }
     20 

    四.案例演示:注解模式
         与xml模式相比,需修改applicationContext.xml和MyAdvice类
         1.applicationContext.xml
       

      1  <?xml version="1.0" encoding="UTF-8"?>
      2 
      3     <beans
      4      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      5      xmlns="http://www.springframework.org/schema/beans"
      6      xmlns:context="http://www.springframework.org/schema/context"
      7      xmlns:aop="http://www.springframework.org/schema/aop"
      8      xsi:schemaLocation="http://www.springframework.org/schema/beans
      9                          http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
     10                          http://www.springframework.org/schema/context
     11                          http://www.springframework.org/schema/context/spring-context-4.2.xsd
     12                          http://www.springframework.org/schema/aop
     13                          http://www.springframework.org/schema/aop/spring-aop-4.2.xsd ">
     14 
     15      <!--配置目标对象  -->
     16      <bean name="userService" class="huguangqin.com.cnblogs.service.serviceImpl.UserServiceImpl"></bean>
     17 
     18     <!--配置通知对象  -->
     19      <bean name="myAdvice" class="huguangqin.com.cnblogs.advice.MyAdvice"></bean>
     20 
     21     <!--将通知织入目标 ,打开注解配置开关 -->
     22      <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
     23      </beans>
     24 

        2.MyAdvice
       

      1  package huguangqin.com.cnblogs.advice;
      2 
      3     import org.aspectj.lang.ProceedingJoinPoint;
      4      import org.aspectj.lang.annotation.After;
      5      import org.aspectj.lang.annotation.AfterReturning;
      6      import org.aspectj.lang.annotation.AfterThrowing;
      7      import org.aspectj.lang.annotation.Around;
      8      import org.aspectj.lang.annotation.Aspect;
      9      import org.aspectj.lang.annotation.Before;
     10 
     11     //通知类
     12     @Aspect
     13      public class MyAdvice {
     14 
     15         // 前置
     16         @Before("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
     17          public void before() {
     18              System.out.println("我是前置通知!");
     19          }
     20 
     21         // 环绕通知
     22         /*
     23           * spring框架为我们提供了一个接口:ProceedingJoinPoint,它可以作为环绕通知的方法参数
     24          * 在环绕通知执行时,spring框架会为我们提供该接口的实现类对象,我们直接使用就行。
     25          * 该接口中有一个方法proceed(),此方法就相当于method.invoke()
     26           */
     27          @Around("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
     28          public Object around(ProceedingJoinPoint pjp) throws Throwable {
     29              System.out.println("我是环绕通知,前半部分!");
     30              // 执行目标方法
     31             Object proceed = pjp.proceed();
     32              System.out.println("我是环绕通知,后半部分!");
     33              return proceed;
     34          }
     35 
     36         // 后置 => 出现异常就不执行的后置通知
     37         @AfterReturning("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
     38          public void afterReturning() {
     39              System.out.println("我是后置通知,出现异常就不执行的后置通知!");
     40          }
     41 
     42         // 最终通知 => 无论是否出现异常都执行的后置通知
     43         @After("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
     44          public void after() {
     45              System.out.println("我是最终通知,出现异常仍然执行的后置通知!");
     46          }
     47 
     48         // 异常 => 出现异常才执行的通知
     49         @AfterThrowing("execution(* huguangqin.com.cnblogs.service.serviceImpl.*ServiceImpl.*(..))")
     50          public void afterThrowing() {
     51              System.out.println("我是异常通知,出现异常才执行的通知!");
     52          }
     53      }
     54 

    四.动态代理回顾
    1.原生动态代理--必需要一个接口,否则不能使用
    a.编写接口
       

      1  package huguangqin.com.cnblogs.serive;
      2 
      3     public interface Service {
      4          void find();
      5      }
      6 

    b.编写接口的实现类
       

      1  package huguangqin.com.cnblogs.seriveImpl;
      2 
      3     import huguangqin.com.cnblogs.serive.Service;
      4 
      5     public class ServiceImpl implements Service {
      6 
      7         @Override
      8          public void find() {
      9              System.out.println("找到了~~");
     10          }
     11 
     12     }
     13 

    c.创建该动态代理类
        

      1 package huguangqin.com.cnblogs.proxy;
      2 
      3     import java.lang.reflect.InvocationHandler;
      4     import java.lang.reflect.Method;
      5      import java.lang.reflect.Proxy;
      6 
      7     import huguangqin.com.cnblogs.serive.Service;
      8      import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
      9 
     10     public class MyProxy implements InvocationHandler {
     11 
     12         // 目标接口--我需要知道代理哪个接口
     13         private Service target;
     14 
     15         // 代理类的有参构造--利用给我的接口生成 这个接口代理类
     16         public MyProxy(Service target) {
     17              super();
     18              this.target = target;
     19          }
     20 
     21         // 获取代理对象--输出该接口的代理代象
     22         public Service getServiceProxy() {
     23              return (Service) Proxy.newProxyInstance(ServiceImpl.class.getClassLoader(), ServiceImpl.class.getInterfaces(),
     24                      this);
     25          }
     26 
     27         @Override
     28          public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
     29              System.out.println("start transaction");
     30              Object invoke = method.invoke(target, args);
     31             System.out.println("end transaction");
     32              return invoke;
     33          }
     34 
     35     }
     36 

    d.创建测试类
        

      1 package huguangqin.com.cnblogs.proxy;
      2 
      3     import org.junit.Test;
      4 
      5     import huguangqin.com.cnblogs.serive.Service;
      6      import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
      7 
      8     public class Demo {
      9 
     10         @Test
     11          public void demo() {
     12              // 被代理对象
     13             Service ser = new ServiceImpl();
     14              // 代理工厂
     15             MyProxy mp = new MyProxy(ser);
     16              // 获得代理类
     17             Service proxy = mp.getServiceProxy();
     18              proxy.find();
     19          }
     20      }
     21 


    2.CGLIB创建动态代理
    c.创建动态代理类
        

      1 package huguangqin.com.cnblogs.proxy;
      2 
      3     import java.lang.reflect.Method;
      4 
      5     import org.springframework.cglib.proxy.Enhancer;
      6      import org.springframework.cglib.proxy.MethodInterceptor;
      7      import org.springframework.cglib.proxy.MethodProxy;
      8 
      9     import huguangqin.com.cnblogs.serive.Service;
     10      import huguangqin.com.cnblogs.seriveImpl.ServiceImpl;
     11 
     12     //cglib
     13      public class MyProxy implements MethodInterceptor {
     14 
     15         public Service getMyProxy() {
     16              Enhancer en = new Enhancer();
     17              // 指定父类
     18             en.setSuperclass(ServiceImpl.class);
     19              // 设置需要增强的代码
     20             en.setCallback(this);
     21              // 创建代理对象
     22             return (Service) en.create();
     23 
     24         }
     25 
     26         @Override
     27          // proxy: 代理对象
     28         // arg1: 目标方法对象
     29         // arg2: 目标方法参数
     30         // methodProxy: 代理方法对象
     31         public Object intercept(Object proxy, Method arg1, Object[] arg2, MethodProxy methodProxy) throws Throwable {
     32              System.out.println("start");
     33             // 调用原业务方法
     34             Object invokeSuper = methodProxy.invokeSuper(proxy, arg2);
     35              System.out.println("end");
     36              return invokeSuper;
     37          }
     38 
     39     }
     40 

    d.测试类
       

      1  package huguangqin.com.cnblogs.test;
      2 
      3     import org.junit.Test;
      4 
      5     import huguangqin.com.cnblogs.proxy.MyProxy;
      6      import huguangqin.com.cnblogs.serive.Service;
      7 
      8     public class Demo {
      9 
     10         @Test
     11          public void demo() {
     12              // 代理工厂
     13             MyProxy mp = new MyProxy();
     14              // 获得代理类
     15             Service proxy = mp.getMyProxy();
     16              proxy.find();
     17          }
     18      }
     19 

  • 相关阅读:
    测试一下你的T-SQL基础知识-count
    测试一下你的T-SQL基础知识-subquery
    Microsoft SQL Server 2012 管理 (2): Auditing
    Webpack
    react
    Webpack 傻瓜式指南(一)
    谈谈react-router学习
    使用Flexible 实现手淘H5 页面的终端适配学习
    Promise 让异步更优
    基于LeanCloud云引擎的Web全栈方案
  • 原文地址:https://www.cnblogs.com/huguangqin/p/7488592.html
Copyright © 2011-2022 走看看