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