SpringCGLlB动态代理

开课吧开课吧锤锤2021-08-10 11:31

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

CGLIB(CodeGenerationLibrary)是一个高性能开源的代码生成包,它被许多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了。  

SpringCGLlB动态代理

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

示例  

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

创建SpringDemo项目,并在src目录下创建net.kaikeba包。  

导入相关JAR包。  

在net.kaikeba包下创建UserManager(用户管理接口)、UserManagerImpl(用户管理接口实现类)、MyAspect(切面类)和CGLIBProxy(动态代理类)。  

运行SpringDemo项目。  

UserManager类代码如下。

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

UserManagerImpl类代码如下。 

package net.kaikeba;
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.kaiekeba;
public class MyAspect {
    public void myBefore() {
        System.out.println("方法执行之前");
    }
    public void myAfter() {
        System.out.println("方法执行之后");
    }
}

CglibProxy类代码如下。  

package net.kaikeba;
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("kaikeba", "https://www.kaikeba.com/"); // 执行新增方法
        user.delUser("kaikeba"); // 执行删除方法
    }
}

运行结果如下。  

方法执行之前
正在执行添加用户方法
用户名称: kaikeba 密码: https://www.kaikeba.com/
方法执行之后
方法执行之前
正在执行删除用户方法
用户名称: kaikeba
方法执行之后

JDK代理和CGLIB代理的区别  

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

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

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

JDK动态代理特点  

代理对象必须实现一个或多个接口  

以接口的形式接收代理实例,而不是代理类  

CGLIB动态代理特点  

代理对象不能被final修饰  

以类或接口形式接收代理实例  

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

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

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

以上就是开课吧广场小编为大家整理发布的“SpringCGLlB动态代理”一文,更多Java教程相关内容尽在开课吧广场Java教程频道!

SpringCGLlB动态代理

免责声明:本站所提供的内容均来源于网友提供或网络搜集,由本站编辑整理,仅供个人研究、交流学习使用。如涉及版权问题,请联系本站管理员予以更改或删除。
有用
分享
全部评论快来秀出你的观点
登录 后可发表观点…
发表
暂无评论,快来抢沙发!
高并发编程训练营