代码示例
接口
publicinterfaceIUserDao{voidsave();}
实现类
publicclassUserDaoimplementsIUserDao{@Overridepublicvoidsave(){ System.out.println("=====已经保存数据======="); }}
代理类
publicclassDynamicJdkProxy{/**
* 维护一个目标对象
*/privateObject target;publicDynamicJdkProxy(Object target){this.target = target; }/**
* 给目标对象生成代理对象
*
* @return
*/publicObjectgetProxyInstance(){returnProxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(),newInvocationHandler() { @OverridepublicObjectinvoke(Object proxy, Method method, Object[] args) throws Throwable{ System.out.println("开始事务2");//执行目标对象方法Object returnValue = method.invoke(target, args); System.out.println("提交事务2");returnreturnValue; } } ); }}
运行
//生成相应的class文件System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");// 目标对象IUserDao target =newUserDao();// 【原始的类型 class com.example.learning.proxy.UserDao】System.out.println(target.getClass());// 给目标对象,创建代理对象IUserDao proxy = (IUserDao)newDynamicJdkProxy(target).getProxyInstance();// class $Proxy0 内存中动态生成的代理对象System.out.println(proxy.getClass());// 执行方法 【代理对象】proxy.save();
执行结果
class com.example.learning.proxy.UserDaoclass com.sun.proxy.$Proxy0开始事务2=====已经保存数据=======提交事务2Process finished withexitcode0
源码分析:
publicstaticObjectnewProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)throwsIllegalArgumentException{//克隆接口finalClass[] intfs = interfaces.clone();//重点:生成 $Proxy0.class 文件并通过 ClassLoader 加载进来Class cl = getProxyClass0(loader, intfs);//创建代理类的构造器finalConstructor cons = cl.getConstructor(constructorParams);//生成代理类的实例returncons.newInstance(newObject[]{h}); }
再来看 getProxyClass0 的具体实现: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函数,直接取代理类的路径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 函数,取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;/*
* 产生代理类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标识
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()); } }}
核心代码
调用的就是InvocationHandler#invoke方法super.h.invoke(this, m3, (Object[])null); h为Proxy类的/**
* the invocation handler for this proxy instance.
* @serial
*/protectedInvocationHandler h;
JDK 代理通过在运行期期间创建一个接口的实现类来完成对目标对象的代理.
CGLIB 代理
CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层依靠ASM(开源的Java字节码编辑类库)操作字节码实现。
代理类
publicclassUserDaoCG{publicvoidsave(){ System.out.println("=====已经保存数据======="); }}
CG 代理
publicclassCgLibProxyimplementsMethodInterceptor{/**
* 维护目标对象
*/privateObject target;publicCgLibProxy(Object target){this.target = target; }/** * 给目标对象创建一个代理对象 * *@return*/publicObjectgetProxyInstance(){//1.工具类Enhancer en =newEnhancer();//2.设置父类en.setSuperclass(target.getClass());//3.设置回调函数en.setCallback(this);//4.创建子类(代理对象)returnen.create(); }@OverridepublicObjectintercept(Object obj, Method method, Object[] args, MethodProxy proxy)throwsThrowable{ System.out.println("开始CGLib事务...");//执行目标对象的方法Object returnValue = method.invoke(target, args); System.out.println("提交CGLib事务...");returnreturnValue; }}
运行代理
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,"/Users/xxx/IdeaProjects/learning/cg");//目标对象UserDao target =newUserDao();//代理对象UserDao proxy = (UserDao)newCgLibProxy(target).getProxyInstance();//执行代理对象的方法proxy.save();
运行结果
CGLIB debugging enabled, writing to'/Users/xxx/IdeaProjects/learning/cg'开始CGLib事务...=====已经保存数据=======提交CGLib事务...
生成的代理类
//// 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(); }}
关键代码
public finalvoidsave() {//代理类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(); } }
深圳网站建设www.sz886.com