cglib创建代理对象

还是从一个的小demo开始

例子

  1. 被代理的类

    public class Bean{public String sayHello(String name) {return "Bean.sayHello";}private String  privateSayHello(String name){return "Bean.privateSayHello";}public String lipu1(){return "lipu";}private String privateLipu1(){return "privateLipu1";}public String jump(){return "jump";}private String privateJump(){return "privateJump";}public String hhhh(){return "hhhh";}private String privateHhhh(){return "hhhh";}public String dadada(){return "dadada";}private String privateDadada(){return "privateDadada";}public String lululu(){return "lululu";}private String privateLululu(){return "privateLululu";}}
    
  2. 主测试类

    public class SampleTest {public static void main(String[] args) {// 保存生成的class的路径,对应的代码在DebuggingClassWriter#DEBUG_LOCATION_PROPERTY字段,toByteArray方法System.getProperties().setProperty("cglib.debugLocation","C:\\Users\\Administrator\\Desktop\\temp");Enhancer enhancer = new Enhancer();final Bean bean = new Bean();enhancer.setSuperclass(Bean.class);// 下面的这些都是Callback,这些Callback是通过CallbackFilter来指定的。Dispatcher dispatcher = new Dispatcher() {@Overridepublic Object loadObject() throws Exception {System.out.println("SampleTest.loadObject");return bean;}};MethodInterceptor methodInterceptor = new MethodInterceptor() {@Overridepublic Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("SampleTest.intercept");return "SampleTest.intercept";}};InvocationHandler invocationHandler = new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("SampleTest.invoke");return "SampleTest.invoke";}};LazyLoader lazyLoader = new LazyLoader() {@Overridepublic Object loadObject() throws Exception {System.out.println("SampleTest.loadObject");return bean;}};FixedValue fixedValue = new FixedValue() {@Overridepublic Object loadObject() throws Exception {System.out.println("SampleTest.loadObject");return bean;}};ProxyRefDispatcher proxyRefDispatcher = new ProxyRefDispatcher() {@Overridepublic Object loadObject(Object proxy) throws Exception {return bean;}};Callback[] callbacks = {dispatcher,methodInterceptor,invocationHandler,lazyLoader,fixedValue,NoOp.INSTANCE,proxyRefDispatcher};// 通过方法的名字来指定那个callback起作用CallbackFilter callbackFilter = new CallbackFilter() {@Overridepublic int accept(Method method) {System.out.println("SampleTest.accept:" + method.getName());switch (method.getName()){case "sayHello":return 0;case "lipu1":return 1;case "jump":return 2;case "hhhh":return 3;case "dadada":return 4;case "lululu":  // 如果是 NoOp.INSTANCE表示不需要代理,在生成的代理类里面没有操作,也就是代理类不会重写父类的方法return 5;case "sasasasa":return 6;}return 0;}};enhancer.setCallbacks(callbacks);enhancer.setCallbackFilter(callbackFilter);Bean o = (Bean) enhancer.create();String test = o.sayHello("test");System.out.println(test);}
    }
    

概念解释

这里只是将正常使用的时候的两种常见的类型做解释,其余和Cglib有比较重要的概念在之后说

Callback

先看类图

关于各个的实现类的功能,已经在各个类的注释上说清楚了。可能有的意思还是不太懂,在本文的最后一节里面,贴出了生成的代理类,对比代理类,看看不同的Callback的子类的作用,就很清晰了。

子类解释

  1. MethodInterceptor:回调,可以通过MethodProxy调用父类,或者同一个类型的Bean的同名方法
  2. NoOp:什么都不做
  3. LazyLoader:懒加载,但是加载过之后,就不加载了。
  4. Dispatcher:做分派,每次都会调用。通过它返回的Bean来做同名方法的调用
  5. InvocationHandler:这就和JDK的一样,和MethodInterceptor不一样的是,它没有MethodProxy
  6. FixedValue:固定值。

CallbackFilter

在生成代理类的时候,代理类会重写父类的方法,在重写父类方法的时候,会通过它来判断要用哪个Callback。

accept方法返回的是Callback数组中的下标。在构建代理类的时候,就会使用Callback数组对应下标中的Callback。

public interface CallbackFilter {int accept(Method method);boolean equals(Object o);
}

在生成代理类的时候,代理类会重写父类的方法,在重写父类方法的时候,会通过它来判断要用哪个Callback。对应于(Enhancer#emitMethods,在这个方法里面有int index = filter.accept(actualMethod);代码)

如果传递的Callback多于一个,并且没有指定CallbackFilter的话,就会报错,如果CallBack就一个,它会给一个默认的CallbackFilter,总是返回0。(Enhancer#preValidate做判断,并且给默认值。)

这是和JDK-Proxy不同的一点,在JDK-Proxy是不能支持多个InvocationHandler,但是Cglib是可以的

这篇文章不具体的分析CGLIB创建代理对象的操作。旨在说清楚Callback子接口的作用,还有CallBackFilter。还有生成的代理类长什么样?

代理类

代理类的创建和生成是在内存里面的,不过可以通过配置,让生成的类保存起来,便于观察。通过下面的代码开启
System.getProperties().setProperty("cglib.debugLocation","C:\\Users\\Administrator\\Desktop\\temp");

在运行上面的例子之后,就会在指定的文件夹下面生成几个class文件

将生成的文件直接拖入Idea,idea会反编译。便于我们观察

代码比较多,详细的解释写在注释里面,这里会对这个类来做一些简单的说明:

  1. 在代理类里面保留callback子接口的引用关系,在不同的方法里面用不同的callback。

  2. private方法是不能被代理对象重写的, 可以看到上面例子里面private开头的方法,都没有被重写。

  3. 如果给一个方法指定的callback类型是NoOp.INSTANCE,那这个方法可能是不会被代理类重写的(可以看到,上面例子中lululu方法并没有被重写),这里说可能的意思是NoOp也有NoOpGenerator,具体的代码逻辑在NoOpGenerator#generate。它要求满足下面才可以重写。

看这个代码逻辑,有两个问题,

  • Method有区分,OriginalMethod和Method有什么区别?
  • OriginalMethod为public,代理的方法为Public是什么样的场景?

具体在后面分析

  1. 所有通过Enhancer生成的代理类都实现了Factory接口

通过这个接口可以很快的创建代理类(很快的意思是,如果要创建一个和当前代理类在同样的方法用同样的callback类型,但是行为不一样,创建起来比较快,因为直接new 对象就好了,但是如果要通过Enhancer来做的,就比较慢了,快就快在这里了,如果用Enhancer来做,起码要在内存里面编织字节码,这一点就比较慢了)只要指定Callback就可以创建代理类,可以动态的修改Callback(也就是可以动态的修改行为),还可以获取Callback。

  1. equals,toString,hashCode,clone也会走callbackFilter的逻辑,但是这里要注意了,对于protected修饰的方法,不同的CallbackGenerator有不同的要求

    DispatcherGenerator:不支持重写(DispatcherGenerator#generate方法里面有if (!TypeUtils.isProtected(method.getModifiers()))判断)

    FixedValueGenerator:支持(FixedValueGenerator#generate方法里面没有类似上面的判断)

    InvocationHandlerGenerator:支持(InvocationHandlerGenerator#generate,没有类似上面的判断)

    LazyLoaderGenerator:不支持(LazyLoaderGenerator#generate,TypeUtils.isProtected(method.getModifiers())

    MethodInterceptorGenerator:支持(MethodInterceptorGenerator#generate)

    NoOpGenerator:不支持(NoOpGenerator#generate)

  2. MethodInterceptor 应用的方法比较特殊,和普通的不一样

    • 属性中多了一个MethodProxy的引用,并且还多了一个以CGLIB开头,中间是方法名字,后面是Proxy结尾的方法,在这个方法里面直接调用了父类的方法。

  • 多的这个方法有什么用?创建的MethodProxy有什么用?

    创建的MethodProxy是要通过MethodInterceptor传递的,我们在日常用的时候可以直接调用MethodProxy的invokeSuper,来调用父类(被代理的类)的方法。

    这个操作就会调用到多出来的这个方法(对比到上图中就是GLIB$lipu1$2方法)。首先调用super肯定不能直接调用到lipu1方法。如果调用到,就陷入到循环里面了。这就像在JDK-proxy的时候,在InvocationHandler里面通过第一个参数(proxy)来做调用会导致栈溢出,因为陷入到无限套娃里面了。

所以,就得单独搞一个方法,不要走MethodInterceptor的拦截操作。就不会有栈溢出的问题了。此外,MethodProxy还有别的作用,可以通过MethodProxy来调用指定对象的目标方法(对应的就是invoke(Object,Object[]))方法。在利用MethodProxy做调用的时候,这个过程还会生成两个代理类。通过这两代理类做调用。

  1. MethodProxy解释

    方法和属性都在上面展示了,这里说几个问题

    • 代理对象中的MethodProxy赋值操作

      具体的代码在MethodInterceptorGenerator#generate里面。会在代理类里面静态的引用,在静态代码块里面会通过MethodProxy#create(Class c1, Class c2, String desc, String name1, String name2)来创建。方法的参数从左到右为,被代理类对象,代理类对象,方法签名(方法参数,返回值等等),属于被代理对象方法签名一样的方法名称,属于代理对象方法签名一样的方法名称。

      现在看起来有点模糊,在之后的文章里面会详细的解释清楚的。

    • 在通过MethodProxy来调用方法的时候,也会创建动态的创建两个类。

      具体的代码在MethodProxy#helper方里面。在每次调用MethodProxy的invoke或者invokeSuper的时候,都会调用init方法,init方法里面会调用到helper方法。在这里面会创建一个类。

         private static FastClass helper(CreateInfo ci, Class type) {FastClass.Generator g = new FastClass.Generator();g.setType(type);g.setClassLoader(ci.c2.getClassLoader());g.setNamingPolicy(ci.namingPolicy);g.setStrategy(ci.strategy);g.setAttemptLoad(ci.attemptLoad);return g.create();}
      

      这个Generator是FastClass的内部类,也是继承了AbstractClassGenerator,可以生成类。

  2. 代理类中方法名字生成的逻辑在哪里,class文件的命名是什么样的规则?

  • NamingPolicy接口,用来生成class文件的名字,DefaultNamingPolicy是它的默认的实现类。
  • 方法名字生成逻辑和代码生成逻辑

主要在CallbackGenerator的实现类里面,通过不同的实现类,来生成不同类型的代码。在这里面会通过Context来获取字段的信息。

  • 静态方法名字生成逻辑

生成的代理类

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package net.sf.cglib.samples.simple;import java.lang.reflect.Method;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.core.Signature;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Dispatcher;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.FixedValue;
import net.sf.cglib.proxy.InvocationHandler;
import net.sf.cglib.proxy.LazyLoader;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
import net.sf.cglib.proxy.ProxyRefDispatcher;
import net.sf.cglib.proxy.UndeclaredThrowableException;
// 生成的代理类会继承要代理的类,并且实现Factory接口
public class Bean$$EnhancerByCGLIB$$d79f67a6 extends Bean implements Factory {// 标志位,表示是否初始化过,默认值是falseprivate boolean CGLIB$BOUND;public static Object CGLIB$FACTORY_DATA;// 利用ThreadLocal来存储Callback[]private static final ThreadLocal CGLIB$THREAD_CALLBACKS;// Callback[] private static final Callback[] CGLIB$STATIC_CALLBACKS;// 下面的这几个属性都是在创建代理对象的时候,通过Enhancer传递进来的Callback// 传递进来的dispatchprivate Dispatcher CGLIB$CALLBACK_0;//传递进来的MethodInterceptorprivate MethodInterceptor CGLIB$CALLBACK_1;// InvocationHandlerprivate InvocationHandler CGLIB$CALLBACK_2;private LazyLoader CGLIB$CALLBACK_3;private FixedValue CGLIB$CALLBACK_4;private NoOp CGLIB$CALLBACK_5;private ProxyRefDispatcher CGLIB$CALLBACK_6;// LazyLoader的引用的返回值的引用private static Object CGLIB$CALLBACK_FILTER;//liupu1方法的引用,而且这个引用是属于Bean对象的private static final Method CGLIB$lipu1$2$Method;//MethodProxy对象,可以看下面的CGLIB$STATICHOOK1方法,va1是Bean的class对象,var0是当前代理对象的class对象。// ()Ljava/lang/String;是方法的签名,lipu1和CGLIB$lipu1$2是不同的类对象的不同方法名字。private static final MethodProxy CGLIB$lipu1$2$Proxy;// 空参数对象,这就一个默认值private static final Object[] CGLIB$emptyArgs;// bean对象的jump方法引用private static final Method CGLIB$jump$5;// lazyLoader加载引用关系private Object CGLIB$LAZY_LOADER_3;static void CGLIB$STATICHOOK1() {// 赋值CGLIB$THREAD_CALLBACKS = new ThreadLocal();CGLIB$emptyArgs = new Object[0];Class var0 = Class.forName("net.sf.cglib.samples.simple.Bean$$EnhancerByCGLIB$$d79f67a6");Class var1;CGLIB$lipu1$2$Method = ReflectUtils.findMethods(new String[]{"lipu1", "()Ljava/lang/String;"}, (var1 = Class.forName("net.sf.cglib.samples.simple.Bean")).getDeclaredMethods())[0];CGLIB$lipu1$2$Proxy = MethodProxy.create(var1, var0, "()Ljava/lang/String;", "lipu1", "CGLIB$lipu1$2");CGLIB$jump$5 = Class.forName("net.sf.cglib.samples.simple.Bean").getDeclaredMethod("jump");}//sayHello用的callback是Dispatcher, public final String sayHello(String var1) {// 每个变量都是关联好的,在什么方法用什么callback都是确定好的,Dispatcher var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return ((Bean)var10000.loadObject()).sayHello(var1);}// public final boolean equals(Object var1) {Dispatcher var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000.loadObject().equals(var1);}public final String toString() {Dispatcher var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000.loadObject().toString();}public final int hashCode() {Dispatcher var10000 = this.CGLIB$CALLBACK_0;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_0;}return var10000.loadObject().hashCode();}// 要注意这个方法,这是 MethodProxy CGLIB$lipu1$2$Proxy属性里面的,在通过MethodProxy.invokeSuper的时候会调用到这个方法final String CGLIB$lipu1$2() {return super.lipu1();}// lipu1用的是methodInterceptor,在调用的时候会将CGLIB$lipu1$2$Proxy传递过去,并且,因为这个方法没有入参,    public final String lipu1() {MethodInterceptor var10000 = this.CGLIB$CALLBACK_1;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_1;}return var10000 != null ? (String)var10000.intercept(this, CGLIB$lipu1$2$Method, CGLIB$emptyArgs, CGLIB$lipu1$2$Proxy) : super.lipu1();}//静态方法,获取MethodProxy,通过方法的签名,这个签名对象有俩个字段,名字描述public static MethodProxy CGLIB$findMethodProxy(Signature var0) {String var10000 = var0.toString();switch(var10000.hashCode()) {case -286557062:if (var10000.equals("lipu1()Ljava/lang/String;")) {return CGLIB$lipu1$2$Proxy;}}return null;}// 用的是invocationHandlerpublic final String jump() {try {InvocationHandler var10000 = this.CGLIB$CALLBACK_2;// 这是做初始化操作的if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_2;}return (String)var10000.invoke(this, CGLIB$jump$5, new Object[0]);} catch (Error | RuntimeException var1) {throw var1;} catch (Throwable var2) {throw new UndeclaredThrowableException(var2);}}// 用的是lazyLoaderpublic final String hhhh() {// 它调用的是CGLIB$LOAD_PRIVATE_3方法,然后再调用hhh方法//CGLIB$LOAD_PRIVATE_3在下面方法声明,在它里面会先看是否调用过,没有调用过,才会调用loadObject,。通过loadObject返回的对象来// 调用hhh方法return ((Bean)this.CGLIB$LOAD_PRIVATE_3()).hhhh();}private final synchronized Object CGLIB$LOAD_PRIVATE_3() {Object var10000 = this.CGLIB$LAZY_LOADER_3;if (var10000 == null) {LazyLoader var10001 = this.CGLIB$CALLBACK_3;if (var10001 == null) {CGLIB$BIND_CALLBACKS(this);var10001 = this.CGLIB$CALLBACK_3;}var10000 = this.CGLIB$LAZY_LOADER_3 = var10001.loadObject();}return var10000;}// 用的是fixedValue,这个比较重要,直接返回loadObject方法返回的值。public final String dadada() {FixedValue var10000 = this.CGLIB$CALLBACK_4;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_4;}return (String)var10000.loadObject();}
// proxyRefDispatcher 在调用的时候,会将代理对象传递过去,还是和之前一样,做调用public final String sasasasa() {ProxyRefDispatcher var10000 = this.CGLIB$CALLBACK_6;if (var10000 == null) {CGLIB$BIND_CALLBACKS(this);var10000 = this.CGLIB$CALLBACK_6;}return ((Bean)var10000.loadObject(this)).sasasasa();}// 构造方法public Bean$$EnhancerByCGLIB$$d79f67a6() {CGLIB$BIND_CALLBACKS(this);}//给ThreadLoacal设置callBack[]public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] var0) {CGLIB$THREAD_CALLBACKS.set(var0);}// 改变callback[],注意,看这个名字有一个static,上面的名字里面有一个Threadpublic static void CGLIB$SET_STATIC_CALLBACKS(Callback[] var0) {CGLIB$STATIC_CALLBACKS = var0;}// 私有静态方法,用这个方法来给CGLIB$CALLBACK_6这些赋值,首先会从ThreadLocal中获取值,再回从静态的callback[]里面获取值private static final void CGLIB$BIND_CALLBACKS(Object var0) {Bean$$EnhancerByCGLIB$$d79f67a6 var1 = (Bean$$EnhancerByCGLIB$$d79f67a6)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;}}// 赋值Callback[] var10001 = (Callback[])var10000;var1.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)((Callback[])var10000)[6];var1.CGLIB$CALLBACK_5 = (NoOp)var10001[5];var1.CGLIB$CALLBACK_4 = (FixedValue)var10001[4];var1.CGLIB$CALLBACK_3 = (LazyLoader)var10001[3];var1.CGLIB$CALLBACK_2 = (InvocationHandler)var10001[2];var1.CGLIB$CALLBACK_1 = (MethodInterceptor)var10001[1];var1.CGLIB$CALLBACK_0 = (Dispatcher)var10001[0];}}// 这个方法是Factory接口的方法,所有通过Enhancer生成的代理类都实现了这个接口,利用这个接口就可以快速的创建实例,// 改变callback,获取callbackpublic Object newInstance(Callback[] var1) {CGLIB$SET_THREAD_CALLBACKS(var1);Bean$$EnhancerByCGLIB$$d79f67a6 var10000 = new Bean$$EnhancerByCGLIB$$d79f67a6();CGLIB$SET_THREAD_CALLBACKS((Callback[])null);return var10000;}public Object newInstance(Callback var1) {throw new IllegalStateException("More than one callback object required");}public Object newInstance(Class[] var1, Object[] var2, Callback[] var3) {CGLIB$SET_THREAD_CALLBACKS(var3);Bean$$EnhancerByCGLIB$$d79f67a6 var10000 = new Bean$$EnhancerByCGLIB$$d79f67a6;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);Object var10000;switch(var1) {case 0:var10000 = this.CGLIB$CALLBACK_0;break;case 1:var10000 = this.CGLIB$CALLBACK_1;break;case 2:var10000 = this.CGLIB$CALLBACK_2;break;case 3:var10000 = this.CGLIB$CALLBACK_3;break;case 4:var10000 = this.CGLIB$CALLBACK_4;break;case 5:var10000 = this.CGLIB$CALLBACK_5;break;case 6:var10000 = this.CGLIB$CALLBACK_6;break;default:var10000 = null;}return (Callback)var10000;}public void setCallback(int var1, Callback var2) {switch(var1) {case 0:this.CGLIB$CALLBACK_0 = (Dispatcher)var2;break;case 1:this.CGLIB$CALLBACK_1 = (MethodInterceptor)var2;break;case 2:this.CGLIB$CALLBACK_2 = (InvocationHandler)var2;break;case 3:this.CGLIB$CALLBACK_3 = (LazyLoader)var2;break;case 4:this.CGLIB$CALLBACK_4 = (FixedValue)var2;break;case 5:this.CGLIB$CALLBACK_5 = (NoOp)var2;break;case 6:this.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)var2;}}public Callback[] getCallbacks() {CGLIB$BIND_CALLBACKS(this);return new Callback[]{this.CGLIB$CALLBACK_0, this.CGLIB$CALLBACK_1, this.CGLIB$CALLBACK_2, this.CGLIB$CALLBACK_3, this.CGLIB$CALLBACK_4, this.CGLIB$CALLBACK_5, this.CGLIB$CALLBACK_6};}public void setCallbacks(Callback[] var1) {this.CGLIB$CALLBACK_0 = (Dispatcher)var1[0];this.CGLIB$CALLBACK_1 = (MethodInterceptor)var1[1];this.CGLIB$CALLBACK_2 = (InvocationHandler)var1[2];this.CGLIB$CALLBACK_3 = (LazyLoader)var1[3];this.CGLIB$CALLBACK_4 = (FixedValue)var1[4];this.CGLIB$CALLBACK_5 = (NoOp)var1[5];this.CGLIB$CALLBACK_6 = (ProxyRefDispatcher)var1[6];}static {CGLIB$STATICHOOK1();}
}

到此,结束了。

关于博客这件事,我是把它当做我的笔记,里面有很多的内容反映了我思考的过程,因为思维有限,不免有些内容有出入,如果有问题,欢迎指出。一同探讨。谢谢

cglib创建代理对象(1)相关推荐

  1. 使用cglib创建代理对象

    在上一篇文章中,我讨论了基于标准Java的代理对象. 当您要在实现接口的对象上具有方法调用处理程序时,可以使用这些方法. Java反射代理的创建要求您具有一个实现接口的对象. 我们要代理的对象已经失控 ...

  2. Spring AOP 源码分析 - 创建代理对象

    1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...

  3. 使用djcproxy创建代理对象

    在过去的几周中,我展示了如何使用Java Reflection API和cglib创建代理对象. 在本文中,我将向您展示如何使用djcproxy做到这一点. 哦,不是,另一个代理实现! 除了我创建此代 ...

  4. Spring AOP源码(2)—AspectJAwareAdvisorAutoProxyCreator创建代理对象【两万字】

      基于最新Spring 5.x,介绍了Spring AOP中的AspectJAwareAdvisorAutoProxyCreator自动代理创建者的工作流程,对于创建代理对象的源码进行了深度分析! ...

  5. CGLIb 创建代理

    CGLIb 创建代理 创建回调 创建代理(通过增强器和回调接口) 设置回调 CGLib总结 代理对象通过继承目标对象来封装目标对象的实现 CGlib 拦截的实现--在执行目标方法前判断拦截器是否存在并 ...

  6. CGLIB动态代理对象执行流程分析

    前言 都说CGLIB动态代理对象执行方法的速度相较于JDK动态代理更快,那么为什么更快,实际是因为CGLIB中采用了FastClass机制,本篇文章将对CGLIB动态代理对象执行某一个方法的流程进行分 ...

  7. 【设计模式】代理模式 ( 动态代理使用流程 | 创建目标对象 | 创建被代理对象 | 创建调用处理程序 | 动态创建代理对象 | 动态代理调用 )

    文章目录 前言 一.静态代理的弊端 二.动态代理的优势 三.动态代理使用流程 1.目标对象接口 2.被代理对象 3.调用处理程序 4.客户端 四.动态生成 代理对象 类 的 字节码 文件数据 前言 代 ...

  8. MyBatis运行原理(三)接口式编程及创建代理对象原理分析

    一.面向接口开发步骤 定义代理接口,将操作数据库的方法定义在代理接口中. 在SQL 映射文件中编写SQL 语句. 将SQL 映射文件注册在MyBatis 的全局配置文件中. 编写测试代码. 二.环境准 ...

  9. CGLIB 实现代理对象API

    转载自 CGLIB 实现代理对象API 1. 加入库 cglib库 cglib-2.2.jar asm库(cglib 需要asm库,如果没有加入asm的jar文件,就会报asm错误) asm-3.1. ...

最新文章

  1. YOLO在升级 | PP-YOLO v2开源致敬YOLOV4携带Tricks又准又快地归来(附论文与源码)...
  2. R语言dataframe获取每个字段(特征)的数据类型实战:使用sapply函数获取每个字段(特征)的数据类型、通过柱状图可视化特征的种类以及个数
  3. java 向下转型_Java_向下转型
  4. cleanmymac 4.2_15北师大版八年级物理上册4.2节乐音微课视频|知识点|练习
  5. 【前端分享】jQuery.lazyload详解(转)
  6. linux cgoup内存限制,Linux Cgroup系列(05):限制cgroup的CPU使用(subsystem之cpu)
  7. Div+CSS布局入门教程(四) 页面顶部制作之二
  8. python面相对象编程超市系统_python面向对象编程: 面向对象版学员管理系统
  9. ant-design 本地web版本下载_bilibili 哔哩哔哩视频如何下载到电脑的 3 种方法
  10. 按工作日加减天数,忽略星期六日
  11. php $GLOBALS 超全局变量的理解
  12. docker运行jenkins挂掉_docker搭建jenkins
  13. 初中数学最全几何模型_初中数学几何模型秘籍.pdf
  14. pandas训练集测试集划分_用pandas划分数据集实现训练集和测试集
  15. 什么是 Rax,以及 Rax 的特点
  16. 【从蛋壳到满天飞】JS 数据结构解析和算法实现-链表
  17. VAD、KWS、ASR
  18. 二分查找总结——左闭右开区间和左闭右闭区间(C++语言)
  19. 数字图像处理(1)-图片信息获取和RGB-HSI
  20. 安装了向日葵或TeamViewer导致系统亮度无法调节

热门文章

  1. java之静态代理模式
  2. 锐龙内战,强强对决 —— MateBook 13 AMD 横评 小新 Pro 13 AMD
  3. php查找/过滤一段文字中的违禁词敏感词
  4. 安卓集合和数组互相转换
  5. [ZT]grub4dos初级教程-入门篇
  6. 精品慕课资源推荐线性代数
  7. mysql strict_关于mysql 严格模式 Strict Mode的说明讲解
  8. 模仿猫眼电影静态网页展示2
  9. Caption Anything:细粒度可控的图像描述,试试解读清明上河图!
  10. 如何利用Reveal神器查看各大APP UI搭建层级