Spring温故而知新系列教程之AOP代理
aop的概念
aop:aspect-oriented programming(面向切面编程),*的解释如下:aspect是一种新的模块化机制,用来描述分散在对象、类或者函数中的横切关注点,从关注点中分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不在含有针对特定领域问题的代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护,这样原本分散在整个应用程序中的变动就可以很好地管理起来。从aop的角度,应用可以分为横切关注点和业务逻辑代码,实际开发中,这些横切关注点往往会直接嵌入到业务逻辑代码中,面向切面编程就是要解决把横切关注点与业务逻辑相分离
实现方式:
spring默认使用 jdk 动态代理作为aop的代理,缺陷是目标类的类必须实现接口,否则不能使用jdk动态代理。如果需要代理的是类而不是接口,那么spring会默认使用cglib代理,关于两者的区别:jdk动态代理是通过java的反射机制来实现的,目标类必须要实现接口,cglib是针对类来实现代理的,他的原理是动态的为指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
jdk动态代理
jdk动态代理是在程序运行过程中,根据目标类实现的接口来动态生成代理类的class文件,使用主要涉及两个类:
invocationhandler接口: 它提供了一个invoke(object obj,method method, object[] args)
方法供实现者提供相应的代理逻辑的实现。可以对实际的实现进行一些特殊的处理其中参数
object obj :被代理的目标类
method method: 需要执行的目标类的方法
object[] args :目标方法的参数
proxy类:提供一个方法newproxyinstance (classloader loader, class[] interfaces, invocationhandler h)
来获得动态代理类
示例代码:
public interface orderservice { public void createorder(); }
public class orderserviceimpl implements orderservice { @override public void createorder() { system.out.println("creating order"); } }
public class orderlogger { public void beforecreateorder(){ system.out.println("before create order"); } public void aftercreateorder(){ system.out.println("after create order"); } }
package com.sl.aop; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; public class serviceproxy implements invocationhandler { private object targetclass; private orderlogger orderlogger; public serviceproxy(object targetclass,orderlogger orderlogger) { this.targetclass = targetclass; this.orderlogger = orderlogger; } //获取代理 public object getdynamicproxy() { return proxy.newproxyinstance(targetclass.getclass().getclassloader(), //通过这个classloader生成代理对象 targetclass.getclass().getinterfaces(),//代理类已实现的接口 this); //动态代理调用方法是关联的invocationhandler,最终通过此invocationhandler的invoke方法执行真正的方法 } //实现相应的代理逻辑 @override public object invoke(object proxy, method method, object[] args) throws throwable { this.orderlogger.beforecreateorder(); object result= method.invoke(targetclass, args); this.orderlogger.aftercreateorder(); return result; } }
测试类:
package com.sl.aop; import org.junit.test; public class aoptest { @test public void testdynamicproxy() { orderserviceimpl serviceimpl = new orderserviceimpl(); orderlogger logger = new orderlogger(); orderservice service = (orderservice) new serviceproxy(serviceimpl, logger).getdynamicproxy(); service.createorder(); } }
运行结果:
到这个其实还是有点困惑,proxy.newproxyinstance()
这个返回的是什么? invoke方法在哪里调用的?我们看一下jdk源码:看看dk动态代理的过程是什么样的:
根据源码内部的函数调用proxy.newproxyinstance()->proxy.getproxyclass0()->weakcache.get()
,先定位到
weakcache.class:
public v get(k key, p parameter) { objects.requirenonnull(parameter); expungestaleentries(); object cachekey = cachekey.valueof(key, refqueue); // lazily install the 2nd level valuesmap for the particular cachekey concurrentmap<object, supplier<v>> valuesmap = map.get(cachekey); if (valuesmap == null) { concurrentmap<object, supplier<v>> oldvaluesmap = map.putifabsent(cachekey, valuesmap = new concurrenthashmap<>()); if (oldvaluesmap != null) { valuesmap = oldvaluesmap; } } // create subkey and retrieve the possible supplier<v> stored by that // subkey from valuesmap object subkey = objects.requirenonnull(subkeyfactory.apply(key, parameter)); supplier<v> supplier = valuesmap.get(subkey); factory factory = null; while (true) { if (supplier != null) { // supplier might be a factory or a cachevalue<v> instance v value = supplier.get(); if (value != null) { return value; } } // else no supplier in cache // or a supplier that returned null (could be a cleared cachevalue // or a factory that wasn't successful in installing the cachevalue) // lazily construct a factory if (factory == null) { factory = new factory(key, parameter, subkey, valuesmap); } if (supplier == null) { supplier = valuesmap.putifabsent(subkey, factory); if (supplier == null) { // successfully installed factory supplier = factory; } // else retry with winning supplier } else { if (valuesmap.replace(subkey, supplier, factory)) { // successfully replaced // cleared cacheentry / unsuccessful factory // with our factory supplier = factory; } else { // retry with current supplier supplier = valuesmap.get(subkey); } } } }
可以看到函数return value; 而 v value = supplier.get();
继续往下读可以发现 supper=factory,实际上是一个factory对象,那么继续查看factory.get()
方法
public synchronized v get() { // serialize access // re-check supplier<v> supplier = valuesmap.get(subkey); if (supplier != this) { // something changed while we were waiting: // might be that we were replaced by a cachevalue // or were removed because of failure -> // return null to signal weakcache.get() to retry // the loop return null; } // else still us (supplier == this) // create new value v value = null; try { value = objects.requirenonnull(valuefactory.apply(key, parameter)); } finally { if (value == null) { // remove us on failure valuesmap.remove(subkey, this); } } // the only path to reach here is with non-null value assert value != null; // wrap value with cachevalue (weakreference) cachevalue<v> cachevalue = new cachevalue<>(value); // try replacing us with cachevalue (this should always succeed) if (valuesmap.replace(subkey, this, cachevalue)) { // put also in reversemap reversemap.put(cachevalue, boolean.true); } else { throw new assertionerror("should not reach here"); } // successfully replaced us with new cachevalue -> return the value // wrapped by it return value; }
return value;那么直接查看赋值语句:value = objects.requirenonnull(valuefactory.apply(key, parameter));
valuefactory又什么鬼?
public weakcache(bifunction<k, p, ?> subkeyfactory, bifunction<k, p, v> valuefactory) { this.subkeyfactory = objects.requirenonnull(subkeyfactory); this.valuefactory = objects.requirenonnull(valuefactory); } private static final weakcache<classloader, class<?>[], class<?>> proxyclasscache = new weakcache<>(new keyfactory(), new proxyclassfactory());
可以知道valuefactory是proxyclassfactory类型对象,直接查看proxyclassfactory. apply()
方法
public class<?> apply(classloader loader, class<?>[] interfaces) { map<class<?>, boolean> interfaceset = new identityhashmap<>(interfaces.length); for (class<?> intf : interfaces) { /* * verify that the class loader resolves the name of this * interface to the same class object. */ class<?> interfaceclass = null; try { interfaceclass = class.forname(intf.getname(), false, loader); } catch (classnotfoundexception e) { } if (interfaceclass != intf) { throw new illegalargumentexception( intf + " is not visible from class loader"); } /* * verify that the class object actually represents an * interface. */ if (!interfaceclass.isinterface()) { throw new illegalargumentexception( interfaceclass.getname() + " is not an interface"); } /* * verify that this interface is not a duplicate. */ if (interfaceset.put(interfaceclass, boolean.true) != null) { throw new illegalargumentexception( "repeated interface: " + interfaceclass.getname()); } } string proxypkg = null; // package to define proxy class in int accessflags = modifier.public | modifier.final; /* * record the package of a non-public proxy interface so that the * proxy class will be defined in the same package. verify that * all non-public proxy interfaces are in the same package. */ for (class<?> intf : interfaces) { int flags = intf.getmodifiers(); if (!modifier.ispublic(flags)) { accessflags = modifier.final; string name = intf.getname(); int n = name.lastindexof('.'); string pkg = ((n == -1) ? "" : name.substring(0, n + 1)); if (proxypkg == null) { proxypkg = pkg; } else if (!pkg.equals(proxypkg)) { throw new illegalargumentexception( "non-public interfaces from different packages"); } } } if (proxypkg == null) { // if no non-public proxy interfaces, use com.sun.proxy package proxypkg = reflectutil.proxy_package + "."; } /* * choose a name for the proxy class to generate. */ long num = nextuniquenumber.getandincrement(); string proxyname = proxypkg + proxyclassnameprefix + num; /* * generate the specified proxy class. */ byte[] proxyclassfile = proxygenerator.generateproxyclass( proxyname, interfaces, accessflags); try { return defineclass0(loader, proxyname, proxyclassfile, 0, proxyclassfile.length); } catch (classformaterror e) { /* * a classformaterror here means that (barring bugs in the * proxy class generation code) there was some other * invalid aspect of the arguments supplied to the proxy * class creation (such as virtual machine limitations * exceeded). */ throw new illegalargumentexception(e.tostring()); } } }
直接画重点:
byte[] proxyclassfile = proxygenerator.generateproxyclass( proxyname, interfaces, accessflags); return defineclass0(loader, proxyname, proxyclassfile, 0, proxyclassfile.length);
调用proxygenerator.generateproxyclass
最终动态生成一个代理类,但是似乎并未找到何处调用了invoke方法;参考csdn: 这篇文章,尝试将这个动态生成的二进制字节码输出到本地,并反编译出来一看究竟,测试代码如下:
public class aoptest { @test public void testdynamicproxy() { orderserviceimpl serviceimpl = new orderserviceimpl(); orderlogger logger = new orderlogger(); orderservice service = (orderservice) new serviceproxy(serviceimpl, logger).getdynamicproxy(); service.createorder(); //输出动态代理类字节码 createproxyclassfile(); } private static void createproxyclassfile(){ string name = "proxyobject"; byte[] data = proxygenerator.generateproxyclass(name,new class[]{orderservice.class}); fileoutputstream out =null; try { out = new fileoutputstream(name+".class"); system.out.println((new file("hello")).getabsolutepath()); out.write(data); } catch (filenotfoundexception e) { e.printstacktrace(); } catch (ioexception e) { e.printstacktrace(); }finally { if(null!=out) try { out.close(); } catch (ioexception e) { e.printstacktrace(); } } } }
使用java decompiler工具将这个二进制class文件反编译查看:
具体动态代理类proxyobject.java:
import com.sl.aop.orderservice; import java.lang.reflect.invocationhandler; import java.lang.reflect.method; import java.lang.reflect.proxy; import java.lang.reflect.undeclaredthrowableexception; public final class proxyobject extends proxy implements orderservice { private static method m1; private static method m2; private static method m3; private static method m0; public proxyobject(invocationhandler paraminvocationhandler) { super(paraminvocationhandler); } public final boolean equals(object paramobject) { try { return ((boolean)this.h.invoke(this, m1, new object[] { paramobject })).booleanvalue(); } catch (error|runtimeexception localerror) { throw localerror; } catch (throwable localthrowable) { throw new undeclaredthrowableexception(localthrowable); } } public final string tostring() { try { return (string)this.h.invoke(this, m2, null); } catch (error|runtimeexception localerror) { throw localerror; } catch (throwable localthrowable) { throw new undeclaredthrowableexception(localthrowable); } } public final void createorder() { try { this.h.invoke(this, m3, null); return; } catch (error|runtimeexception localerror) { throw localerror; } catch (throwable localthrowable) { throw new undeclaredthrowableexception(localthrowable); } } public final int hashcode() { try { return ((integer)this.h.invoke(this, m0, null)).intvalue(); } catch (error|runtimeexception localerror) { throw localerror; } catch (throwable localthrowable) { throw new undeclaredthrowableexception(localthrowable); } } static { try { m1 = class.forname("java.lang.object").getmethod("equals", new class[] { class.forname("java.lang.object") }); m2 = class.forname("java.lang.object").getmethod("tostring", new class[0]); m3 = class.forname("com.sl.aop.orderservice").getmethod("createorder", new class[0]); m0 = class.forname("java.lang.object").getmethod("hashcode", new class[0]); return; } catch (nosuchmethodexception localnosuchmethodexception) { throw new nosuchmethoderror(localnosuchmethodexception.getmessage()); } catch (classnotfoundexception localclassnotfoundexception) { throw new noclassdeffounderror(localclassnotfoundexception.getmessage()); } }
终于看到关于invoke的部分了:
public final void createorder() { try { this.h.invoke(this, m3, null); return; } catch (error|runtimeexception localerror) { throw localerror; } catch (throwable localthrowable) { throw new undeclaredthrowableexception(localthrowable); } }
实际上动态代理类继承自proxy,并且实现了目标类继承的接口,在createorder方法中调用了invoke方法,实现了切面逻辑的植入,这里也回答了一个问题,为什么jdk动态代理的目标类必须是实现接口的,因为代理类其实是针对接口代理,而不是针对类来代理的,动态代理类自己继承自proxy,java也不允许多重继承。动态代理类和目标类其实是各自实现了接口,代理类通过invocationhandler.invoke实现对目标类方法的调用。
cglib动态代理
cglib代理是通过使用一个字节码处理框架asm,来转换字节码并生成新的类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,实现织如如横切逻辑 ,效率上比使用反射技术的jdk动态代理要高,但是由于cglib的原理是动态为目标类生成子类代理类,所以不能为声明为final的方法进行代理。其使用主要涉及两个类:
methodinterceptor接口:该接口提供一个方法intercept(object arg0, method arg1, object[] arg2, methodproxy arg3)
主要用于拦截目标类方法的调用
object arg0, :被代理的目标类
method arg1, 委托方法
object[] arg2, 方法参数
methodproxy arg3 :代理方法的methodproxy对象
enhancer类:用于创建代理类
示例:
实现methodinterceptor接口,代理类在调用方法时,cglib会回调methodinterceptor接口intercept方法,从而织入切面逻辑。
package com.sl.aop; import java.lang.reflect.method; import org.springframework.cglib.proxy.enhancer; import org.springframework.cglib.proxy.methodinterceptor; import org.springframework.cglib.proxy.methodproxy; public class cglibserviceproxy implements methodinterceptor { private object targetclass; private orderlogger orderlogger; public cglibserviceproxy(object targetclass,orderlogger orderlogger) { this.targetclass = targetclass; this.orderlogger = orderlogger; } /** * 创建代理对象 * */ public object getinstance() { enhancer enhancer = new enhancer(); //设置目标类(需要被代理的类) enhancer.setsuperclass(this.targetclass.getclass()); // 回调方法 enhancer.setcallback(this); // 创建代理对象 return enhancer.create(); } /** * 拦截所有目标类方法的调用 * */ @override public object intercept(object arg0, method arg1, object[] arg2, methodproxy arg3) throws throwable { orderlogger.beforecreateorder(); object o1 = arg3.invokesuper(arg0, arg2); orderlogger.aftercreateorder(); return o1; } }
测试方法:
public void testdynamicproxy() { system.setproperty(debuggingclasswriter.debug_location_property, "d:\\class"); orderserviceimpl serviceimpl = new orderserviceimpl(); orderlogger logger = new orderlogger(); cglibserviceproxy proxy = new cglibserviceproxy(serviceimpl,logger); //通过生成子类的方式创建代理类 orderserviceimpl proxyimp = (orderserviceimpl)proxy.getinstance(); proxyimp.createorder(); }
结果:
system.setproperty(debuggingclasswriter.debug_location_property, "d:\\class");
将cglib动态代理类输出到指定目录,反编译查看一下代理类真面目:
package com.sl.aop; import com.sl.aop.orderserviceimpl; 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 orderserviceimpl$$enhancerbycglib$$17779aa4 extends orderserviceimpl 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$createorder$0$method; private static final methodproxy cglib$createorder$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.sl.aop.orderserviceimpl$$enhancerbycglib$$17779aa4"); 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$createorder$0$method = reflectutils.findmethods(new string[]{"createorder", "()v"}, (var1 = class.forname("com.sl.aop.orderserviceimpl")).getdeclaredmethods())[0]; cglib$createorder$0$proxy = methodproxy.create(var1, var0, "()v", "createorder", "cglib$createorder$0"); } final void cglib$createorder$0() { super.createorder(); } public final void createorder() { methodinterceptor var10000 = this.cglib$callback_0; if(this.cglib$callback_0 == null) { cglib$bind_callbacks(this); var10000 = this.cglib$callback_0; } if(var10000 != null) { var10000.intercept(this, cglib$createorder$0$method, cglib$emptyargs, cglib$createorder$0$proxy); } else { super.createorder(); } } final boolean cglib$equals$1(object var1) { return super.equals(var1); } public final boolean equals(object var1) { methodinterceptor var10000 = this.cglib$callback_0; if(this.cglib$callback_0 == 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); return var2 == null?false:((boolean)var2).booleanvalue(); } else { return super.equals(var1); } } final string cglib$tostring$2() { return super.tostring(); } public final string tostring() { methodinterceptor var10000 = this.cglib$callback_0; if(this.cglib$callback_0 == null) { cglib$bind_callbacks(this); var10000 = this.cglib$callback_0; } return var10000 != null?(string)var10000.intercept(this, cglib$tostring$2$method, cglib$emptyargs, cglib$tostring$2$proxy):super.tostring(); } final int cglib$hashcode$3() { return super.hashcode(); } public final int hashcode() { methodinterceptor var10000 = this.cglib$callback_0; if(this.cglib$callback_0 == 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); return var1 == null?0:((number)var1).intvalue(); } else { return super.hashcode(); } } final object cglib$clone$4() throws clonenotsupportedexception { return super.clone(); } protected final object clone() throws clonenotsupportedexception { methodinterceptor var10000 = this.cglib$callback_0; if(this.cglib$callback_0 == null) { cglib$bind_callbacks(this); var10000 = this.cglib$callback_0; } return var10000 != 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 -2138148221: if(var10000.equals("createorder()v")) { return cglib$createorder$0$proxy; } break; case -508378822: if(var10000.equals("clone()ljava/lang/object;")) { return cglib$clone$4$proxy; } break; case 1826985398: if(var10000.equals("equals(ljava/lang/object;)z")) { return cglib$equals$1$proxy; } break; case 1913648695: if(var10000.equals("tostring()ljava/lang/string;")) { return cglib$tostring$2$proxy; } break; case 1984935277: if(var10000.equals("hashcode()i")) { return cglib$hashcode$3$proxy; } } return null; } public orderserviceimpl$$enhancerbycglib$$17779aa4() { 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) { orderserviceimpl$$enhancerbycglib$$17779aa4 var1 = (orderserviceimpl$$enhancerbycglib$$17779aa4)var0; if(!var1.cglib$bound) { var1.cglib$bound = true; object var10000 = cglib$thread_callbacks.get(); if(var10000 == null) { var10000 = cglib$static_callbacks; if(cglib$static_callbacks == null) { return; } } var1.cglib$callback_0 = (methodinterceptor)((callback[])var10000)[0]; } } public object newinstance(callback[] var1) { cglib$set_thread_callbacks(var1); orderserviceimpl$$enhancerbycglib$$17779aa4 var10000 = new orderserviceimpl$$enhancerbycglib$$17779aa4(); cglib$set_thread_callbacks((callback[])null); return var10000; } public object newinstance(callback var1) { cglib$set_thread_callbacks(new callback[]{var1}); orderserviceimpl$$enhancerbycglib$$17779aa4 var10000 = new orderserviceimpl$$enhancerbycglib$$17779aa4(); cglib$set_thread_callbacks((callback[])null); return var10000; } public object newinstance(class[] var1, object[] var2, callback[] var3) { cglib$set_thread_callbacks(var3); orderserviceimpl$$enhancerbycglib$$17779aa4 var10000 = new orderserviceimpl$$enhancerbycglib$$17779aa4; switch(var1.length) { case 0: var10000.<init>(); cglib$set_thread_callbacks((callback[])null); return var10000; default: throw new illegalargumentexception("constructor not found"); } } public callback getcallback(int var1) { cglib$bind_callbacks(this); methodinterceptor var10000; switch(var1) { case 0: var10000 = this.cglib$callback_0; break; default: var10000 = null; } return var10000; } public void setcallback(int var1, callback var2) { switch(var1) { case 0: this.cglib$callback_0 = (methodinterceptor)var2; default: } } public callback[] getcallbacks() { cglib$bind_callbacks(this); return new callback[]{this.cglib$callback_0}; } public void setcallbacks(callback[] var1) { this.cglib$callback_0 = (methodinterceptor)var1[0]; } static { cglib$statichook1(); } }
上面的代码可以看到代理类orderserviceimpl$$enhancerbycglib$$17779aa4 继承目标类orderserviceimpl并且实现了接口factory,代理类中关于createorder生成了两个方法cglib$createorder$0和createorder:
cglib$createorder$0方法内部直接调用目标类的supper.createorder
createorder方法内部首先盘点否实现了methodinterceptor接口的callback,如果存在则调用methodinterceptor接口拦截方法intercept,根据前面的实现intercept方法内部实现了对目标方法的调用object o1 = arg3.invokesuper(arg0, arg2)
,invokesuper内部实际上是直接调用的代理类的cglib$createorder$0()
方法,最终调用了目标类createorder。
两种代理对比
jdk动态代理:
代理类与委托类实现同一接口,主要是通过代理类实现invocationhandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理 优点:不需要硬编码接口,代码复用率高,缺点:只能够代理实现了接口的委托类
cglib动态代理:
代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了methodinterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理 优点:可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口,缺点:不能对final类以及final方法进行代理
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。