失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > AOP的底层实现-CGLIB动态代理和JDK动态代理

AOP的底层实现-CGLIB动态代理和JDK动态代理

时间:2021-04-19 03:32:57

相关推荐

AOP的底层实现-CGLIB动态代理和JDK动态代理

AOP是目前Spring框架中的核心之一,在应用中具有非常重要的作用,也是Spring其他组件的基础。它是一种面向切面编程的思想。关于AOP的基础知识,相信多数童鞋都已经了如指掌,我们就略过这部分,来讲解下AOP的核心功能的底层实现机制:如何用动态代理来实现切面拦截。AOP的拦截功能是由java中的动态代理来实现的。说白了,就是在目标类的基础上增加切面逻辑,生成增强的目标类(该切面逻辑或者在目标类函数执行之前,或者目标类函数执行之后,或者在目标类函数抛出异常时候执行。不同的切入时机对应不同的Interceptor的种类,如BeforeAdviseInterceptor,AfterAdviseInterceptor以及ThrowsAdviseInterceptor等)。那么动态代理是如何实现将切面逻辑(advise)织入到目标类方法中去的呢?下面我们就来详细介绍并实现AOP中用到的两种动态代理。AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。一、jdk动态代理实现AOP拦截(代码中的关键地方都添加了注释)

