代碼示例
接口
publicinterfaceIUserDao{voidsave();}
實(shí)現(xiàn)類
publicclassUserDaoimplementsIUserDao{@Overridepublicvoidsave(){? ? ? ? System.out.println("=====已經(jīng)保存數(shù)據(jù)=======");? ? }}
代理類
publicclassDynamicJdkProxy{/**
? ? * 維護(hù)一個(gè)目標(biāo)對(duì)象
? ? */privateObject target;publicDynamicJdkProxy(Object target){this.target = target;? ? }/**
? ? * 給目標(biāo)對(duì)象生成代理對(duì)象
? ? *
? ? * @return
? ? */publicObjectgetProxyInstance(){returnProxy.newProxyInstance(? ? ? ? ? ? ? ? target.getClass().getClassLoader(),? ? ? ? ? ? ? ? target.getClass().getInterfaces(),newInvocationHandler() {? ? ? ? ? ? ? ? ? ? @OverridepublicObjectinvoke(Object proxy, Method method, Object[] args) throws Throwable{? ? ? ? ? ? ? ? ? ? ? ? System.out.println("開始事務(wù)2");//執(zhí)行目標(biāo)對(duì)象方法Object returnValue = method.invoke(target, args);? ? ? ? ? ? ? ? ? ? ? ? System.out.println("提交事務(wù)2");returnreturnValue;? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? );? ? }}
運(yùn)行
//生成相應(yīng)的class文件System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");// 目標(biāo)對(duì)象IUserDao target =newUserDao();// 【原始的類型 class com.example.learning.proxy.UserDao】System.out.println(target.getClass());// 給目標(biāo)對(duì)象,創(chuàng)建代理對(duì)象IUserDao proxy = (IUserDao)newDynamicJdkProxy(target).getProxyInstance();// class $Proxy0? 內(nèi)存中動(dòng)態(tài)生成的代理對(duì)象System.out.println(proxy.getClass());// 執(zhí)行方法? 【代理對(duì)象】proxy.save();
執(zhí)行結(jié)果
class com.example.learning.proxy.UserDaoclass com.sun.proxy.$Proxy0開始事務(wù)2=====已經(jīng)保存數(shù)據(jù)=======提交事務(wù)2Process finished withexitcode0
源碼分析:
publicstaticObjectnewProxyInstance(ClassLoader loader,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Class<?>[] interfaces,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? InvocationHandler h)throwsIllegalArgumentException{//克隆接口finalClass[] intfs = interfaces.clone();//重點(diǎn):生成 $Proxy0.class 文件并通過 ClassLoader 加載進(jìn)來Class cl = getProxyClass0(loader, intfs);//創(chuàng)建代理類的構(gòu)造器finalConstructor cons = cl.getConstructor(constructorParams);//生成代理類的實(shí)例returncons.newInstance(newObject[]{h});? ? }
再來看 getProxyClass0 的具體實(shí)現(xiàn):ProxyClassFactory工廠類:
Map, Boolean> interfaceSet =newIdentityHashMap<>(interfaces.length);for(Class intf : interfaces) {? ? ? ? ? ? ? ? ? ? interfaceClass = Class.forName(intf.getName(),false, loader);? ? ? ? ? ? }StringproxyPkg =null;// package to define proxy class in//如果需要代理的類中有非public函數(shù),直接取代理類的路徑for(Class intf : interfaces) {intflags = intf.getModifiers();if(!Modifier.isPublic(flags)) {? ? ? ? ? ? ? ? ? ? accessFlags = Modifier.FINAL;Stringname = intf.getName();intn = name.lastIndexOf('.');Stringpkg = ((n ==-1) ?"": name.substring(0, n +1));if(proxyPkg ==null) {? ? ? ? ? ? ? ? ? ? ? ? proxyPkg = pkg;? ? ? ? ? ? ? ? ? ? }elseif(!pkg.equals(proxyPkg)) {thrownewIllegalArgumentException("non-public interfaces from different packages");? ? ? ? ? ? ? ? ? ? }? ? ? ? ? ? ? ? }? ? ? ? ? ? }//如果全是 Public 函數(shù),取com.sun.proxy 作為包名if(proxyPkg ==null) {// if no non-public proxy interfaces, use com.sun.proxy packageproxyPkg = ReflectUtil.PROXY_PACKAGE +".";? ? ? ? ? ? }/*
? ? ? ? ? ? *? 生成代理類名稱 com.sun.proxy.$ProxyXXX
? ? ? ? ? ? */longnum= nextUniqueNumber.getAndIncrement();StringproxyName = proxyPkg + proxyClassNamePrefix +num;/*
? ? ? ? ? ? * 產(chǎn)生代理類class
? ? ? ? ? ? */byte[] proxyClassFile = ProxyGenerator.generateProxyClass(? ? ? ? ? ? ? ? proxyName, interfaces, accessFlags);//加載classreturndefineClass0(loader, proxyName,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? proxyClassFile,0, proxyClassFile.length);? ? ? ? }
生成class
publicstaticbyte[] generateProxyClass(finalString var0, Class[] var1,intvar2) {? ? ? ? ProxyGenerator var3 =newProxyGenerator(var0, var1, var2);finalbyte[] var4 = var3.generateClassFile();if(saveGeneratedFiles) {? ? ? ? ...? ? ? ? }
是否生成class標(biāo)識(shí)
privatestaticfinalbooleansaveGeneratedFiles = (Boolean)AccessController.doPrivileged(newGetBooleanAction("sun.misc.ProxyGenerator.saveGeneratedFiles"));
生成后的代理類:
publicfinalclass$Proxy0extendsProxyimplementsIUserDao{privatestaticMethod m1;privatestaticMethod m3;privatestaticMethod m2;privatestaticMethod m0;public$Proxy0(InvocationHandler var1)throws{super(var1);? ? }publicfinalbooleanequals(Object var1)throws{//省略}publicfinalvoidsave()throws{try{super.h.invoke(this, m3, (Object[])null);? ? ? ? }catch(RuntimeException | Error var2) {throwvar2;? ? ? ? }catch(Throwable var3) {thrownewUndeclaredThrowableException(var3);? ? ? ? }? ? }publicfinalStringtoString()throws{//省略}publicfinalinthashCode()throws{//省略}static{try{? ? ? ? ? ? m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));? ? ? ? ? ? m3 = Class.forName("com.example.learning.proxy.IUserDao").getMethod("save");? ? ? ? ? ? m2 = Class.forName("java.lang.Object").getMethod("toString");? ? ? ? ? ? m0 = Class.forName("java.lang.Object").getMethod("hashCode");? ? ? ? }catch(NoSuchMethodException var2) {thrownewNoSuchMethodError(var2.getMessage());? ? ? ? }catch(ClassNotFoundException var3) {thrownewNoClassDefFoundError(var3.getMessage());? ? ? ? }? ? }}
核心代碼
調(diào)用的就是InvocationHandler#invoke方法super.h.invoke(this, m3, (Object[])null);? h為Proxy類的/**
? ? * the invocation handler for this proxy instance.
? ? * @serial
? ? */protectedInvocationHandler h;
JDK 代理通過在運(yùn)行期期間創(chuàng)建一個(gè)接口的實(shí)現(xiàn)類來完成對(duì)目標(biāo)對(duì)象的代理.
CGLIB 代理
CGLIB代理:實(shí)現(xiàn)原理類似于JDK動(dòng)態(tài)代理诈乒,只是它在運(yùn)行期間生成的代理對(duì)象是針對(duì)目標(biāo)類擴(kuò)展的子類。CGLIB是高效的代碼生成包,底層依靠ASM(開源的Java字節(jié)碼編輯類庫)操作字節(jié)碼實(shí)現(xiàn)。
代理類
publicclassUserDaoCG{publicvoidsave(){? ? ? ? System.out.println("=====已經(jīng)保存數(shù)據(jù)=======");? ? }}
CG 代理
publicclassCgLibProxyimplementsMethodInterceptor{/**
? ? * 維護(hù)目標(biāo)對(duì)象
? ? */privateObject target;publicCgLibProxy(Object target){this.target = target;? ? }/**? ? * 給目標(biāo)對(duì)象創(chuàng)建一個(gè)代理對(duì)象? ? *? ? *@return*/publicObjectgetProxyInstance(){//1.工具類Enhancer en =newEnhancer();//2.設(shè)置父類en.setSuperclass(target.getClass());//3.設(shè)置回調(diào)函數(shù)en.setCallback(this);//4.創(chuàng)建子類(代理對(duì)象)returnen.create();? ? }@OverridepublicObjectintercept(Object obj, Method method, Object[] args, MethodProxy proxy)throwsThrowable{? ? ? ? System.out.println("開始CGLib事務(wù)...");//執(zhí)行目標(biāo)對(duì)象的方法Object returnValue = method.invoke(target, args);? ? ? ? System.out.println("提交CGLib事務(wù)...");returnreturnValue;? ? }}
運(yùn)行代理
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/xxx/IdeaProjects/learning/cg");//目標(biāo)對(duì)象UserDao target =newUserDao();//代理對(duì)象UserDao proxy = (UserDao)newCgLibProxy(target).getProxyInstance();//執(zhí)行代理對(duì)象的方法proxy.save();
運(yùn)行結(jié)果
CGLIB debugging enabled, writing to'/Users/xxx/IdeaProjects/learning/cg'開始CGLib事務(wù)...=====已經(jīng)保存數(shù)據(jù)=======提交CGLib事務(wù)...
生成的代理類
//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package com.example.learning.proxy;import java.lang.reflect.Method;import org.springframework.cglib.core.ReflectUtils;import org.springframework.cglib.core.Signature;import org.springframework.cglib.proxy.Callback;import org.springframework.cglib.proxy.Factory;import org.springframework.cglib.proxy.MethodInterceptor;import org.springframework.cglib.proxy.MethodProxy;public class UserDao$$EnhancerByCGLIB$$6efc5e8bextends UserDao implements Factory {? ? private boolean CGLIB$BOUND;? ? public static Object CGLIB$FACTORY_DATA;? ? private static final ThreadLocal CGLIB$THREAD_CALLBACKS;? ? private static final Callback[] CGLIB$STATIC_CALLBACKS;? ? private MethodInterceptor CGLIB$CALLBACK_0;? ? private static Object CGLIB$CALLBACK_FILTER;? ? private static final Method CGLIB$save$0$Method;? ? private static final MethodProxy CGLIB$save$0$Proxy;? ? private static final Object[] CGLIB$emptyArgs;? ? private static final Method CGLIB$equals$1$Method;? ? private static final MethodProxy CGLIB$equals$1$Proxy;? ? private static final Method CGLIB$toString$2$Method;? ? private static final MethodProxy CGLIB$toString$2$Proxy;? ? private static final Method CGLIB$hashCode$3$Method;? ? private static final MethodProxy CGLIB$hashCode$3$Proxy;? ? private static final Method CGLIB$clone$4$Method;? ? private static final MethodProxy CGLIB$clone$4$Proxy;? ? static void CGLIB$STATICHOOK1() {? ? ? ? CGLIB$THREAD_CALLBACKS= new ThreadLocal();? ? ? ? CGLIB$emptyArgs= new Object[0];? ? ? ? Class var0 = Class.forName("com.example.learning.proxy.UserDao$$EnhancerByCGLIB$$6efc5e8b");? ? ? ? Class var1;? ? ? ? Method[] var10000 = ReflectUtils.findMethods(new String[]{"equals","(Ljava/lang/Object;)Z","toString","()Ljava/lang/String;","hashCode","()I","clone","()Ljava/lang/Object;"}, (var1 = Class.forName("java.lang.Object")).getDeclaredMethods());? ? ? ? CGLIB$equals$1$Method= var10000[0];? ? ? ? CGLIB$equals$1$Proxy= MethodProxy.create(var1, var0,"(Ljava/lang/Object;)Z","equals","CGLIB$equals$1");? ? ? ? CGLIB$toString$2$Method= var10000[1];? ? ? ? CGLIB$toString$2$Proxy= MethodProxy.create(var1, var0,"()Ljava/lang/String;","toString","CGLIB$toString$2");? ? ? ? CGLIB$hashCode$3$Method= var10000[2];? ? ? ? CGLIB$hashCode$3$Proxy= MethodProxy.create(var1, var0,"()I","hashCode","CGLIB$hashCode$3");? ? ? ? CGLIB$clone$4$Method= var10000[3];? ? ? ? CGLIB$clone$4$Proxy= MethodProxy.create(var1, var0,"()Ljava/lang/Object;","clone","CGLIB$clone$4");? ? ? ? CGLIB$save$0$Method= ReflectUtils.findMethods(new String[]{"save","()V"}, (var1 = Class.forName("com.example.learning.proxy.UserDao")).getDeclaredMethods())[0];? ? ? ? CGLIB$save$0$Proxy= MethodProxy.create(var1, var0,"()V","save","CGLIB$save$0");? ? }? ? final void CGLIB$save$0() {? ? ? ? super.save();? ? }? ? public final voidsave() {? ? ? ? MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if(var10000 == null) {? ? ? ? ? ? CGLIB$BIND_CALLBACKS(this);? ? ? ? ? ? var10000 = this.CGLIB$CALLBACK_0;? ? ? ? }if(var10000 != null) {? ? ? ? ? ? var10000.intercept(this, CGLIB$save$0$Method, CGLIB$emptyArgs, CGLIB$save$0$Proxy);? ? ? ? }else{? ? ? ? ? ? super.save();? ? ? ? }? ? }? ? final boolean CGLIB$equals$1(Object var1) {returnsuper.equals(var1);? ? }? ? public final boolean equals(Object var1) {? ? ? ? MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if(var10000 == null) {? ? ? ? ? ? CGLIB$BIND_CALLBACKS(this);? ? ? ? ? ? var10000 = this.CGLIB$CALLBACK_0;? ? ? ? }if(var10000 != null) {? ? ? ? ? ? Object var2 = var10000.intercept(this, CGLIB$equals$1$Method, new Object[]{var1}, CGLIB$equals$1$Proxy);returnvar2 == null ?false: (Boolean)var2;? ? ? ? }else{returnsuper.equals(var1);? ? ? ? }? ? }? ? final String CGLIB$toString$2() {returnsuper.toString();? ? }? ? public final StringtoString() {? ? ? ? MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if(var10000 == null) {? ? ? ? ? ? CGLIB$BIND_CALLBACKS(this);? ? ? ? ? ? var10000 = this.CGLIB$CALLBACK_0;? ? ? ? }returnvar10000 != null ? (String)var10000.intercept(this, CGLIB$toString$2$Method, CGLIB$emptyArgs, CGLIB$toString$2$Proxy) : super.toString();? ? }? ? final int CGLIB$hashCode$3() {returnsuper.hashCode();? ? }? ? public final inthashCode() {? ? ? ? MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if(var10000 == null) {? ? ? ? ? ? CGLIB$BIND_CALLBACKS(this);? ? ? ? ? ? var10000 = this.CGLIB$CALLBACK_0;? ? ? ? }if(var10000 != null) {? ? ? ? ? ? Object var1 = var10000.intercept(this, CGLIB$hashCode$3$Method, CGLIB$emptyArgs, CGLIB$hashCode$3$Proxy);returnvar1 == null ? 0 : ((Number)var1).intValue();? ? ? ? }else{returnsuper.hashCode();? ? ? ? }? ? }? ? final Object CGLIB$clone$4() throws CloneNotSupportedException {returnsuper.clone();? ? }? ? protected final Objectclone() throws CloneNotSupportedException {? ? ? ? MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;if(var10000 == null) {? ? ? ? ? ? CGLIB$BIND_CALLBACKS(this);? ? ? ? ? ? var10000 = this.CGLIB$CALLBACK_0;? ? ? ? }returnvar10000 != null ? var10000.intercept(this, CGLIB$clone$4$Method, CGLIB$emptyArgs, CGLIB$clone$4$Proxy) : super.clone();? ? }? ? public static MethodProxy CGLIB$findMethodProxy(Signature var0) {? ? ? ? String var10000 = var0.toString();? ? ? ? switch(var10000.hashCode()) {case-508378822:if(var10000.equals("clone()Ljava/lang/Object;")) {returnCGLIB$clone$4$Proxy;? ? ? ? ? ? }break;case1826985398:if(var10000.equals("equals(Ljava/lang/Object;)Z")) {returnCGLIB$equals$1$Proxy;? ? ? ? ? ? }break;case1872760024:if(var10000.equals("save()V")) {returnCGLIB$save$0$Proxy;? ? ? ? ? ? }break;case1913648695:if(var10000.equals("toString()Ljava/lang/String;")) {returnCGLIB$toString$2$Proxy;? ? ? ? ? ? }break;case1984935277:if(var10000.equals("hashCode()I")) {returnCGLIB$hashCode$3$Proxy;? ? ? ? ? ? }? ? ? ? }returnnull;? ? }? ? public UserDao$$EnhancerByCGLIB$$6efc5e8b() {? ? ? ? CGLIB$BIND_CALLBACKS(this);? ? }? ? public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {? ? ? ? CGLIB$THREAD_CALLBACKS.set(var0);? ? }? ? public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {? ? ? ? CGLIB$STATIC_CALLBACKS= var0;? ? }? ? private static final void CGLIB$BIND_CALLBACKS(Object var0) {? ? ? ? UserDao$$EnhancerByCGLIB$$6efc5e8bvar1 = (UserDao$$EnhancerByCGLIB$$6efc5e8b)var0;if(!var1.CGLIB$BOUND) {? ? ? ? ? ? var1.CGLIB$BOUND=true;? ? ? ? ? ? Object var10000 = CGLIB$THREAD_CALLBACKS.get();if(var10000 == null) {? ? ? ? ? ? ? ? var10000 = CGLIB$STATIC_CALLBACKS;if(var10000 == null) {return;? ? ? ? ? ? ? ? }? ? ? ? ? ? }? ? ? ? ? ? var1.CGLIB$CALLBACK_0= (MethodInterceptor)((Callback[])var10000)[0];? ? ? ? }? ? }? ? public Object newInstance(Callback[] var1) {? ? ? ? CGLIB$SET_THREAD_CALLBACKS(var1);? ? ? ? UserDao$$EnhancerByCGLIB$$6efc5e8bvar10000 = new UserDao$$EnhancerByCGLIB$$6efc5e8b();? ? ? ? CGLIB$SET_THREAD_CALLBACKS((Callback[])null);returnvar10000;? ? }? ? public Object newInstance(Callback var1) {? ? ? ? CGLIB$SET_THREAD_CALLBACKS(new Callback[]{var1});? ? ? ? UserDao$$EnhancerByCGLIB$$6efc5e8bvar10000 = new UserDao$$EnhancerByCGLIB$$6efc5e8b();? ? ? ? CGLIB$SET_THREAD_CALLBACKS((Callback[])null);returnvar10000;? ? }? ? public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {? ? ? ? CGLIB$SET_THREAD_CALLBACKS(var3);? ? ? ? UserDao$$EnhancerByCGLIB$$6efc5e8bvar10000 = new UserDao$$EnhancerByCGLIB$$6efc5e8b;? ? ? ? switch(var1.length) {case0:? ? ? ? ? ? var10000.();? ? ? ? ? ? CGLIB$SET_THREAD_CALLBACKS((Callback[])null);returnvar10000;? ? ? ? default:? ? ? ? ? ? throw new IllegalArgumentException("Constructor not found");? ? ? ? }? ? }? ? public Callback getCallback(int var1) {? ? ? ? CGLIB$BIND_CALLBACKS(this);? ? ? ? MethodInterceptor var10000;? ? ? ? switch(var1) {case0:? ? ? ? ? ? var10000 = this.CGLIB$CALLBACK_0;break;? ? ? ? default:? ? ? ? ? ? var10000 = null;? ? ? ? }returnvar10000;? ? }? ? public void setCallback(int var1, Callback var2) {? ? ? ? switch(var1) {case0:? ? ? ? ? ? this.CGLIB$CALLBACK_0= (MethodInterceptor)var2;? ? ? ? default:? ? ? ? }? ? }? ? public Callback[]getCallbacks() {? ? ? ? CGLIB$BIND_CALLBACKS(this);returnnew Callback[]{this.CGLIB$CALLBACK_0};? ? }? ? public void setCallbacks(Callback[] var1) {? ? ? ? this.CGLIB$CALLBACK_0= (MethodInterceptor)var1[0];? ? }? ? static {? ? ? ? CGLIB$STATICHOOK1();? ? }}
關(guān)鍵代碼
public finalvoidsave() {//代理類MethodInterceptor var10000 =this.CGLIB$CALLBACK_0;if(var10000 == null) {CGLIB$BIND_CALLBACKS(this);? ? ? ? ? ? var10000 =this.CGLIB$CALLBACK_0;? ? ? ? }//如果代理類不為空,直接調(diào)用代理方法if(var10000 != null) {? ? ? ? ? ? var10000.intercept(this,CGLIB$save$0$Method,CGLIB$emptyArgs,CGLIB$save$0$Proxy);? ? ? ? }else{super.save();? ? ? ? }? ? }
深圳網(wǎng)站建設(shè)www.sz886.com