您的位置:

CGlib实现原理详解

一、CGlib代理原理

在面向对象编程中,代理模式是一种常用的设计模式。它可以在不改变原有对象代码的前提下,通过新增代理对象,在代理对象中增加一些其他的功能,从而提供更加完整、更加复杂的功能。CGlib代理是基于动态代理的一种实现方式,是Java中常用的代理技术之一。

动态代理和静态代理最大的区别就在于代理类的生成方式。静态代理需要人工编写代理类,而动态代理则可以在运行时动态生成代理类。Java JDK提供了一个Proxy类,可以通过Proxy的工厂方法newProxyInstance动态生成代理对象。

不过JDK提供的动态代理有一个限制,就是只能代理实现了接口的类。如果要代理没有实现接口的类,就要使用其他的代理技术。而CGlib是一种可以代理类的技术。使用CGlib实现动态代理,本质上是在运行时,通过字节码处理框架ASM,动态生成一个被代理类的子类,并覆盖其中的方法,达到代理的目的。

二、CGlib原理

CGlib,全称为Code Generation Library,是一个开源的非侵入式的Java字节码生成库。它允许在运行时对字节码进行操作,生成新的类,以实现例如AOP之类的功能。

与静态代理和JDK动态代理不同,CGlib在运行时动态生成被代理类的子类,并重写其中的方法。因此,对被代理类的方法访问是通过子类方法访问的,而不是被代理类方法访问的。子类方法可以通过调用父类方法实现对被代理类方法的访问。

CGlib生成子代理类的方式是在内存中构建代理类的所有方法的字节码,并将其转换成class对象,从而实现对被代理类方法的代理。由于CGlib是直接操作class字节码实现代理的,因此需要引入ASM字节码框架,用于处理Java字节码。

三、CGlib底层原理

CGlib底层运用Java字节码技术实现代理,下面简单介绍一下Java字节码的执行过程:

一是Java程序源代码被编译成Java字节码文件(.class文件)。

二是Java虚拟机(JVM)将Java字节码文件解释成机器指令。

三是CPU执行机器指令,进行计算操作。

CGlib底层实现通过ASM技术直接操作字节码来完成对代理对象的生成,主要分为以下几个步骤:

1、确定需要代理的类和方法,生成对应的MethodInterceptor实现类。

public class UserProxy implements MethodInterceptor {
    private Object target;
    public UserProxy(Object target) {
        this.target = target;
    }
    public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable {
        System.out.println("Before method invoke");
        Object result = method.invoke(target, args);
        System.out.println("After method invoke");
        return result;
    }
}

2、使用ASM库加载被代理类的字节码,并动态生成代理对象的子类。

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(target.getClass());
enhancer.setCallback(new UserProxy(target));
Object proxy = enhancer.create();

在这个过程中,我们需要在内存中先读取被代理类的二进制字节码文件,然后再解析出类信息,这个时候我们就要使用ASM库:

ClassReader classReader = new ClassReader(target.getClass().getName());
ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor classVisitor = new AddFieldAdapter(classWriter,
                Opcodes.ACC_PUBLIC, "hash", "I");
classReader.accept(classVisitor, ClassReader.SKIP_DEBUG);
byte[] data = classWriter.toByteArray();

四、CGlib底层实现原理

底层实现原理主要是通过ASM(a very small and fast Java bytecode manipulation framework)框架来直接操作数据字节码。ASM可以直接生成和修改字节码,也可以在字节码的生成和修改中提供一些帮助和支持。

ASM使用Visitor模式来操作字节码,它通过ClassVisitor和MethodVisitor类提供了访问类层次结构和方法级别元素的途径。

CGlib实现动态代理的过程如下:

1、创建Enhancer对象。

2、设置父类和回调方法。

Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);
enhancer.setCallback(new UserServiceInterceptor());

3、通过Enhancer对象的create()方法生成代理对象。

UserServiceImpl proxyUserService = (UserServiceImpl) enhancer.create();

4、调用代理对象方法。

String username = userSerivceimpl.getUserName();

五、CGlib动态代理原理

CGlib可以创建一个类的子类,并且在子类中采用方法拦截的技术拦截所有父类方法的调用。在拦截器中可以添加一些额外的逻辑。相比Java动态代理,CGlib不要求被代理类必须实现接口,它是基于类代理,对指定的类生成一个子类,并覆盖其中的方法来实现代理的功能。

在使用CGlib进行代理时,代理类和被代理类构成了继承关系。代理类继承被代理类,所以代理类拥有了被代理类的所有属性和方法,而且可以拦截被代理方法进行增强。

下面是一个CGlib动态代理实现的示例代码:

public class UserServiceInterceptor implements MethodInterceptor {
    private UserService userService;
    public UserServiceInterceptor(UserService userService) {
        this.userService = userService;
    }
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("begin method...");
        Object result = method.invoke(userService, objects);
        System.out.println("end method...");
        return result;
    }
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class); 
enhancer.setCallback(new UserServiceInterceptor(userService));
UserService userServiceProxy = (UserService) enhancer.create();

结束语

CGlib是一种非常常用的代理方式,通过字节码的修改,可以实现对被代理对象的增强和功能扩展。在使用CGlib进行代理时,我们需要深入了解其实现原理,灵活运用其底层知识,才能更好地发挥其代理作用。