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

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

动态代理三种方式

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

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

cglib如何实现代理

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

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

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。
相关文章
相关标签/搜索