Реализация и принцип динамического прокси CGLIB (1)

Java

Во-первых, принцип реализации

  • Используя пакет с открытым исходным кодом ASM, загрузите файл класса реального класса объекта, сгенерируйте его подкласс, изменив байт-код, и перезапишите соответствующий метод родительского класса.

    Примечание: ASM — это платформа для прямого управления байт-кодом.

2. Метод реализации

  • 1) Определите обработчик перехвата. Реализуйте интерфейс MethodInterceptor и переопределите метод перехвата для обработки перехвата.
  • 2) Создание динамических прокси-классов. Измените байт-код файла класса прокси-объекта, чтобы сгенерировать подкласс.
    <dependency>
      <groupId>cglib</groupId>
      <artifactId>cglib-nodep</artifactId>
      <version>3.3.0</version>
      <scope>compile</scope>
    </dependency>
package com.java24k.example.target;

/**
 * @Description: 真实主题即被代理对象
 * @Author zhoufeng
 * @Date 2020/7/13 2:34
 * @version: V1.0
 */
public class TargetClass {

    public void targetInfo(){
        System.out.println("打印目标类信息");
     }
}

package com.java24k.example.interceptor;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Description: 代理拦截处理器
 * @Author zhoufeng
 * @Date 2020/7/13 2:30
 * @version: V1.0
 */
public class MyInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("------插入前置通知代码-------------");
        // 此处一定要使用proxy的invokeSuper方法来调用目标类的方法
        methodProxy.invokeSuper(o, objects);
        System.out.println("------插入后置处理代码-------------");
        return null;
    }
}
package com.java24k.example.test;

import com.java24k.example.interceptor.MyInterceptor;
import com.java24k.example.target.TargetClass;
import net.sf.cglib.proxy.Enhancer;

/**
 * @Description: 生成cglib代理测试类
 * @Author zhoufeng
 * @Date 2020/7/13 2:41
 * @version: V1.0
 */
public class CglibProxyTest {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        // 设置目标类
        enhancer.setSuperclass(TargetClass.class);
        // 设置拦截器对象
        enhancer.setCallback(new MyInterceptor());
        // 创建子类 即代理
        TargetClass targetClassProxy = (TargetClass) enhancer.create();
        targetClassProxy.targetInfo();
    }
}
------插入前置通知代码-------------
打印目标类信息
------插入后置处理代码-------------

Process finished with exit code 0

3. Механизм FastClass

В динамическом прокси JDK метод вызова целевого объекта использует отражение, а в динамическом прокси CGLIB используется механизм FastClass.

  • Использование FastClass: динамически генерируйте класс, который наследует FastClass, записывайте объект делегата в класс и напрямую вызывайте метод объекта делегата.
  • Логика FastClass: В динамическом классе, наследующем FastClass, индекс метода получается в соответствии с сигнатурой метода (имя метода + параметры метода), а метод целевого объекта вызывается в соответствии с индексом метода.
  • Преимущества FastClass: FastClass используется для замены отражения Java, что позволяет избежать проблемы медленных вызовов, вызванных отражением.

Во втором и третьем разделах мы проанализируем CGLIB для создания исходного кода динамического прокси и исходного кода FastClass.