1、为目标类(target)定义统一的接口类Service,这个是jdk动态代理必须的前提。[java]view plaincopypackagejdkproxy;/***该类是所有被代理类的接口类,jdk实现的代理要求被代理类基于统一的接口**@authortyp**/publicinterfaceService{/***add方法*/publicvoidadd();/***update方法*/publicvoidupdate();}2、目标类AService,我们的实验目标就是在AService中add和update方法的前后实现拦截,加入自定义切面逻辑advise[java]view plaincopypackagejdkproxy;/***被代理类,即目标类target**@authortyp**/publicclassAServiceimplementsService{/**(non-Javadoc)**@seejdkproxy.Service#add()*/publicvoidadd(){System.out.println("AServiceadd>>>>>>>>>>>>>>>>>>");}/**(non-Javadoc)**@seejdkproxy.Service#update()*/publicvoidupdate(){System.out.println("AServiceupdate>>>>>>>>>>>>>>>");}}3、实现动态代理类MyInvocationHandler,实现InvocationHandler接口,并且实现接口中的invoke方法。仔细看invoke方法,就是在该方法中加入切面逻辑的。目标类方法的执行是由mehod.invoke(target,args)这条语句完成。[java]view plaincopypackagejdkproxy;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;/***@authortyp**/publicclassMyInvocationHandlerimplementsInvocationHandler{privateObjecttarget;MyInvocationHandler(){super();}MyInvocationHandler(Objecttarget){super();this.target=target;}publicObjectinvoke(Objectproxy,Methodmethod,Object[]args)throwsThrowable{//程序执行前加入逻辑,MethodBeforeAdviceInterceptorSystem.out.println("before-----------------------------");//程序执行Objectresult=method.invoke(target,args);//程序执行后加入逻辑,MethodAfterAdviceInterceptorSystem.out.println("after------------------------------");returnresult;}}4、测试类,其中增强的目标对象是由Proxy.newProxyInstance(aService.getClass().getClassLoader(), aService.getClass().getInterfaces(), handler);来生成的。[java]view plaincopypackagejdkproxy;importjava.lang.reflect.Proxy;/***@authortyp**/publicclassTest{publicstaticvoidmain(String[]args){ServiceaService=newAService();MyInvocationHandlerhandler=newMyInvocationHandler(aService);//Proxy为InvocationHandler实现类动态创建一个符合某一接口的代理实例ServiceaServiceProxy=(Service)Proxy.newProxyInstance(aService.getClass().getClassLoader(),aService.getClass().getInterfaces(),handler);//由动态生成的代理对象来aServiceProxy代理执行程序,其中aServiceProxy符合Service接口aServiceProxy.add();System.out.println();aServiceProxy.update();//以下是对B的代理//ServicebService=newBService();//MyInvocationHandlerhandler=newMyInvocationHandler(bService);//ServicebServiceProxy=(Service)Proxy.newProxyInstance(bService//.getClass().getClassLoader(),bService.getClass()//.getInterfaces(),handler);//bServiceProxy.add();//System.out.println();//bServiceProxy.update();}}自此,jdk动态代理来实现AOP拦截机制的代码已经实现,下面我们看一下拦截的结果,程序输出结果如下:before-----------------------------AServiceadd>>>>>>>>>>>>>>>>>>after------------------------------before-----------------------------AServiceupdate>>>>>>>>>>>>>>>after------------------------------

可以看到,在目标类AService的add和update方法前后已经加入了自定义的切面逻辑,AOP拦截机制生效了。

二、cglib动态代理实现AOP拦截(代码中的关键地方都添加了注释)

1、目标类,cglib不需要定义目标类的统一接口[java]view plaincopypackagecglibproxy;/***被代理类,即目标对象target**@authortyp**/publicclassBase{/***一个模拟的add方法*/publicvoidadd(){System.out.println("add------------");}}2、实现动态代理类CglibProxy,需要实现MethodInterceptor接口,实现intercept方法。该代理中在add方法前后加入了自定义的切面逻辑,目标类add方法执行语句为proxy.invokeSuper(object, args);

[java]view plaincopypackagecglibproxy;importjava.lang.reflect.Method;importnet.sf.cglib.proxy.MethodInterceptor;importnet.sf.cglib.proxy.MethodProxy;/***此为代理类,用于在pointcut处添加advise**@authortyp**/publicclassCglibProxyimplementsMethodInterceptor{publicObjectintercept(Objectobject,Methodmethod,Object[]args,MethodProxyproxy)throwsThrowable{//添加切面逻辑(advise),此处是在目标类代码执行之前,即为MethodBeforeAdviceInterceptor。System.out.println("before-------------");//执行目标类add方法proxy.invokeSuper(object,args);//添加切面逻辑(advise),此处是在目标类代码执行之后,即为MethodAfterAdviceInterceptor。System.out.println("after--------------");returnnull;}}3、获取增强的目标类的工厂Factory,其中增强的方法类对象是有Enhancer来实现的,代码如下所示:[java]view plaincopypackagecglibproxy;importnet.sf.cglib.proxy.Enhancer;/***工厂类,生成增强过的目标类(已加入切入逻辑)**@authortyp**/publicclassFactory{/***获得增强之后的目标类,即添加了切入逻辑advice之后的目标类**@paramproxy*@return*/publicstaticBasegetInstance(CglibProxyproxy){Enhancerenhancer=newEnhancer();enhancer.setSuperclass(Base.class);//回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法enhancer.setCallback(proxy);//此刻,base不是单纯的目标类,而是增强过的目标类Basebase=(Base)enhancer.create();returnbase;}}4、测试类

[java]view plaincopypackagecglibproxy;/***@authortyp**/publicclassTest{publicstaticvoidmain(String[]args){CglibProxyproxy=newCglibProxy();//base为生成的增强过的目标类Basebase=Factory.getInstance(proxy);base.add();}}自此,cglib动态代理实现的AOP拦截机制已经基本实现,下面我们来看一下拦截的效果如何,程序执行结果如下:

before-------------add------------after--------------可以看到,在目标类Base的add方法前后已经加入了自定义的切面逻辑,AOP拦截机制生效了。

此外,需要说明一下的是,cglib动态代理用到了第三方类库,需要在项目中引入两个jar包:cglib.jar和asm.jar。稍后会在csdn资源中上传这两个jar包。免积分的啊。jar包和相关代码请见/detail/dreamrealised/6427885

总之,AOP的核心机制和基本功能已经能够通过动态代理来实现了,至于AOP中,如何从配置文档中得到目标类target、advisor的bean,如何判断拦截器类型等问题,就借助于Spring中另一个核心IOC来解决了,后续会有IOC的核心实现机制讲解。

转载自/dreamrealised/article/details/12885739

如果觉得《AOP的底层实现-CGLIB动态代理和JDK动态代理》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。