spring中AOP动态代理的两种方式
AOP動(dòng)態(tài)代理的兩種方式
Spring AOP動(dòng)態(tài)代理的方式(spring的AOP默認(rèn)是JDK Proxy)
淺談這兩種動(dòng)態(tài)代理
JDK的動(dòng)態(tài)代理,需要有實(shí)現(xiàn)接口
動(dòng)態(tài)代理——JDK Proxy
? JDKProxy動(dòng)態(tài)代理是針對(duì)對(duì)象做代理,要求原始對(duì)象具有接口實(shí)現(xiàn),并對(duì)接口方法進(jìn)行增強(qiáng)
在aop動(dòng)態(tài)代理的時(shí)候發(fā)現(xiàn)這個(gè)類(lèi)是實(shí)現(xiàn)接口的類(lèi),就選擇JDK的動(dòng)態(tài)代理,從ioc中獲取這個(gè)動(dòng)態(tài)代理的實(shí)現(xiàn)類(lèi)就需要按照接口.class去獲取
CGLIB動(dòng)態(tài)代理方式,繼承方式
動(dòng)態(tài)代理——CGLIB
? CGLIB(Code Generation Library),Code生成類(lèi)庫(kù)
? CGLIB動(dòng)態(tài)代理不限定是否具有接口,可以對(duì)任意操作進(jìn)行增強(qiáng)
? CGLIB動(dòng)態(tài)代理無(wú)需要原始被代理對(duì)象,動(dòng)態(tài)創(chuàng)建出新的代理對(duì)象
spring需要在配置文件中開(kāi)啟CGLIB方式
就選擇CGLIB動(dòng)態(tài)代理方式,繼承方式,就直接用這個(gè)類(lèi).class去獲取,因?yàn)楦割?lèi)接收子類(lèi)沒(méi)問(wèn)題
CGLIB和Java動(dòng)態(tài)代理的區(qū)別
Java動(dòng)態(tài)代理只能夠?qū)涌谶M(jìn)行代理,不能對(duì)普通的類(lèi)進(jìn)行代理(因?yàn)樗猩傻拇眍?lèi)的父類(lèi)為Proxy,Java類(lèi)繼承機(jī)制不允許多重繼承);CGLIB能夠代理普通類(lèi);
Java動(dòng)態(tài)代理使用Java原生的反射API進(jìn)行操作,在生成類(lèi)上比較高效;CGLIB使用ASM框架直接對(duì)字節(jié)碼進(jìn)行操作,在類(lèi)的執(zhí)行過(guò)程中比較高效
————————————————
模擬AOP動(dòng)態(tài)代理
接口與實(shí)現(xiàn)類(lèi)
業(yè)務(wù)層接口
package com.fs.service;public interface AopService {void findAll(); }業(yè)務(wù)層實(shí)現(xiàn)類(lèi)
public class AopServiceImpl implements AopService {@Overridepublic void findAll() {System.out.println("業(yè)務(wù)層執(zhí)行了findAll~~~");} }模擬:動(dòng)態(tài)代理——JDK Proxy JDK的動(dòng)態(tài)代理,需要有實(shí)現(xiàn)接口
動(dòng)態(tài)代理生成類(lèi)
package com.fs.proxy;import com.fs.service.AopService;import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy;/* 動(dòng)態(tài)代理——JDK ProxyProxy類(lèi)中的靜態(tài)方法:可以生產(chǎn)代理人對(duì)象static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)返回一個(gè)指定接口的代理類(lèi)實(shí)例,該接口可以將方法調(diào)用指派到指定的調(diào)用處理程序。參數(shù):ClassLoader loader:傳遞類(lèi)加載器Class<?>[] interfaces:傳遞被代理人實(shí)現(xiàn)的所有接口InvocationHandler h:生產(chǎn)代理人的接口,傳遞InvocationHandler接口的實(shí)現(xiàn)類(lèi)對(duì)象public Object invoke(Object proxy, Method method, Object[] args)proxy:代表的是內(nèi)部產(chǎn)生的代理對(duì)象method:被攔截到的方法,invoke方法會(huì)對(duì)實(shí)現(xiàn)類(lèi)方法進(jìn)行攔截,使用反射技術(shù)后去獲取這些個(gè)方法args:被攔截到方法的參數(shù),如果沒(méi)有,就是null*/ public class JDKProxyDemo {/*動(dòng)態(tài)代理AopService,對(duì)其findAll()方法進(jìn)行增強(qiáng)*/public static AopService getProxy(AopService aopService){//使用Jdk的Proxy動(dòng)態(tài)代理AopServiceAopService service = (AopService) Proxy.newProxyInstance(aopService.getClass().getClassLoader(), aopService.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//被代理類(lèi)無(wú)論什么方法,都會(huì)進(jìn)這個(gè)invoke方法進(jìn)行調(diào)用//我們對(duì)findAll()進(jìn)行增強(qiáng),就先判斷一下Object o = null;if (method.getName().equals("findAll")){//在方法調(diào)用前,對(duì)方法進(jìn)行增強(qiáng)System.out.println("我在原始方法調(diào)用前,增強(qiáng)了方法~~~");//是這個(gè)方法,就調(diào)用 第一個(gè)參數(shù)為被代理的對(duì)象,第二個(gè)參數(shù)為調(diào)用方法需要的參數(shù)o = method.invoke(aopService, args);System.out.println("我在原始方法調(diào)用后,增強(qiáng)了方法~~~");}else {//如果不是findAll.就不增強(qiáng)o = method.invoke(aopService, args);}return o;}});return service;} }測(cè)試方法
//測(cè)試JDKProxyDemo@Testpublic void testDemo(){//創(chuàng)建需要被代理的對(duì)象AopServiceImpl aopService = new AopServiceImpl();//使用自己寫(xiě)的生成代理對(duì)象的類(lèi)的方法得到動(dòng)態(tài)代理的對(duì)象AopService proxy = JDKProxyDemo.getProxy(aopService);//調(diào)用動(dòng)態(tài)代理生成的對(duì)象的方法proxy.findAll();}執(zhí)行結(jié)果
模擬:CGLIB動(dòng)態(tài)代理方式,繼承方式
動(dòng)態(tài)代理生成類(lèi)
package com.fs.cglib;import com.fs.service.AopService; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/* CGLIB實(shí)現(xiàn)對(duì)類(lèi)進(jìn)行動(dòng)態(tài)代理, 動(dòng)態(tài)代理——CGLIB ? CGLIB(Code Generation Library),Code生成類(lèi)庫(kù) ? CGLIB動(dòng)態(tài)代理不限定是否具有接口,可以對(duì)任意操作進(jìn)行增強(qiáng) ? CGLIB動(dòng)態(tài)代理無(wú)需要原始被代理對(duì)象,動(dòng)態(tài)創(chuàng)建出新的代理對(duì)象intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) MethodProxy methodProxy 這個(gè)代表所有父類(lèi)的方法,所以我們使用這個(gè) Object[] objects 這個(gè)就是ages 傳遞調(diào)用方法傳遞的參數(shù)*/ public class CGLIBProxy {//對(duì) AopService的findAll();進(jìn)行增強(qiáng)public static AopService getProxy(Class clazz){//創(chuàng)建Enhancer對(duì)象(可以理解為內(nèi)存中動(dòng)態(tài)創(chuàng)建了一個(gè)類(lèi)的字節(jié)碼)Enhancer enhancer = new Enhancer();//設(shè)置Enhancer對(duì)象的父類(lèi)是指定類(lèi)型AopServerImplenhancer.setSuperclass(clazz);//設(shè)置回掉方法enhancer.setCallback(new MethodInterceptor() {@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {if (method.getName().equals("findAll")){System.out.println("我對(duì)findAll方法執(zhí)行前進(jìn)行了增強(qiáng)");}//通過(guò)調(diào)用父類(lèi)的方法實(shí)現(xiàn)對(duì)原始方法的調(diào)用Object ret = methodProxy.invokeSuper(o, objects);// //后置增強(qiáng)內(nèi)容,與JDKProxy區(qū)別:JDKProxy僅對(duì)接口方法做增強(qiáng),cglib對(duì)所有方法做增強(qiáng),包括Object類(lèi)中的方法if (method.getName().equals("findAll")){System.out.println("我對(duì)findAll方法執(zhí)行后進(jìn)行了增強(qiáng)");}return ret;}});//使用Enhancer對(duì)象創(chuàng)建對(duì)應(yīng)的對(duì)象AopService aopService = (AopService) enhancer.create();return aopService;} }測(cè)試方法
//測(cè)試CGLIBProxy@Testpublic void testDemo02(){//創(chuàng)建需要被代理的對(duì)象,傳遞實(shí)現(xiàn)類(lèi)的class文件AopService proxy = CGLIBProxy.getProxy(AopServiceImpl.class);proxy.findAll();}執(zhí)行結(jié)果
關(guān)于匿名內(nèi)部類(lèi)中 外部的變量或方法參數(shù)沒(méi)有 final解釋
Java開(kāi)發(fā)者們,如果你們想要在匿名內(nèi)部類(lèi)里面使用外部的局部變量或方法參數(shù),那抱歉受限于語(yǔ)言設(shè)計(jì),這個(gè)外部的變量只能聲明為final的了。
當(dāng)然在JDK 1.8及以后,看起來(lái)似乎編譯器取消了這種限制,沒(méi)有被聲明為final的變量或參數(shù)也可以在匿名內(nèi)部類(lèi)內(nèi)部被訪問(wèn)了。但實(shí)際上是因?yàn)镴ava 8引入了effectively final的概念(A variable or parameter whose value is never changed after it is initialized is effectively final)。所以,實(shí)際上是諸如effectively final的變量或參數(shù)被Java默認(rèn)為final類(lèi)型,所以才不會(huì)報(bào)錯(cuò)(最簡(jiǎn)單的測(cè)試方式:將上述代碼integer變量取消final修飾(effectively final),試一下,在下面對(duì)其重新賦值(not effectively final),再試一下),而上述的根本原因沒(méi)有任何變化。
超強(qiáng)干貨來(lái)襲 云風(fēng)專(zhuān)訪:近40年碼齡,通宵達(dá)旦的技術(shù)人生總結(jié)
以上是生活随笔為你收集整理的spring中AOP动态代理的两种方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: spring的AOP配置之@注解方式
- 下一篇: java模拟单链表环形链表解决约瑟夫问题