spring--AOP

AOP:
概述:
面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
它的底层是采用动态代理的方式来实现的。
目标类如果是接口+实现类,spring采用的是jdk动态代理。--前提必须有接口。
目标类如果是只有实现类,spring采用的是cglib字节码增强。

aop术语:
1.target:   目标类,需要被增强的类。例如:UserService
2.Joinpoint:连接点,目标类上可能被增强的点。(目标类上的方法) 例如:addUser()、updateUser() ...
3.pointcut:  切入点,已经被增强的连接点(目标类的方法)。例如:addUser()
4.advice:    通知/增强 ,通知是指拦截到目标类的Joinpoint(可能被增强的方法)之后所要做的事情(外部的方法)
5.weaving:   织入,指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy:     代理对象
7.aspect:    切面,通知 和 切入点 结合(拦截目标类可能被增强的外部方法和目标类上已经被增强的方法)。

JDK动态代理:
生成动态代理:将通知与目标类进行整合到一个类中,生成一个代理类。
Proxy.netProxyInstance(loder,interfaces,h)
             工具类:Proxy.newProxyInstance ,此方法返回值Object
 *   loader 类加载器:把动态代理类加载到内存的。
  *    常用:当前类的类加载器 A.class.getClassLoader();
  *   Class[] interfaces 代理类需要实现所有接口。
  *    方法1:目标类.getClass().getInterfaces()
  *    方法2:new Class[]{目标类接口.class,...}
 *   InvocationHandler接口, 处理类,回调函数.
  *    代理类每一个方法执行时,都将调用处理类的invoke方法
  *     参数31:Object proxy , 代理类本身
  *     参数32:Method method,当前执行的方法描述对象
   *      执行目标方法:method.invoke(目标类,实际参数)
  *     参数33:Object[] args ,方法执行的实际参数
 主要代码: 
  UserService proxyService = (UserService)Proxy.newProxyInstance(
      MyFactory.class.getClassLoader(),
      new Class[]{UserService.class},
      new InvocationHandler(){

       @Override
       public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        //1 前通知
        myAspect.before();
        //2 目标方法  , 参考:userService.addUser();
        Object obj = method.invoke(userService, args);
        //3后通知
        myAspect.after();
        
        return obj;
       }});
  
  return proxyService;

CGLIB代理:
它是一个开源项目。它是强大的,高性能的,高质量的代码生成类库,它可以在运行期扩展实现类和接口。
字节码增强框架:cglib、javassist。
在使用cglib前需要导包:
一个核心包,一个依赖包:
位置:将spring-core-3.2.0.RELEASE.jar解压。里面的cglib和asm
cglib生成代理:
cglib 动态生成 目标类的子类,子类是一个代理类。 要求:目标类不能使final,与目标类的实例无关。
   核心类
  Enhancer(增强) enhancer = new Enhancer();
   确定父类
  enhancer.setSuperclass(UserServiceImpl.class);
   3.3 确定回调函数,类似jdk invocationHandler
     intercept()方法 等效 jdk invoke方法
      参数1:proxy,代理对象
      参数2:method,当前对象的方法
      参数3:args,方法的实际参数
      参数4:methodProxy,方法的代理
  enhancer.setCallback(new MethodInterceptor(){
   @Override
   public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {   
    //1 前通知
    myAspect.before();  
    //2目标方法
    Object obj = method.invoke(userService, args);    
    //3后通知
    myAspect.after();    
    return obj;
   }
  });
 创建代理类
  UserServiceImpl proxyService = (UserServiceImpl) enhancer.create();  
  return proxyService;

aop联盟通知类型:
? 通知类型最终是为了确定执行的方法方法名。
? AOP联盟规定5种通知类型:前置通知、后置通知、环绕通知、抛出异常通知、引介通知(不研究)
 前置通知 org.springframework.aop.MethodBeforeAdvice
  在目标方法执行前实施增强
 后置通知 org.springframework.aop.AfterReturningAdvice
  在目标方法执行后实施增强
 环绕通知 org.aopalliance.intercept.MethodInterceptor【】--必须手动执行目标方法
  在目标方法执行前后实施增强
 异常抛出通知 org.springframework.aop.ThrowsAdvice
  在方法抛出异常后实施增强
 引介通知 org.springframework.aop.IntroductionInterceptor
  在目标类中添加一些新的方法和属性

