1. Java

cglib

使用Java17 测试cglib:

首先在pom.xml文件中引入cglib依赖

<dependency>
       <groupId>cglib</groupId>
       <artifactId>cglib</artifactId>
       <version>3.3.0</version>
</dependency>

编写测试代码:

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

/**
 * @author BH6AOL
 * @version 1.0
 * @description: TODO
 * @date 2024-03-11 10:14
 */
public class Main {
    public void sayHello(Integer name){
        System.out.println("Hello " + name);
    }
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Main.class);
        enhancer.setCallback((MethodInterceptor) (o, method, objects, methodProxy) -> {
            System.out.println("before exec sayHello()");
            Object result = methodProxy.invokeSuper(o, objects);
            System.out.println("after exec sayHello()");
            return result;
        });

        Main m = (Main) enhancer.create();
        m.sayHello(123);
    }
}

发现无法运行,错误如下:

Unable to make protected final java.lang.Class java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain) throws java.lang.ClassFormatError accessible: module java.base does not "opens java.lang" to unnamed module @7506e922

经查是因为cglib目前已经不再维护了(见github:https://github.com/cglib/cglib),对新java支持不佳,可以使用VM参数:

--add-opens java.base/java.lang=ALL-UNNAMED

注:在Java 9及以后的版本中,引入了模块化系统,它允许将代码和资源划分为多个模块以提高代码的可维护性和安全性。然而,由于模块的隔离性,某些代码可能无法在模块之间进行正常的交互。这时,我们可以使用Java --add-opens选项来解决此类问题。

运行输出:

before exec sayHello()
Hello 123
after exec sayHello()

众所周知,spring框架AOP实现部分基于cglib,那么既然cglib官方已经不维护了,spring是怎么操作的呢?

原来spring现在自己维护cglib:https://github.com/spring-projects/spring-framework/tree/main/spring-core/src/main/java/org/springframework/cglib

回到我们之前的代码,修改pom文件为:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-core</artifactId>
    <version>6.1.3</version>
</dependency>

java代码将Enhancer类和MethodInterceptor类改为spring的即可:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;

这样就不用加jvm参数了。