zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    JVM调优之Tomcat启动参数配置及详解
    项目启动部署时报错:java.lang.NoSuchMethodError
    Springboot系列:@SpringBootApplication注解
    Tomcat下部署SpringBoot
    springboot 使用传统方式部署
    Spring Boot 学习笔记一(SpringBoot启动过程)
    Spring Boot【快速入门】
    Windows系统CPU内存网络性能统计第一篇 内存
    MinGW-w64非官方编译器集成安装包(很清楚)
    SyncML是一平台无关的信息同步标准协议集
  • 原文地址:https://www.cnblogs.com/emanlee/p/15146924.html
Copyright © 2011-2022 走看看