日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java静态代理、动态代理与CGLib代理

發(fā)布時間:2025/3/15 java 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java静态代理、动态代理与CGLib代理 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

java的動態(tài)代理舉足輕重,它同反射原理一直是許多框架的底層實現(xiàn)。今天嘮一下。

一、代理模式

代理模式是一種設(shè)計模式,提供了對目標(biāo)對象額外的訪問方式,即通過代理對象訪問目標(biāo)對象,這樣可以在不修改原目標(biāo)對象的前提下,提供額外的功能操作,擴(kuò)展目標(biāo)對象的功能。簡言之,代理模式就是設(shè)置一個中間代理來控制訪問原目標(biāo)對象,以達(dá)到增強(qiáng)原對象的功能和簡化訪問方式。代理分靜態(tài)代理和動態(tài)代理兩種。
示意圖:

二、靜態(tài)代理

我們平常去電影院看電影的時候,在電影開始的階段是不是經(jīng)常會放廣告呢?
電影是電影公司委托給影院進(jìn)行播放的,但是影院可以在播放電影的時候,產(chǎn)生一些自己的經(jīng)濟(jì)收益,比如賣爆米花、可樂等,然后在影片開始結(jié)束時播放一些廣告。
現(xiàn)在用代碼來進(jìn)行模擬。
首先得有一個接口,通用的接口是代理模式實現(xiàn)的基礎(chǔ)。這個接口我們命名為 Movie,代表電影播放的能力。

public interface Movie {void play();}

然后,我們要有一個真正的實現(xiàn)這個 Movie 接口的類,和一個只是實現(xiàn)接口的代理類。

public class RealMovie implements Movie { @Overridepublic void play() {// TODO Auto-generated method stubSystem.out.println("您正在觀看電影 《肖申克的救贖》");} }

這個表示真正的影片。它實現(xiàn)了 Movie 接口,play() 方法調(diào)用時,影片就開始播放。那么 Proxy 代理呢?

public class Cinema implements Movie { RealMovie movie;public Cinema(RealMovie movie) {super();this.movie = movie;}@Overridepublic void play() {guanggao(true); movie.play(); guanggao(false);} public void guanggao(boolean isStart){if ( isStart ) {System.out.println("電影馬上開始了,爆米花、可樂、口香糖9.8折,快來買啊!");} else {System.out.println("電影馬上結(jié)束了,爆米花、可樂、口香糖9.8折,買回家吃吧!");}} }

Cinema 就是 Proxy 代理對象,它有一個 play() 方法。不過調(diào)用 play() 方法時,它進(jìn)行了一些相關(guān)利益的處理,那就是廣告。現(xiàn)在,我們編寫測試代碼。

public class ProxyTest {public static void main(String[] args) {RealMovie realmovie = new RealMovie();Movie movie = new Cinema(realmovie);movie.play();} }

然后觀察結(jié)果:

電影馬上開始了,爆米花、可樂、口香糖9.8折,快來買啊! 您正在觀看電影 《肖申克的救贖》 電影馬上結(jié)束了,爆米花、可樂、口香糖9.8折,買回家吃

現(xiàn)在可以看到,代理模式可以在不修改被代理對象的基礎(chǔ)上,通過擴(kuò)展代理類,進(jìn)行一些功能的附加與增強(qiáng)。值得注意的是,代理類和被代理類應(yīng)該共同實現(xiàn)一個接口,或者是共同繼承某個類。
上面介紹的是靜態(tài)代理的內(nèi)容,為什么叫做靜態(tài)呢?
因為它的類型是事先預(yù)定好的,比如上面代碼中的 Cinema 這個類。

三、動態(tài)代理所涉及的一些接口、類及方法

java動態(tài)代理的主要類和接口有:
java.lang.reflect.Proxy,java.lang.reflect.InvocationHandler