spring配置生成代理--半自动
从spring容器中获得代理类

导包:
spring对aop的实现:
spring-framework-3.2.0.RELEASE\libs-->spring-aop-3.2.0.RELEASE.jar
aop联盟包:
依赖包中:spring-framework-3.0.2dependencies\org.aopalliance\com.springsource.org.aopalliance\1.0.0-->com.springsource.org.aopalliance-1.0.0.jar

切面类:
切面类(存放通知advice ,需要aop联盟定义通知类型,使spring最终可以确定需要执行的方法名)
此类编写中要实现.MethodInterceptor【】--环绕通知必须手动执行目标方法:mi.proceed(),此方法返回一个Object类型。

配置文件创建代理对象:
主要是通过代理工厂bean来进行实现的。也就是将以前手动代理的创建代理部分由spring配置文件来进行实现。
 <!-- 1 创建目标类 -->
 <bean id="userServiceId" class="cn.itcast.b_factorybean.UserServiceImpl"></bean>
 <!-- 2 创建切面类(通知) -->
 <bean id="myAspectId" class="cn.itcast.b_factorybean.MyAspect"></bean>
 <!-- 3 创建代理
   ProxyFactoryBean 一个代理工厂bean,用于生成另一个bean,它生成的是代理bean。
  3.1 interfaces,确定接口
  3.2 target,确定目标类
  3.3 interceptorNames 确定通知
  3.4 optimize 强制使用cglib
  注意:在编写下面的属性及值时,通过注释来进行确定,以免值类型错误
 -->
 <bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean">
  <property name="interfaces" value="cn.itcast.b_factorybean.UserService"></property>
  <property name="target" ref="userServiceId"></property>
  <property name="interceptorNames" value="myAspectId"></property>
  <property name="optimize" value="true"></property>
 </bean>

 
springAOP全自动编程:
从spring容器获得目标类,通过spring aop编程进行配置,如果有配置获得其实是代理类。
将使用aspectj 表达式,用于确定切入点。
需要再依赖中导入aspectj的规范包(在此用到的是织入,所以导入的是织入包):
spring-framework-3.0.2dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE-->com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
目标类和切面类的编写和半自动的一样,主要差异在配置文件上:
配置:
 <!-- 1 创建目标类 -->
 <bean id="userServiceId" class="cn.itcast.c_aop.UserServiceImpl"></bean>
 <!-- 2 创建切面类(通知) -->
 <bean id="myAspectId" class="cn.itcast.c_aop.MyAspect"></bean>
 <!-- 3 aop编程
  <aop:config> 进行aop所有配置
  <aop:advisor>特殊的切面,只有一个切入点和一个通知
    advice-ref 通知引用(也就是切面类)
    pointcut-ref 切入点引用(目标类中的实现增强的方法,需要用到切入点的表达式来实现)
  <aop:pointcut> 声明切入点,用于描述出目标类
    id 切入点名称
    expression 切入点表达式
     execution(表达式语法)  表示可以匹配方法
      表达式语法:返回值  包.类.方法(参数)
       返回值:
        String 执行类型
        *  任意
       包
        cn.itcast     指定包
        cn.itcast..     当前包,以及子包
        cn.itcast.crm.*.service.. crm项目,*子模块,子模块下的service,以及子包。
       类
        UserService   指定类
        User*    User开头
        *Service   以Service结尾
        *     任意
       方法 ,与类相同的
       参数
        ()    无参
        (int)   一个参数
        (int,int)  两个参数
        (..)   任意参数
      综合:execution(* cn.itcast.crm.*.service..*.*(..))
        -->
 <aop:config>
  <aop:pointcut expression="execution(* cn.itcast.c_aop.*.*(..))" id="myPointcut"/>
  <aop:advisor advice-ref="myAspectId" pointcut-ref="myPointcut"/>
 </aop:config>

猜你喜欢

转载自jackpot1234.iteye.com/blog/2308771