• Spring CGLlB动态代理


    通过学习《Spring JDK动态代理》一节可以了解到,JDK 动态代理使用起来非常简单,但是 JDK 动态代理的目标类必须要实现一个或多个接口,具有一定的局限性。如果不希望实现接口,可以使用 CGLIB代理。

    CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它被许多 AOP 框架所使用,其底层是通过使用一个小而快的字节码处理框架 ASM(Java 字节码操控框架)转换字节码并生成新的类。使用 CGLIB 需要导入 CGLIB 和 ASM 包,即 asm-x.x.jar 和 CGLIB-x.x.x.jar 。如果您已经导入了 Spring 的核心包 spring-core-x.x.x.RELEASE.jar,就不用再导入 asm-x.x.jar 和 cglib-x.x.x.jar 了。

    Spring 核心包中包含 CGLIB 和 asm,也就是说 Spring 核心包已经集成了 CGLIB 所需要的包,所以在开发中不需要另外导入asm-x.x.jar 和 cglib-x.x.x.jar 包了。

    示例

    下面使用 Eclipse IDE 演示 CGLIB 动态代理的使用,步骤如下:

    • 创建 SpringDemo 项目,并在 src 目录下创建 net.biancheng 包。
    • 导入相关 JAR 包。
    • 在 net.biancheng 包下创建 UserManager(用户管理接口)、UserManagerImpl(用户管理接口实现类)、MyAspect(切面类)和 CGLIBProxy(动态代理类)。
    • 运行 SpringDemo 项目。


    UserManager 类代码如下。

    package net.biancheng;
    
    public interface UserManager {
       
        // 新增用户抽象方法
        void addUser(String userName, String password);
    
        // 删除用户抽象方法
        void delUser(String userName);
    
    }

    UserManagerImpl 类代码如下。

    package net.biancheng;
    
    public class UserManagerImpl implements UserManager {
    
        @Override
        public void addUser(String userName, String password) {
            System.out.println("正在执行添加用户方法");
            System.out.println("用户名称: " + userName + " 密码: " + password);
    
        }
    
        @Override
        public void delUser(String userName) {
            System.out.println("正在执行删除用户方法");
            System.out.println("用户名称: " + userName);
        }
    
    }

    MyAspect 类代码如下。

    package net.biancheng;
    
    public class MyAspect {
        public void myBefore() {
            System.out.println("方法执行之前");
        }
    
        public void myAfter() {
            System.out.println("方法执行之后");
        }
    }

    CglibProxy 类代码如下。

    package net.biancheng;
    
    import java.lang.reflect.Method;
    
    import org.springframework.CGLIB.proxy.Enhancer;
    import org.springframework.CGLIB.proxy.MethodInterceptor;
    import org.springframework.CGLIB.proxy.MethodProxy;
    
    /**
    * CGLIB动态代理,实现MethodInterceptor接口
    *
    * @author 编程帮
    *
    */
    public class CglibProxy implements MethodInterceptor {
        private Object target;// 需要代理的目标对象
        final MyAspect myAspect = new MyAspect();
    
        // 重写拦截方法
        @Override
        public Object intercept(Object obj, Method method, Object[] arr, MethodProxy proxy) throws Throwable {
            myAspect.myBefore();
            Object invoke = method.invoke(target, arr);// 方法执行,参数:target目标对象 arr参数数组
            myAspect.myAfter();
            return invoke;
        }
    
        // 定义获取代理对象方法
        public Object getCglibProxy(Object objectTarget) {
            // 为目标对象target赋值
            this.target = objectTarget;
            Enhancer enhancer = new Enhancer();
            // 设置父类,因为CGLIB是针对指定的类生成一个子类,所以需要指定父类
            enhancer.setSuperclass(objectTarget.getClass());
            enhancer.setCallback(this);// 设置回调
            Object result = enhancer.create();// 创建并返回代理对象
            return result;
        }
    
        public static void main(String[] args) {
            CglibProxy cglib= new CglibProxy();// 实例化CglibBProxy对象
            UserManager user = (UserManager) cglib.getCglibProxy(new UserManagerImpl());// 获取代理对象
            user.addUser("bianchengbang", "www.biancheng.net"); // 执行新增方法
            user.delUser("bianchengbang"); // 执行删除方法
        }
    
    }

    运行结果如下。

    方法执行之前
    正在执行添加用户方法
    用户名称: bianchengbang 密码: www.biancheng.net
    方法执行之后
    方法执行之前
    正在执行删除用户方法
    用户名称: bianchengbang
    方法执行之后

    JDK代理和CGLIB代理的区别

    JDK 动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 InvokeHandler 来处理。而 CGLIB 动态代理是利用 ASM 开源包,加载代理对象类的 class 文件,通过修改其字节码生成子类来处理。

    JDK 动态代理只能对实现了接口的类生成代理,而不能针对类。

    CGLIB 是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法不能声明成 final 类型。

    JDK动态代理特点

    • 代理对象必须实现一个或多个接口
    • 以接口的形式接收代理实例,而不是代理类

    CGLIB动态代理特点

    • 代理对象不能被 final 修饰
    • 以类或接口形式接收代理实例

    JDK与CGLIB动态代理的性能比较

    生成代理实例性能:JDK > CGLIB
    代理实例运行性能:JDK > CGLIB

    http://c.biancheng.net/spring/cglib-proxy.html

  • 相关阅读:
    (转载)C++ string中find() ,rfind() 等函数 用法总结及示例
    UVA 230 Borrowers (STL 行读入的处理 重载小于号)
    UVA 12100 打印队列(STL deque)
    uva 12096 The SetStack Computer(STL set的各种库函数 交集 并集 插入迭代器)
    uva 1592 Database (STL)
    HDU 1087 Super Jumping! Jumping! Jumping!
    hdu 1176 免费馅饼
    HDU 1003 Max Sum
    转战HDU
    hust 1227 Join Together
  • 原文地址:https://www.cnblogs.com/emanlee/p/15146924.html
Copyright © 2020-2023  润新知