  • java.lang.reflect.Proxy:動態(tài)代理機(jī)制的主類,提供一組靜態(tài)方法為一組接口動態(tài)的生成對象和代理類。其包含以下重要方法:
  • 1、public static InvocationHandler getInvocationHandler(Object var0) 該方法用于獲取指定代理對象所關(guān)聯(lián)的調(diào)用處理器
    2、public static Class<?> getProxyClass(ClassLoader var0, Class… var1) 該方法用于獲取關(guān)聯(lián)于指定類裝載器和一組接口的動態(tài)代理類的類對象
    3、public static Object newProxyInstance(ClassLoader var0, Class<?>[]var1, InvocationHandler var2) 方法用于為指定類裝載器,一組接口及調(diào)用處理器生成動態(tài)代理類實例

  • java.lang.reflect.InvocationHandler:調(diào)用處理器接口,自定義invoke方法,用于實現(xiàn)對于真正委托類的代理訪問
  • public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

  • java.lang.ClassLoader:類裝載器類
  • 將類的字節(jié)碼裝載到 Java 虛擬機(jī)(JVM)中并為其定義類對象,然后該類才能被使用。Proxy類與普通類的唯一區(qū)別就是其字節(jié)碼是由 JVM 在運行時動態(tài)生成的而非預(yù)存在于任何一個 .class 文件中。

    四、動態(tài)代理例子(基于反射技術(shù)實現(xiàn)的)

    1.方法接口

    public interface SayGoodbye {void sayGoodbye(String name); } public interface SayHello {void sayHello(String name); }

    2.接口實現(xiàn)

    public class goodByeImpl implements SayGoodbye {@Overridepublic void sayGoodbye(String name) {System.out.println("GoodBye"+name);} } public class HelloImpl implements SayHello{@Overridepublic void sayHello(String name) {System.out.println("Hello"+name);} }

    3.代理實例類

    public class ServiceProxy implements InvocationHandler {private Object target;public void InvokeBefore(){System.out.println("調(diào)用前");}public void InvokeAfter(){System.out.println("調(diào)用后");}public Object getInstance(Object target) {this.target = target;//target.getClass().getClassLoader() 類加載器,動態(tài)代理的類加載器必然和被代理的對象在同一個加載器,所以直接使用//target.getClass().getInterfaces() 實現(xiàn)的接口//this 該方法只負(fù)責(zé)實例化代理,至于代理業(yè)務(wù)的流程規(guī)范,由InvocationHandler(this)來定義return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);}@Override//Object proxy代理類//Method method要攔截(優(yōu)化)的方法//Object[] args方法的參數(shù)public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {Object result;//反射方法前調(diào)用InvokeBefore();//反射執(zhí)行方法 相當(dāng)于調(diào)用target.sayHelllo;result = method.invoke(target,args);//反射方法后調(diào)用.InvokeAfter();return result;} }

    4.測試類

    public class ProxyTest {public static void main(String[] args) {//生成proxy類ServiceProxy proxy = new ServiceProxy();//獲取SayGoodbye代理對象,此處需要傳入goodByeImpl實例給getInstance方法,最終被newProxyInstance調(diào)用SayGoodbye sgServiceProxy = (SayGoodbye) proxy.getInstance(new goodByeImpl());//通過代理對象調(diào)用方法sgServiceProxy.sayGoodbye(" lisi");//獲取SayHello代理對象SayHello shServiceProxy=(SayHello)proxy.getInstance(new HelloImpl());//調(diào)用對象方法shServiceProxy.sayHello(" zhangsan");} }

    5.運行結(jié)果

    調(diào)用前 GoodBye lisi 調(diào)用后 調(diào)用前 Hello zhangsan 調(diào)用后

    總結(jié):動態(tài)代理如果需求改變,只需修改接口方法以及實現(xiàn)類,而無需修改代理的實例,實現(xiàn)了解耦。

    五、動態(tài)代理源碼解析

    1.Proxy類的靜態(tài)方法newProxyInstance方法

