`
truelove12358
  • 浏览: 77626 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

Spring AOP原理解析、CGLIB解析

 
阅读更多


Spring AOP原理解析

原文:http://blog.jobbole.com/28791/


笔记:


简介:AOP(Aspect Orient Programming),也就是面向方面编程,作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表;而动态代理则以 Spring AOP 为代表。本文会从 AspectJ 分析起,逐渐深入,并介绍 CGLIB 来介绍 Spring AOP 框架的实现原理。

AOP(Aspect Orient Programming),作为面向对象编程的一种补充,广泛应用于处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理则可分为静态代理和动态代理两大类,其中静态代理是指使用 AOP 框架提供的命令进行编译,从而在编译阶段就可生成 AOP 代理类,因此也称为编译时增强;而动态代理则在运行时借助于 JDK 动态代理、CGLIB 等在内存中“临时”生成 AOP 动态代理类,因此也被称为运行时增强。

Spring AOP 实现原理与 CGLIB 应用


Spring AOP 原理剖析

通过Spring AOP配置使用可以知道:

AOP 代理其实是由 AOP 框架动态生成的一个对象,该对象可作为目标对象使用。AOP 代理包含了目标对象的全部方法,但 AOP 代理中的方法与目标对象的方法存在差异:AOP 方法在特定切入点添加了增强处理,并回调了目标对象的方法。

AOP 代理所包含的方法与目标对象的方法示意图如图 3 所示。

图 3.AOP 代理的方法与目标对象的方法

Spring AOP 实现原理与 CGLIB 应用

Spring 的 AOP 代理由 Spring 的 IoC 容器负责生成、管理,其依赖关系也由 IoC 容器负责管理。因此,AOP 代理可以直接使用容器中的其他 Bean 实例作为目标,这种关系可由 IoC 容器的依赖注入提供。

纵观 AOP 编程,其中需要程序员参与的只有 3 个部分:

● 定义普通业务组件。

●定义切入点,一个切入点可能横切多个业务组件。

●定义增强处理,增强处理就是在 AOP 框架为普通业务组件织入的处理动作。

上面 3 个部分的第一个部分是最平常不过的事情,无须额外说明。那么进行 AOP 编程的关键就是定义切入点和定义增强处理。一旦定义了合适的切入点和增强处理,AOP 框架将会自动生成 AOP 代理,而 AOP 代理的方法大致有如下公式:

代理对象的方法 = 增强处理 + 被代理对象的方法

在上面这个业务定义中,不难发现 Spring AOP 的实现原理其实很简单:AOP 框架负责动态地生成 AOP 代理类,这个代理类的方法则由 Advice 和回调目标对象的方法所组成。

对于前面提到的图 2 所示的软件调用结构:当方法 1、方法 2、方法 3 ……都需要去调用某个具有“横切”性质的方法时,传统的做法是程序员去手动修改方法 1、方法 2、方法 3 ……、通过代码来调用这个具有“横切”性质的方法,但这种做法的可扩展性不好,因为每次都要改代码。

于是 AOP 框架出现了,AOP 框架则可以“动态的”生成一个新的代理类,而这个代理类所包含的方法 1、方法 2、方法 3 ……也增加了调用这个具有“横切”性质的方法——但这种调用由 AOP 框架自动生成的代理类来负责,因此具有了极好的扩展性。程序员无需手动修改方法 1、方法 2、方法 3 的代码,程序员只要定义切入点即可—— AOP 框架所生成的 AOP 代理类中包含了新的方法 1、访法 2、方法 3,而 AOP 框架会根据切入点来决定是否要在方法 1、方法 2、方法 3 中回调具有“横切”性质的方法。


简而言之:AOP 原理的奥妙就在于动态地生成了代理类,这个代理类实现了图 2 的调用——这种调用无需程序员修改代码。


接下来介绍的 CGLIB 就是一个代理生成库,下面介绍如何使用 CGLIB 来生成代理类。


使用 CGLIB 生成代理类

CGLIB(Code Generation Library),简单来说,就是一个代码生成类库。它可以在运行时候动态是生成某个类的子类。

此处使用前面定义的 Chinese 类,现在改为直接使用 CGLIB 来生成代理,这个代理类同样可以实现 Spring AOP 代理所达到的效果。

下面先为 CGLIB 提供一个拦截器实现类:

清单 12.AroundAdvice.java

上面这个 AroundAdvice.java 的作用就像前面介绍的 Around Advice,它可以在调用目标方法之前、调用目标方法之后织入增强处理。

接下来程序提供一个 ChineseProxyFactory 类,这个 ChineseProxyFactory 类会通过 CGLIB 来为 Chinese 生成代理类:

清单 13.ChineseProxyFactory.java

上面粗体字代码就是使用 CGLIB 的 Enhancer 生成代理对象的关键代码,此时的 Enhancer 将以 Chinese 类作为目标类,以 AroundAdvice 对象作为“Advice”,程序将会生成一个 Chinese 的子类,这个子类就是 CGLIB 生成代理类,它可作为 Chinese 对象使用,但它增强了 Chinese 类的方法。

测试 Chinese 代理类的主程序如下:

清单 14.Main.java

运行上面主程序,看到如下输出结果:

执行目标方法之前,模拟开始事务 …

— 正在执行 sayHello 方法 —

执行目标方法之后,模拟结束事务 …

被改变的参数 Hello , CGLIB 新增的内容

执行目标方法之前,模拟开始事务 …

我正在吃 : 被改变的参数

执行目标方法之后,模拟结束事务 …

class lee.Chinese<nobr style="border:0px; padding:0px; margin:0px; max-width:none; max-height:none; min-width:0px; min-height:0px; vertical-align:0px"><span class="math" id="MathJax-Span-18" style="border:0px; margin:0px; padding:0px; display:inline-block; position:static; vertical-align:0px; width:11.06em"><span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:relative; vertical-align:0px; width:9em; height:0px"><span style="border:0px; margin:0px; padding:0px; font-size:18.45px; position:absolute; vertical-align:0px; top:-2.274em; left:0em"><span class="mrow" id="MathJax-Span-19" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px"><span class="mi" id="MathJax-Span-20" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">E<span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; overflow:hidden; height:1px; width:0.003em"></span></span><span class="mi" id="MathJax-Span-21" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">n</span><span class="mi" id="MathJax-Span-22" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">h</span><span class="mi" id="MathJax-Span-23" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">a</span><span class="mi" id="MathJax-Span-24" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">n</span><span class="mi" id="MathJax-Span-25" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">c</span><span class="mi" id="MathJax-Span-26" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">e</span><span class="mi" id="MathJax-Span-27" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">r</span><span class="mi" id="MathJax-Span-28" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">B</span><span class="mi" id="MathJax-Span-29" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">y<span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; overflow:hidden; height:1px; width:0.003em"></span></span><span class="mi" id="MathJax-Span-30" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">C<span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; overflow:hidden; height:1px; width:0.057em"></span></span><span class="mi" id="MathJax-Span-31" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">G</span><span class="mi" id="MathJax-Span-32" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">L</span><span class="mi" id="MathJax-Span-33" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">I<span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; overflow:hidden; height:1px; width:0.057em"></span></span><span class="mi" id="MathJax-Span-34" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">B</span></span><span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; width:0px; height:2.279em"></span></span></span><span style="border-width:0px; border-left-style:solid; border-color:initial; margin:0px; padding:0px; display:inline-block; position:static; vertical-align:-0.33em; overflow:hidden; width:0px; height:1.27em"></span></span></nobr>4bd097d9

从上面输出结果来看,CGLIB 生成的代理完全可以作为 Chinese 对象来使用,而且 CGLIB 代理对象的 sayHello()、eat() 两个方法已经增加了事务控制(只是模拟),这个 CGLIB 代理其实就是 Spring AOP 所生成的 AOP 代理。

通过程序最后的输出,不难发现这个代理对象的实现类是 lee.Chinese<nobr style="border:0px; padding:0px; margin:0px; max-width:none; max-height:none; min-width:0px; min-height:0px; vertical-align:0px"><span class="math" id="MathJax-Span-35" style="border:0px; margin:0px; padding:0px; display:inline-block; position:static; vertical-align:0px; width:11.06em"><span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:relative; vertical-align:0px; width:9em; height:0px"><span style="border:0px; margin:0px; padding:0px; font-size:18.45px; position:absolute; vertical-align:0px; top:-2.274em; left:0em"><span class="mrow" id="MathJax-Span-36" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px"><span class="mi" id="MathJax-Span-37" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">E<span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; overflow:hidden; height:1px; width:0.003em"></span></span><span class="mi" id="MathJax-Span-38" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">n</span><span class="mi" id="MathJax-Span-39" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">h</span><span class="mi" id="MathJax-Span-40" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">a</span><span class="mi" id="MathJax-Span-41" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">n</span><span class="mi" id="MathJax-Span-42" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">c</span><span class="mi" id="MathJax-Span-43" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">e</span><span class="mi" id="MathJax-Span-44" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">r</span><span class="mi" id="MathJax-Span-45" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">B</span><span class="mi" id="MathJax-Span-46" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">y<span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; overflow:hidden; height:1px; width:0.003em"></span></span><span class="mi" id="MathJax-Span-47" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">C<span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; overflow:hidden; height:1px; width:0.057em"></span></span><span class="mi" id="MathJax-Span-48" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">G</span><span class="mi" id="MathJax-Span-49" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">L</span><span class="mi" id="MathJax-Span-50" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">I<span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; overflow:hidden; height:1px; width:0.057em"></span></span><span class="mi" id="MathJax-Span-51" style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline; position:static; vertical-align:0px; font-family:MathJax_Math-italic">B</span></span><span style="border:0px; margin:0px; padding:0px; font-size:18.45px; display:inline-block; position:static; vertical-align:0px; width:0px; height:2.279em"></span></span></span><span style="border-width:0px; border-left-style:solid; border-color:initial; margin:0px; padding:0px; display:inline-block; position:static; vertical-align:-0.33em; overflow:hidden; width:0px; height:1.27em"></span></span></nobr>4bd097d9,这就是 CGLIB 所生成的代理类,这个代理类的格式与前面 Spring AOP 所生成的代理类的格式完全相同。

这就是 Spring AOP 的根本所在:Spring AOP 就是通过 CGLIB 来动态地生成代理对象,这个代理对象就是所谓的 AOP 代理,而 AOP 代理的方法则通过在目标对象的切入点动态地织入增强处理,从而完成了对目标方法的增强。

小结

AOP 广泛应用于处理一些具有横切性质的系统级服务,AOP 的出现是对 OOP 的良好补充,它使得开发者能用更优雅的方式处理具有横切性质的服务。不管是那种 AOP 实现,不论是 AspectJ、还是 Spring AOP,它们都需要动态地生成一个 AOP 代理类,区别只是生成 AOP 代理类的时机不同:AspectJ 采用编译时生成 AOP 代理类,因此具有更好的性能,但需要使用特定的编译器进行处理;而 Spring AOP 则采用运行时生成 AOP 代理类,因此无需使用特定编译器进行处理。由于 Spring AOP 需要在每次运行时生成 AOP 代理,因此性能略差一些。



CGLIB实现动态代理原理:

原文:http://blog.jobbole.com/105423/?utm_source=blog.jobbole.com&utm_medium=relatedPosts

jdk中的动态代理通过反射类ProxyInvocationHandler回调接口实现,要求委托类必须实现一个接口,只能对该类接口中定义的方法实现代理,这在实际编程中有一定的局限性。

cglib实现

使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码,下面通过一个例子看看使用CGLib如何实现动态代理。
1、定义业务逻辑

public class UserServiceImpl {  
    public void add() {  
        System.out.println("This is add service");  
    }  
    public void delete(int id) {  
        System.out.println("This is delete service:delete " + id );  
    }  
}

2、实现MethodInterceptor接口,定义方法的拦截器

public class MyMethodInterceptor implements MethodInterceptor {
    public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) throws Throwable {
        System.out.println("Before:" + method);  
        Object object = proxy.invokeSuper(obj, arg);
        System.out.println("After:" + method); 
        return object;
    }
}

3、利用Enhancer类生成代理类;

Enhancer enhancer = new Enhancer();  
enhancer.setSuperclass(UserServiceImpl.class);  
enhancer.setCallback(new MyMethodInterceptor());  
UserServiceImpl userService = (UserServiceImpl)enhancer.create();

4、userService.add()的执行结果:

Before: add
This is add service
After: add

代理对象的生成过程由Enhancer类实现,大概步骤如下:
1、生成代理类Class的二进制字节码;
2、通过Class.forName加载二进制字节码,生成Class对象;
3、通过反射机制获取实例构造,并初始化代理类对象。

cglib字节码生成

Enhancer是CGLib的字节码增强器,可以方便的对类进行扩展,内部调用GeneratorStrategy.generate方法生成代理类的字节码,通过以下方式可以生成class文件。

System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "C:\\\\Code\\\\whywhy\\\\target\\\\classes\\\\zzzzzz")

使用反编译工具 procyon查看代理类实现

java -jar procyon-decompiler-0.5.30.jar UserService$$EnhancerByCGLIB$$394dddeb;

反编译之后的代理类add方法实现如下:

import net.sf.cglib.core.Signature;
import net.sf.cglib.core.ReflectUtils;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;

// 
// Decompiled by Procyon v0.5.30
// 

public class UserService$$EnhancerByCGLIB$$394dddeb extends UserService implements Factory
{
    private boolean CGLIB$BOUND;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private MethodInterceptor CGLIB$CALLBACK_0;
    private static final Method CGLIB$add$0$Method;
    private static final MethodProxy CGLIB$add$0$Proxy;
    private static final Object[] CGLIB$emptyArgs;


    static void CGLIB$STATICHOOK2() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$emptyArgs = new Object[0];
        final Class<?> forName = Class.forName("UserService$$EnhancerByCGLIB$$394dddeb");
        final Class<?> forName3;
        CGLIB$add$0$Method = ReflectUtils.findMethods(new String[] { "add", "()V" }, (forName3 = Class.forName("UserService")).getDeclaredMethods())[0];
        CGLIB$add$0$Proxy = MethodProxy.create((Class)forName3, (Class)forName, "()V", "add", "CGLIB$add$0");
    }

    final void CGLIB$add$0() {
        super.add();
    }

    public final void add() {
        MethodInterceptor cglib$CALLBACK_2;
        MethodInterceptor cglib$CALLBACK_0;
        if ((cglib$CALLBACK_0 = (cglib$CALLBACK_2 = this.CGLIB$CALLBACK_0)) == null) {
            CGLIB$BIND_CALLBACKS(this);
            cglib$CALLBACK_2 = (cglib$CALLBACK_0 = this.CGLIB$CALLBACK_0);
        }
        if (cglib$CALLBACK_0 != null) {
            cglib$CALLBACK_2.intercept((Object)this, UserService$$EnhancerByCGLIB$$394dddeb.CGLIB$add$0$Method, UserService$$EnhancerByCGLIB$$394dddeb.CGLIB$emptyArgs, UserService$$EnhancerByCGLIB$$394dddeb.CGLIB$add$0$Proxy);
            return;
        }
        super.add();
    }

    static {
        CGLIB$STATICHOOK2();
    }
}

通过cglib生成的字节码相比jdk实现来说显得更加复杂。
1、代理类UserService$$EnhancerByCGLIB$$394dddeb继承了委托类UserSevice,且委托类的final方法不能被代理;
2、代理类为每个委托方法都生成两个方法,以add方法为例,一个是重写的add方法,一个是CGLIB$add$0方法,该方法直接调用委托类的add方法;
3、当执行代理对象的add方法时,会先判断是否存在实现了MethodInterceptor接口的对象cglib$CALLBACK_0,如果存在,则调用MethodInterceptor对象的intercept方法:

public Object intercept(Object obj, Method method, Object[] arg, MethodProxy proxy) {
    System.out.println("Before:" + method);  
    Object object = proxy.invokeSuper(obj, arg);
    System.out.println("After:" + method); 
    return object;
}

参数分别为:1、代理对象;2、委托类方法;3、方法参数;4、代理方法的MethodProxy对象。

4、每个被代理的方法都对应一个MethodProxy对象,methodProxy.invokeSuper方法最终调用委托类的add方法,实现如下:

public Object invokeSuper(Object obj, Object[] args) throws Throwable {
    try {
        init();
        FastClassInfo fci = fastClassInfo;
        return fci.f2.invoke(fci.i2, obj, args);
    } catch (InvocationTargetException e) {
        throw e.getTargetException();
    }
}

单看invokeSuper方法的实现,似乎看不出委托类add方法调用,在MethodProxy实现中,通过FastClassInfo维护了委托类和代理类的FastClass。

private static class FastClassInfo {
    FastClass f1;
    FastClass f2;
    int i1;
    int i2;
}

以add方法的methodProxy为例,f1指向委托类对象,f2指向代理类对象,i1和i2分别是方法add和CGLIB$add$0在对象中索引位置。

FastClass实现机制

FastClass其实就是对Class对象进行特殊处理,提出下标概念index,通过索引保存方法的引用信息,将原先的反射调用,转化为方法的直接调用,从而体现所谓的fast,下面通过一个例子了解一下FastClass的实现机制。
1、定义原类

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

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

2、定义Fast类

class FastTest {
    public int getIndex(String signature){
        switch(signature.hashCode()){
        case 3078479:
            return 1;
        case 3108270:
            return 2;
        }
        return -1;
    }

    public Object invoke(int index, Object o, Object[] ol){
        Test t = (Test) o;
        switch(index){
        case 1:
            t.f();
            return null;
        case 2:
            t.g();
            return null;
        }
        return null;
    }
}

在FastTest中有两个方法,getIndex中对Test类的每个方法根据hash建立索引,invoke根据指定的索引,直接调用目标方法,避免了反射调用。所以当调用methodProxy.invokeSuper方法时,实际上是调用代理类的CGLIB$add$0方法,CGLIB$add$0直接调用了委托类的add方法。

jdk和cglib动态代理实现的区别

1、jdk动态代理生成的代理类和委托类实现了相同的接口;
2、cglib动态代理中生成的字节码更加复杂,生成的代理类是委托类的子类,且不能处理被final关键字修饰的方法;
3、jdk采用反射机制调用委托类的方法,cglib采用类似索引的方式直接调用委托类方法;


分享到:
评论

相关推荐

    spring aop 原理解析

    【Spring AOP 原理解析】 Spring AOP(面向切面编程)是Spring框架的重要组成部分,它允许开发者定义“切面”来封装系统中的交叉关注点,如日志、事务管理、安全性等,从而提高代码的可复用性和可维护性。在Spring ...

    spring aop 源码解析

    《Spring AOP 源码解析》 Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架中的一个重要组成部分,它为开发者提供了一种方便的实现横切关注点的方式,如日志、事务管理等。AOP通过将这些关注...

    五、Spring源码分析——Spring Aop

    这对于理解Spring的工作原理,以及优化和扩展Spring AOP功能具有重要意义。 在实际开发中,Spring AOP的应用非常广泛,它可以极大地简化代码,提高代码的可维护性和可复用性。通过阅读和理解Spring AOP的源码,...

    spring ioc和aop原理流程图(详细)

    Spring 框架是Java开发中的核心框架,它主要由两个关键部分组成:IOC(Inversion of Control,控制反转)和AOP(Aspect Oriented Programming,面向切面编程)。这两个概念是Spring框架的核心特性,极大地简化了企业...

    spring aop 学习笔记

    本学习笔记将深入探讨Spring AOP的核心概念、工作原理以及实际应用。 1. **核心概念** - **切面(Aspect)**:切面是关注点的模块化,包含业务逻辑之外的横切关注点,如日志、事务管理。 - **连接点(Join Point...

    第3章 Spring AOP.ppt

    理解和掌握AOP的概念及其在Spring框架中的实现方式,包括基于XML和注解的配置方式,以及JDK动态代理和CGLIB代理的原理和使用。通过学习,应能独立实现AOP相关的功能,提升代码的可扩展性和可维护性。

    深入解析Spring AOP源码:从原理到实现,全方位掌握Java AOP编程精髓

    了解Spring AOP的源码有助于深入理解其工作原理。在源码解析中,我们通常会关注以下几个关键点: 1. 切面类的解析:如何识别和处理切面类,提取切点和通知信息。 2. 创建代理:根据目标对象的类型选择JDK动态代理或...

    springaop

    标题 "springaop" 暗示我们关注的是Spring框架中的AOP(面向切面编程)模块。在Spring框架中,AOP是一种强大的工具,它允许程序员定义“切面”,这些切面可以封装横切关注点,如日志、事务管理、性能监控等,将它们...

    spring aop的jar包

    5. **org.springframework.aop-3.0.5.RELEASE.jar**:这个文件是Spring AOP的核心实现,提供了切面、通知、代理等AOP概念的实现,以及AOP配置和解析的支持。 6. **org.springframework.expression-3.0.5.RELEASE....

    SpringAOP的源码解析.doc

    《Spring AOP源码解析》 Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许我们...通过阅读和理解Spring AOP的源码,我们可以更好地掌控AOP的工作原理,从而在实际开发中更加灵活地运用这一强大的工具。

    spring-aop AND proxy

    标签“源码”意味着这篇博客可能深入解析了Spring AOP的内部工作机制,包括如何通过代理机制实现切面的织入,以及Spring AOP的相关核心类如`Advised`、`ProxyFactoryBean`、`DefaultAdvisorAdapterRegistry`等。...

    Java spring AOP源码

    在探讨Spring AOP源码之前,我们首先需要了解Spring AOP的基本概念以及它的工作原理。面向切面编程(Aspect-Oriented Programming, AOP)是一种编程范式,它通过将横切关注点(cross-cutting concerns)从业务逻辑中...

    spring-aop.rar_aop1270_spring_spring aop

    本文将围绕Spring AOP的源码分析,探讨其核心概念、工作原理以及在实际开发中的应用。 一、AOP核心概念 1. 切面(Aspect):切面是关注点的模块化,通常包含一组通知(advises)和一个切入点(pointcut)定义。 2...

    Spring AOP源码深度解析:掌握Java高级编程核心技术

    本文将深入探讨Spring AOP的实现原理及其在Java高级编程中的应用。 首先,理解AOP的关键概念至关重要。**动态代理**是AOP的基础,Spring支持两种动态代理方式:JDK动态代理和CGLIB代理。JDK动态代理适用于目标对象...

    spring-aop.jar

    本文将围绕spring-aop.jar这个核心组件,详细探讨Spring AOP的原理、使用方式以及它在实际开发中的应用。 一、AOP概述 AOP是一种编程范式,旨在减少代码冗余,提高模块间的解耦度,通过将关注点分离到不同的切面中...

    spring切面AOP所使用的jar包

    Spring框架的AOP(面向切面编程)是其核心特性之一,它允许开发者在不修改原有代码的情况下,通过切面来插入额外的功能,比如...在实际开发中,理解并掌握AOP原理和应用,对于提升软件设计的灵活性和可扩展性至关重要。

    SpringAOP+AspectJ

    **Spring AOP与AspectJ详解** 在现代软件开发中,面向切面编程(Aspect-Oriented Programming,简称AOP)是一种强大的设计模式...通过深入理解AOP原理和实践,我们可以更好地利用这些工具来提高软件质量,降低复杂性。

    Java进阶之SpringAOP源码深度剖析共17页.pd

    通过对Spring AOP源码的深入分析,我们可以了解到其内部是如何通过代理模式和反射技术实现对方法调用的拦截,以及如何解析和执行切点表达式,理解通知的执行流程等。这些深入理解对于优化性能、排查问题以及自定义...

    spring-aop源码

    导入Spring AOP源码到Eclipse工程后,可以通过调试和阅读源码,了解通知的创建、切点的匹配、代理的生成等核心流程,进一步理解Spring AOP的工作原理。 总结,Spring AOP源码的探索有助于开发者深入理解面向切面...

Global site tag (gtag.js) - Google Analytics