• 性能优于JDK代理,CGLib如何实现动态代理


    按照代理的创建时期,代理类可以分为两种。
    静态代理:由程序员创建或特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
    动态代理:在程序运行时,运用反射机制动态创建而成。

    动态代理三种方式

    动态代理实现有三种方式,jdk动态代理(基于接口),cglib动态代理(基于继承),javassist(hibernate中使用这种方式)实现动态代理。

    JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢?
    这就需要CGLib了。

    cglib如何实现代理

    Cglib是一个优秀的动态代理框架,它的底层使用ASM在内存中动态的生成被代理类的子类,使用CGLIB即使代理类没有实现任何接口也可以实现动态代理功能。

    CGLib原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。

    CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高不少,但是CGLib在创建代理对象时所花费的时间却比JDK多得多,所以对于单例的对象,因为无需频繁创建对象,用CGLib合适,反之,使用JDK方式要更为合适一些。同时,由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

    cgLib动态代理实例

    下面演示一个动态代理的实例。

    导入maven 依赖

    cglib 是基于asm 字节修改技术。导入 cglib 会间接导入 asm, ant, ant-launcher 三个jar 包。

    <!-- cglib 动态代理依赖 begin -->
     <dependency>
       <groupId>cglib</groupId>
       <artifactId>cglib</artifactId>
       <version>3.2.5</version></dependency>
       <!-- cglib 动态代理依赖 stop -->
    

    CGLIB的核心类:

    • net.sf.cglib.proxy.Enhancer – 主要的增强类
    • net.sf.cglib.proxy.MethodInterceptor – 主要的方法拦截类,它是Callback接口的子接口,需要用户实现
    • net.sf.cglib.proxy.MethodProxy – JDK的java.lang.reflect.Method类的代理类,可以方便的实现对源对象方法的调用,如使用:
    • Object o = methodProxy.invokeSuper(proxy, args);//虽然第一个参数是被代理对象,也不会出现死循环的问题。

    实现一个业务类,注意,这个业务类并没有实现任何接口:

    public class HelloService {
     
        public HelloService() {
            System.out.println("HelloService构造");
        }
         
        public void sayHello() {
            System.out.println("HelloService:sayHello");
        }
    
    

    net.sf.cglib.proxy.MethodInterceptor接口是最通用的回调(callback)类型,它经常被基于代理的AOP用来实现拦截(intercept)方法的调用。这个接口只定义了一个方法
    public Object intercept(Object object, java.lang.reflect.Method method,
    Object[] args, MethodProxy proxy) throws Throwable;

    方法拦截器 实现 MethodInterceptor 接口:

    public class HelloServiceInterceptor implements MethodInterceptor{
     
        /**
         * sub:cglib生成的代理对象
         * method:被代理对象方法
         * objects:方法入参
         * methodProxy: 代理方法
         */
        @Override
        public Object intercept(Object sub, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("======插入前置通知======");
            Object object = methodProxy.invokeSuper(sub, objects);
            System.out.println("======插入后置通知======");
            return object;
        }
    
    

    测试类,生成CGLIB代理对象调用目标方法:

    public class CglibTest {
        public static void main(String[] args) {
            // 通过CGLIB动态代理获取代理对象的过程
            Enhancer enhancer = new Enhancer();
            // 设置enhancer对象的父类
            enhancer.setSuperclass(HelloService.class);
            // 设置enhancer的回调对象
            enhancer.setCallback(new HelloServiceInterceptor());
            // 创建代理对象
            HelloService proxy= (HelloService)enhancer.create();
            // 通过代理对象调用目标方法
            proxy.sayHello();
        }
    }
    
    

    Cglib 总结

    • CGlib可以传入接口也可以传入普通的类,接口使用实现的方式,普通类使用会使用继承的方式生成代理类.
    • 由于是继承方式,如果是 static方法,private方法,final方法等描述的方法是不能被代理的
    • 做了方法访问优化,使用建立方法索引的方式避免了传统JDK动态代理需要通过Method方法反射调用.
    • 提供callback 和filter设计,可以灵活地给不同的方法绑定不同的callback。编码更方便灵活。
    • CGLIB会默认代理Object中equals,toString,hashCode,clone等方法。比JDK代理多了clone。
  • 相关阅读:
    JBoss下配置数据源加密
    线程返回值的方式介绍
    @Async java 异步方法
    spring 源码下载地址
    springmvc maven 入门及页面拿不到controller的值 显示${message} el表达式不起作用
    mysql常用函数
    eclipse 开发常见问题集锦
    linux 常用命令及零散知识
    js一些注意事项
    liunx 免密登录远程主机
  • 原文地址:https://www.cnblogs.com/binyue/p/12268163.html
Copyright © 2020-2023  润新知