当前位置: 代码迷 >> 综合 >> 聊聊aop和它的动态代理
  详细解决方案

聊聊aop和它的动态代理

热度:0   发布时间:2024-01-28 17:27:26.0

aop: 面向切面编程 

    以切?为基本单位的程序开发,通过切?间的彼此协同,相互调?,完成程序的构建 

PointCut(切入点)

    切入点:即确定添加额外功能的具体位置。

    我们一般通过切入点函数来实现对切入点的表示 ,切入点函数分为四种 :

*  execution:最强大的切入点函数 可以表示 :?法切?点表达式、 类切?点表达式 、包切?点表达常见用法   execution(* com.aptech.jb.epet.dao.hibimpl.*.*(..))   com.aptech.jb.epet.dao.hibimpl 包下所有的类的所有方法。。第一个*代表所有的返回值类型第二个*代表所有的类第三个*代表类所有方法 最后一个..代表所有的参数。
(大致了解即可  execution啥都能做)
*  args    : 主要?于函数(?法) 参数的匹配
*  within :  主要?于进?类、包切?点表达式的匹配
*  @annotation: 为具有特殊注解的?法加?额外功能

Advice (通知)  

常见的通知接口:

* MethodBeforeAdvice  前置通知   
* AfterReturningAdvice  后置通知
* ThrowsAdvice        异常通知
* Methodinterceptor   环绕通知  

如何理解切面  ?

   切面=切入点+额外功能 

   即  切面 =pointcut+ advice 

Spring如何配置切面?

    配置spring的切面存在可以通过  aspect 或者 adviser 来整合配置切面 

applicatioonContext.xml(adviser配置)

<!-- 注入通知类对象 -->
<bean id="before" class="domo07aop.server.Before"/>
<aop:config><aop:pointcut id="pc" expression="execution(* domo07aop.server.serverimpl.*(..))"/>     切入点<aop:advisor advice-ref="before" pointcut-ref="pc"/>     通知器  
</aop:config>

applicatioonContext.xml(aspect 配置)

<aop:config><aop:pointcut expression="execution(* *.sleep(..))" id="sleepPointcut"/><aop:aspect ref="sleepHelperAspect"><aop:before method="beforeSleep" pointcut-ref="sleepPointcut"/><aop:after method="afterSleep" pointcut-ref="sleepPointcut"/></aop:aspect>
</aop:config>

aspect 和adviser区别

<aop:advisor>大多用于事务管理。      
<aop:aspect>大多用于日志、缓存。
<aop:aspect>定义切面时,只需要定义一般的bean就行,而定义< aop:advisor>中引用的通知时,通知必须实现Advice接口。   

关于动态代理

    aop的底层实现 : aop是基于动态字节码技术和反射,通过动态代理实现了spring的aop功能

    动态代理分为 : JDK动态代理   cglib动态代理

AOP的动态代理   (代码实现)

    动态代理实现需要: 目标对象    (JDK动态代理实现需要相应的接口 ,cglib动态代理通过继承实现代理)

*目标对象的接口

package 动态代理;
/**
* 人的接口类  (程序员 )
* @author Administrator
*
*/
public interface Person {void say();void eat();void learn();void deBug();
}

*目标对象类

public class PersonImpl  implements Person{@Overridepublic void say() {System.out.println("你好,我是初级程序员,请多指教!");}@Overridepublic void eat() {// TODO Auto-generated method stubSystem.out.println("我有点不想吃饭了,减肥");}@Overridepublic void learn() {// TODO Auto-generated method stubSystem.out.println("奥里给  学无止境");}@Overridepublic void deBug() {// TODO Auto-generated method stubSystem.out.println("基操勿6");}
}

jdk动态代理:

(jdk代理基于接口实现,动态代理类对象通过方法创建)

package 动态代理;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;import org.junit.Test;/**
* 基于jdk的动态代理  
* @author Administrator
*
*/
public class JdkProxy {@Testpublic void testJdkProxy(){// 目标对象   (被代理对象 )  Person per=new PersonImpl();// 对代理类对象进行增强  通过内部类的方式 简化开发    invocation 类似 spring 中的环绕通知InvocationHandler invocation=new InvocationHandler(){@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(new Date());Object ret=method.invoke(per, args);return ret;}};// 代理类和被代理类实现了相同的接口 ,通过接口来接收代理类对象     // 类加载器的作用  : 1 : 把字节码文件加载到JVM虚拟机中  //    2:在虚拟机中,为字节码创建对象  // ClassLoader:动态代理通过动态字节码文件技术把 字节码文件直接//写入了JVM虚拟机,但是JVM中对象的创建仍然需要类加载器,所以在创//建动态代理对象时,我们需要传入一个类加载器帮助代理对象初始化// interfaces: 传入 被代理对象的接口  使代理对象和被代理对象实现相同的接口// invocationHandler: 对被代理对象的方法实现增强的方法  Person perproxy=(Person)Proxy.newProxyInstance(JdkProxy.class.getClassLoader(), per.getClass().getInterfaces(),invocation);per.eat();perproxy.eat();}}

cglib动态代理

(cglib实现动态代理基于继承,代理类继承被代理类 )(cglib如果不用spring手写实现 需要导入jar cglib-nodep-3.1.jar )

package 动态代理;
import java.lang.reflect.Method;
import org.junit.Test;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 基于  Cglib的动态代理
* @author Administrator
*
*/
public class CglibProxy {@Testpublic void test1(){Person per=new PersonImpl();Enhancer enhance=new Enhancer();//  内部类  MethodInterceptor methodinter=new  MethodInterceptor(){@Overridepublic Object intercept(Object  arg0, Method arg1, Object[] arg2, MethodProxy  arg3)throws Throwable {System.out.println("还活着   Log.......");Object ret=arg1.invoke(per,  arg2);return ret;}};//类加载器  classLoader enhance.setClassLoader(CglibProxy.class.getClassLoader());//  被修饰类的字节码 (jdk传的是接口)enhance.setSuperclass(per.getClass());// 增强的方法enhance.setCallback(methodinter);PersonImpl  perProxy=(PersonImpl)enhance.create();perProxy.eat();}}

JDK 动态代理 和 cglib 动态代理 的异同

1: JDK通过Proxy.newInstance(classLoader,interfaces,InvocationHandler) 实现生产代理对象; 而 cglib通过 net.sf.cglib.proxy.Enhancer.create() 创建代理对象,在创建代理对象前,也需要设置
enhance.setClassLoader(), enhance.setSuperclass(),enhance.setCallback()方法设置属性;  两个方法除了一个传的是接口,一个传的是类的字节码,别的没有很多差别。2: Proxy.newProxyInstance() 通过接?创建代理的实现类; Cglib动态代理 Enhancer通过继承?类创建的代理类

 

  相关解决方案