    public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException{//驗證傳入的InvocationHandler是否為空Objects.requireNonNull(h);//克隆代理類實現(xiàn)的接口final Class<?>[] intfs = interfaces.clone();//獲得安全管理器final SecurityManager sm = System.getSecurityManager();//檢查創(chuàng)建代理類所需的權(quán)限if (sm != null) {checkProxyAccess(Reflection.getCallerClass(), loader, intfs);}/** Look up or generate the designated proxy class.* 查找或者生成特定的代理類(如果緩存中存在,則直接獲取)*/Class<?> cl = getProxyClass0(loader, intfs);/** Invoke its constructor with the designated invocation handler.*/try {//權(quán)限校驗if (sm != null) {checkNewProxyPermission(Reflection.getCallerClass(), cl);}//獲取參數(shù)類型是InvocationHandler.class的代理類構(gòu)造器final Constructor<?> cons = cl.getConstructor(constructorParams);final InvocationHandler ih = h;//如果代理類是不可訪問的, 就使用特權(quán)將它的構(gòu)造器設(shè)置為可訪問if (!Modifier.isPublic(cl.getModifiers())) {AccessController.doPrivileged(new PrivilegedAction<Void>() {public Void run() {cons.setAccessible(true);return null;}});}//傳入InvocationHandler實例去構(gòu)造一個代理類的實例,所有代理類都繼承自Proxy,而Proxy構(gòu)造方法需要InvocationHandler實例作為參數(shù)return cons.newInstance(new Object[]{h});} catch (IllegalAccessException|InstantiationException e) {throw new InternalError(e.toString(), e);} catch (InvocationTargetException e) {Throwable t = e.getCause();if (t instanceof RuntimeException) {throw (RuntimeException) t;} else {throw new InternalError(t.toString(), t);}} catch (NoSuchMethodException e) {throw new InternalError(e.toString(), e);}}

    從newProxyInstance方法看出,產(chǎn)生代理類核心代碼在getProxyClass0

    2.Proxy類的靜態(tài)方法getProxyClass0方法

    private static Class<?> getProxyClass0(ClassLoader loader,Class<?>... interfaces) {if (interfaces.length > 65535) {throw new IllegalArgumentException("interface limit exceeded");}//如果由實現(xiàn)給定接口的代理類存在,這將簡單地返回緩存的副本;否則,將通過ProxyClassFactory創(chuàng)建代理類return proxyClassCache.get(loader, interfaces);}

    getProxyClass0通過類加載器和接口集合去緩存里面獲取,如果能找到代理類就直接返回,否則就會調(diào)用ProxyClassFactory這個工廠去生成一個代理類,下面我們看下Proxy的靜態(tài)內(nèi)部類ProxyClassFactory

    3.ProxyClassFactory

    1 private static final class ProxyClassFactory2 implements BiFunction<ClassLoader, Class<?>[], Class<?>>3 {4 // prefix for all proxy class names 代理類名稱前綴5 private static final String proxyClassNamePrefix = "$Proxy";6 7 // next number to use for generation of unique proxy class names, 用原子類來生成代理類的序號, 保證序號唯一8 private static final AtomicLong nextUniqueNumber = new AtomicLong();9 10 @Override11 public Class<?> apply(ClassLoader loader, Class<?>[] interfaces) {12 13 Map<Class<?>, Boolean> interfaceSet = new IdentityHashMap<>(interfaces.length);14 for (Class<?> intf : interfaces) {15 /*16 * Verify that the class loader resolves the name of this17 * interface to the same Class object.18 */19 Class<?> interfaceClass = null;20 try {21 interfaceClass = Class.forName(intf.getName(), false, loader);22 } catch (ClassNotFoundException e) {23 }24 //intf是否可以由指定的類加載進(jìn)行加載25 if (interfaceClass != intf) {26 throw new IllegalArgumentException(27 intf + " is not visible from class loader");28 }29 /*30 * Verify that the Class object actually represents an31 * interface.32 * intf是否是一個接口33 */34 if (!interfaceClass.isInterface()) {35 throw new IllegalArgumentException(36 interfaceClass.getName() + " is not an interface");37 }38 /*39 * Verify that this interface is not a duplicate.40 * intf在數(shù)組中是否有重復(fù)41 */42 if (interfaceSet.put(interfaceClass, Boolean.TRUE) != null) {43 throw new IllegalArgumentException(44 "repeated interface: " + interfaceClass.getName());45 }46 }47 // package to define proxy class in 生成代理類的包名48 String proxyPkg = null;49 // 代理類的訪問標(biāo)志, 默認(rèn)是public final50 int accessFlags = Modifier.PUBLIC | Modifier.FINAL;51 52 /*53 * Record the package of a non-public proxy interface so that the54 * proxy class will be defined in the same package. Verify that55 * all non-public proxy interfaces are in the same package.56 * 驗證所有非公共代理接口都在同一個包中57 */58 for (Class<?> intf : interfaces) {59 //獲取接口的訪問標(biāo)志60 int flags = intf.getModifiers();61 //如果接口的訪問標(biāo)志不是public, 那么生成代理類的包名和接口包名相同62 if (!Modifier.isPublic(flags)) {63 //生成的代理類的訪問標(biāo)志設(shè)置改為final64 accessFlags = Modifier.FINAL;65 String name = intf.getName();66 int n = name.lastIndexOf('.');67 String pkg = ((n == -1) ? "" : name.substring(0, n + 1));68 if (proxyPkg == null) {69 proxyPkg = pkg;70 } else if (!pkg.equals(proxyPkg)) {71 //代理類如果實現(xiàn)不同包的接口, 并且接口都不是public的, 那么就會在這里報錯72 throw new IllegalArgumentException(73 "non-public interfaces from different packages");74 }75 }76 }77 78 if (proxyPkg == null) {79 // if no non-public proxy interfaces, use com.sun.proxy package 如果沒有非公共代理接口,那生成的代理類都放到默認(rèn)的包下:com.sun.proxy80 proxyPkg = ReflectUtil.PROXY_PACKAGE + ".";81 }82 83 /*84 * Choose a name for the proxy class to generate.85 * 生成代理類的全限定名, 包名+前綴+序號, 例如:com.sun.proxy.$Proxy086 */87 long num = nextUniqueNumber.getAndIncrement();88 String proxyName = proxyPkg + proxyClassNamePrefix + num;89 90 /*91 * Generate the specified proxy class.92 * 這里是核心, 用ProxyGenerator來生成字節(jié)碼, 該類放在sun.misc包下93 */94 byte[] proxyClassFile = ProxyGenerator.generateProxyClass(95 proxyName, interfaces, accessFlags);96 //根據(jù)二進(jìn)制文件生成相應(yīng)的Class實例97 try {98 return defineClass0(loader, proxyName,99 proxyClassFile, 0, proxyClassFile.length); 100 } catch (ClassFormatError e) { 101 /* 102 * A ClassFormatError here means that (barring bugs in the 103 * proxy class generation code) there was some other 104 * invalid aspect of the arguments supplied to the proxy 105 * class creation (such as virtual machine limitations 106 * exceeded). 107 */ 108 throw new IllegalArgumentException(e.toString()); 109 } 110 } 111 }

    大boss終于出現(xiàn)了,下面我們分ProxyGenerator.generateClassFile
    5.ProxyGenerator.generateClassFile

    1 private byte[] generateClassFile() {2 //1、將所有的方法組裝成ProxyMethod對象3 //首先為代理類生成toString, hashCode, equals等代理方法4 this.addProxyMethod(hashCodeMethod, Object.class);5 this.addProxyMethod(equalsMethod, Object.class);6 this.addProxyMethod(toStringMethod, Object.class);7 Class[] var1 = this.interfaces;8 int var2 = var1.length;9 10 int var3;11 Class var4;12 //遍歷每一個接口的每一個方法, 并生成ProxyMethod對象13 for(var3 = 0; var3 < var2; ++var3) {14 var4 = var1[var3];15 Method[] var5 = var4.getMethods();16 int var6 = var5.length;17 18 for(int var7 = 0; var7 < var6; ++var7) {19 Method var8 = var5[var7];20 this.addProxyMethod(var8, var4);21 }22 }23 24 Iterator var11 = this.proxyMethods.values().iterator();25 26 List var12;27 while(var11.hasNext()) {28 var12 = (List)var11.next();29 checkReturnTypes(var12);30 }31 32 //2、組裝要生成的class文件的所有的字段信息和方法信息33 Iterator var15;34 try {35 //添加構(gòu)造器方法36 this.methods.add(this.generateConstructor());37 var11 = this.proxyMethods.values().iterator();38 39 //遍歷緩存中的代理方法40 while(var11.hasNext()) {41 var12 = (List)var11.next();42 var15 = var12.iterator();43 44 while(var15.hasNext()) {45 ProxyGenerator.ProxyMethod var16 = (ProxyGenerator.ProxyMethod)var15.next();46 //添加代理類的靜態(tài)字段, 例如:private static Method m1;47 this.fields.add(new ProxyGenerator.FieldInfo(var16.methodFieldName, "Ljava/lang/reflect/Method;", 10));48 //添加代理類的代理方法49 this.methods.add(var16.generateMethod());50 }51 }52 53 //添加代理類的靜態(tài)字段初始化方法54 this.methods.add(this.generateStaticInitializer());55 } catch (IOException var10) {56 throw new InternalError("unexpected I/O Exception", var10);57 }58 59 if(this.methods.size() > '\uffff') {60 throw new IllegalArgumentException("method limit exceeded");61 } else if(this.fields.size() > '\uffff') {62 throw new IllegalArgumentException("field limit exceeded");63 } else {64 //3、寫入最終的class文件65 //驗證常量池中存在代理類的全限定名66 this.cp.getClass(dotToSlash(this.className));67 //驗證常量池中存在代理類父類的全限定名68 this.cp.getClass("java/lang/reflect/Proxy");69 var1 = this.interfaces;70 var2 = var1.length;71 72 //驗證常量池存在代理類接口的全限定名73 for(var3 = 0; var3 < var2; ++var3) {74 var4 = var1[var3];75 this.cp.getClass(dotToSlash(var4.getName()));76 }77 78 //接下來要開始寫入文件了,設(shè)置常量池只讀79 this.cp.setReadOnly();80 ByteArrayOutputStream var13 = new ByteArrayOutputStream();81 DataOutputStream var14 = new DataOutputStream(var13);82 83 try {84 //1.寫入魔數(shù)85 var14.writeInt(-889275714);86 //2.寫入次版本號87 var14.writeShort(0);88 //3.寫入主版本號89 var14.writeShort(49);90 //4.寫入常量池91 this.cp.write(var14);92 //5.寫入訪問修飾符93 var14.writeShort(this.accessFlags);94 //6.寫入類索引95 var14.writeShort(this.cp.getClass(dotToSlash(this.className)));96 //7.寫入父類索引, 生成的代理類都繼承自Proxy97 var14.writeShort(this.cp.getClass("java/lang/reflect/Proxy"));98 //8.寫入接口計數(shù)值99 var14.writeShort(this.interfaces.length); 100 101 Class[] var17 = this.interfaces; 102 int var18 = var17.length; 103 104 //9.寫入接口集合 105 for(int var19 = 0; var19 < var18; ++var19) { 106 Class var22 = var17[var19]; 107 var14.writeShort(this.cp.getClass(dotToSlash(var22.getName()))); 108 } 109 //10.寫入字段計數(shù)值 110 var14.writeShort(this.fields.size()); 111 var15 = this.fields.iterator(); 112 //11.寫入字段集合 113 while(var15.hasNext()) { 114 ProxyGenerator.FieldInfo var20 = (ProxyGenerator.FieldInfo)var15.next(); 115 var20.write(var14); 116 } 117 //12.寫入方法計數(shù)值 118 var14.writeShort(this.methods.size()); 119 var15 = this.methods.iterator(); 120 //13.寫入方法集合 121 while(var15.hasNext()) { 122 ProxyGenerator.MethodInfo var21 = (ProxyGenerator.MethodInfo)var15.next(); 123 var21.write(var14); 124 } 125 //14.寫入屬性計數(shù)值, 代理類class文件沒有屬性所以為0 126 var14.writeShort(0); 127 //轉(zhuǎn)換成二進(jìn)制數(shù)組輸出 128 return var13.toByteArray(); 129 } catch (IOException var9) { 130 throw new InternalError("unexpected I/O Exception", var9); 131 } 132 } 133 }

    動態(tài)代理的本質(zhì):通過類加載器獲取類字節(jié)碼,通過類實現(xiàn)的接口反射獲得該類的屬性,方法等,并生成新的字節(jié)碼文件

    6.代理類字節(jié)碼文件分析 $Proxy0.class

    1 package com.sun.proxy;2 3 import com.doubibi.framework.util.proxy.HelloService;4 import java.lang.reflect.InvocationHandler;5 import java.lang.reflect.Method;6 import java.lang.reflect.Proxy;7 import java.lang.reflect.UndeclaredThrowableException;8 9 public final class $Proxy0 extends Proxy10 implements HelloService11 {12 //equals方法13 private static Method m1;14 //HelloService 的sayHello方法15 private static Method m3;16 //toString方法17 private static Method m2;18 //hashCode方法19 private static Method m0;20 21 //構(gòu)造方法22 public $Proxy0(InvocationHandler paramInvocationHandler)23 throws 24 {25 super(paramInvocationHandler);26 }27 28 public final boolean equals(Object paramObject)29 throws 30 {31 try32 {33 return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();34 }35 catch (Error|RuntimeException localError)36 {37 throw localError;38 }39 catch (Throwable localThrowable)40 {41 throw new UndeclaredThrowableException(localThrowable);42 }43 }44 45 //調(diào)用了invocationHandler的invoke方法,invoke執(zhí)行了HelloService 的sayHello方法46 public final void sayHello()47 throws 48 {49 try50 {51 this.h.invoke(this, m3, null);52 return;53 }54 catch (Error|RuntimeException localError)55 {56 throw localError;57 }58 catch (Throwable localThrowable)59 {60 throw new UndeclaredThrowableException(localThrowable);61 }62 }63 64 public final String toString()65 throws 66 {67 try68 {69 return (String)this.h.invoke(this, m2, null);70 }71 catch (Error|RuntimeException localError)72 {73 throw localError;74 }75 catch (Throwable localThrowable)76 {77 throw new UndeclaredThrowableException(localThrowable);78 }79 }80 81 public final int hashCode()82 throws 83 {84 try85 {86 return ((Integer)this.h.invoke(this, m0, null)).intValue();87 }88 catch (Error|RuntimeException localError)89 {90 throw localError;91 }92 catch (Throwable localThrowable)93 {94 throw new UndeclaredThrowableException(localThrowable);95 }96 }97 98 static99 { 100 try 101 { 102 m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") }); 103 m3 = Class.forName("com.doubibi.framework.util.proxy.HelloService").getMethod("sayHello", new Class[0]); 104 m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]); 105 m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]); 106 return; 107 } 108 catch (NoSuchMethodException localNoSuchMethodException) 109 { 110 throw new NoSuchMethodError(localNoSuchMethodException.getMessage()); 111 } 112 catch (ClassNotFoundException localClassNotFoundException) 113 { 114 throw new NoClassDefFoundError(localClassNotFoundException.getMessage()); 115 } 116 } 117 }

    源碼分析參考自

    六、CGLib代理

    七、CGLib原理粗略解析

    CGLIB類庫結(jié)構(gòu)

    先看cglib包里有一個主要的包proxy包如下:

    在該包中的Enhancer類和MethodInterceptor接口是整個包的核心所在!Enhancer就是“增強(qiáng)”的意思!主要用于生成動態(tài)子類以啟用方法攔截,什么意思?這樣子講!cglib類代理的基本思想就是對被代理類生成一個新的類(proxy),該類是繼承自被代理類的,并對被代理類方法執(zhí)行前后執(zhí)行一些操作,這些操作的通常就是一些回調(diào)操作,可以是MethodInterceptor,LazyLoader,CallbackFilter,其中MethodInterceptor是最常用的。所有被Enhancer關(guān)聯(lián)的對象默認(rèn)都是實現(xiàn)Factory接口的,該接口提供了一組可以設(shè)置對象回調(diào)類型的方法,你可以通過調(diào)用setUseFactory(false)取消此特性!需要注意的是,cglib是無法代理final修飾的方法的,因為這是java語言規(guī)范決定的!MethodInterceptor是一個提供環(huán)繞通知的通用回調(diào)接口!Aop中有這樣的術(shù)語,那就是前置通知,后置通知,環(huán)繞通知,非常好理解,就是一個在方法執(zhí)行前的通知,一個方法執(zhí)行后的通知,另外一個就是方法執(zhí)行前后都通知。該接口只有一個intercept()方法:

    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,MethodProxy proxy) throws Throwable;

    所有對被代理類方法的執(zhí)行都會跳轉(zhuǎn)到這個方法上面來,而原來的方法則通過反射得到的Method對象或者M(jìn)ethodProxy對象進(jìn)行調(diào)用。

    八、CGLib代理例子

    • 有一個沒有實現(xiàn)任何接口的實體類
    • 實現(xiàn)一個MethodInterceptor,方法調(diào)用會被轉(zhuǎn)發(fā)到該類的intercept()方法。
    • 然后在需要使用實體類的時候,通過CGLIB動態(tài)代理獲取代理對象。

    實體類:

    public class MyEntity {public void method() {System.out.println("method");} }

    實現(xiàn)一個MethodInterceptor:

    import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {System.out.println("before:"+method.getName());Object object = proxy.invokeSuper(obj, arg);System.out.println("after:"+method.getName());return object;} }

    測試類:

    public class Testcglib {public static void main(String[] args) {//該設(shè)置用于輸出cglib動態(tài)代理產(chǎn)生的類 //Enhancer用于操作底層字節(jié)碼,生成虛擬子類//System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"D:\\proxy"); Enhancer enhancer = new Enhancer();//繼承被代理類enhancer.setSuperclass(MyEntity .class);//設(shè)置回調(diào)enhancer.setCallback(new MyMethodInterceptor());//生成代理類對象MyEntity myEntity= (MyEntity)enhancer.create();//在調(diào)用代理類中方法時會被我們實現(xiàn)的方法攔截器進(jìn)行攔截myEntity.method();} }

    詳細(xì)的CGLib源碼分析

    九、JDK動態(tài)代理和CGLIB代理的區(qū)別

    JDK動態(tài)代理模式只能代理接口,如果要代理類那么就不行了。而CGLIB則是代理類。因此,Spring AOP 會這樣子來進(jìn)行切換,因為Spring AOP 同時支持 CGLIB、ASPECTJ、JDK動態(tài)代理,當(dāng)你的真實對象有實現(xiàn)接口時,Spring AOP會默認(rèn)采用JDK動態(tài)代理,否則采用cglib代理。同時CGLIB也有其缺陷,那就是必須目標(biāo)類必須是可以繼承的,如果目標(biāo)類不可繼承,那么我們就無法使用CGLIB來增強(qiáng)該類,我們可以稱JDK動態(tài)代理實現(xiàn)的AOP為面向接口的動態(tài)增強(qiáng),將CGLIB實現(xiàn)的AOP稱為面向子類的動態(tài)增強(qiáng)。
    在spring中:

  • 如果目標(biāo)對象實現(xiàn)了接口,默認(rèn)情況下會采用JDK的動態(tài)代理去實現(xiàn)AOP
  • 如果目標(biāo)對象實現(xiàn)了接口,可以強(qiáng)制使用CGLIB實現(xiàn)AOP
  • 如果目標(biāo)對象沒有實現(xiàn)了接口,必須采用CGLIB庫,spring會自動在JDK動態(tài)代理和CGLIB之間轉(zhuǎn)換
  • 總結(jié)

    以上是生活随笔為你收集整理的Java静态代理、动态代理与CGLib代理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 日韩少妇内射免费播放18禁裸乳 | 亚洲美女激情视频 | 亚洲成人av在线 | 亚洲高清免费观看 | 自拍欧美日韩 | 中国黄色片视频 | 色啪综合 | 老司机福利av| 在线欧美色 | a极黄色片 | 97在线免费视频 | 欧美人妖乱大交 | 中文字幕Av日韩精品 | 亚洲欧美日韩一区二区三区在线观看 | 视频福利在线观看 | 456亚洲影视 | 北条麻妃av在线 | 日本精品视频在线 | www.jizzjizz| 国产在线123 | 日韩精品av一区二区三区 | 尤物视频在线播放 | 一级少妇精品久久久久久久 | 91精品国产99久久久久久红楼 | 欧美成人精精品一区二区频 | 亚洲国产高清国产精品 | 青青草成人免费视频 | av资源网在线 | 国产jjizz一区二区三区视频 | 国产精品久久久久久av | 国产精品久久久久久吹潮 | 精品一区二区三区四区五区 | 久久aaaa片一区二区 | 日韩欧美中文字幕一区二区 | a级片网址 | 成人精品在线视频 | 精品视频一区二区三区四区 | 国产精品99久 | 中文字幕久热 | 性欧美大战久久久久久久 | 欧美久久精品一级黑人c片 1000部多毛熟女毛茸茸 | 免费av动漫 | 久久午夜精品人妻一区二区三区 | 中文一区在线 | 国产麻豆一级片 | 九九视频免费在线观看 | 久久精品国产一区二区三区 | 黄色三级带 | 免费黄视频在线观看 | 人人爽爽爽 | 日韩极品视频 | 九色综合网 | 国产精品毛片久久 | 欧美夜夜夜 | 天天射日日操 | 亲子乱对白乱都乱了 | 精品视频中文字幕 | 日韩一区二区视频在线观看 | 大又大又粗又硬又爽少妇毛片 | 重囗另类bbwseⅹhd | 免费看一级视频 | 日本免费一区二区视频 | 国产区第一页 | 欧美一级欧美三级在线观看 | 日日射夜夜操 | 成人精品视频在线 | 2019中文字幕在线 | 亚洲jizzjizz日本少妇 | 欧美成人一区在线 | 成人免费一级 | 国产精品一区二区三区四区在线观看 | 免费观看的毛片 | 人妻互换一二三区激情视频 | 一区二区三区在线免费观看视频 | 欧美多人猛交狂配 | 91国偷自产中文字幕久久 | 人妻精品无码一区二区三区 | 日本黄色美女视频 | 国产网站黄 | 亚洲精品你懂的 | 麻豆 美女 丝袜 人妻 中文 | 久久久久久久久久久综合 | 亚洲精品久久久久中文字幕二区 | 亚洲少妇一区二区 | 久久影视精品 | www.av黄色| 亚洲熟妇色自偷自拍另类 | 精品国产三级片在线观看 | 中文视频在线观看 | av最新天堂 | 久久久久久久九九九九 | 欧美久久一级 | 熟女俱乐部一区二区视频在线 | 久久久久成人片免费观看蜜芽 | 一级久久久| 男男全肉变态重口高h | 丰满岳乱妇一区二区 | 亚洲av无码国产综合专区 | 制服丝袜手机在线 |