zoukankan      html  css  js  c++  java
  • 性能优于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。
  • 相关阅读:
    Blazor Webassembly本地化的实现
    一分钟搞清C++中的指向常量的指针和常量型指针
    如何使新Edge和旧Edge并行使用
    Build 2020上公布的C# 9.0 新特性
    C# 8.0 新特性之二:接口默认实现
    如何用代码来快速批量下载人教社中小学电子教材
    三大常用数据库事务详解之三:事务运行模式
    三大常用关系型数据库事务详解之二:基本事务命令
    三大关系型数据库事务详解之一:基本概念
    自然语言处理学习笔记之一:概要
  • 原文地址:https://www.cnblogs.com/binyue/p/12268163.html
Copyright © 2011-2022 走看看