前言

我们知道 FastRequest 中有一块前置、后置脚本,允许在 api 执行前后处理一些逻辑。前后置脚本是通过 Groovy 脚本实现的,Groovy是一门跟 Java 非常相像的语言。接下来我们希望利用Groovy来实现加载某个 jar 包下面或者项目下的某个类,并且调用类里面的方法实现一些逻辑

file

本地Jar 加载

this.class.classLoader.addURL(new URL("file:/path/to/jar"))
def StringUtils = Class.forName("org.apache.commons.lang3.StringUtils").getDeclaredConstructor().newInstance()

if(StringUtils.isNotBlank("")){
    //some logic
}

首先我们需要通过 classLoaderaddURL方法将 Jar 加载进来,例如 commons.lang 包有一些非常多的工具方法。接下来就可以通过Class.forName实例化类,并且再后面直接进行调用。

本地 Class加载

本地 Class 调用需要通过 ClassLoader 将本地的 class 加载进来再处理


import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

public class FrLocalClassLoader extends ClassLoader {
    private final String classpath;

    /**
     * @param classpath 类路径,例如/Users/username/xx_project/target/classes
     */
    public FrLocalClassLoader(String classpath) {
        this.classpath = classpath;
    }

    @Override
    public Class<?> findClass(String name) throws ClassNotFoundException {
        String filePath = classpath + File.separator + name.replace(".", File.separator) + ".class";
        File file = new File(filePath);
        if (!file.exists()) {
            throw new ClassNotFoundException("Class not found: " + name);
        }
        try (InputStream inputStream = new FileInputStream(file)) {
            byte[] classData = new byte[(int) file.length()];
            inputStream.read(classData);
            return defineClass(name, classData, 0, classData.length);
        } catch (IOException e) {
            throw new ClassNotFoundException("Could not load class: " + name, e);
        }
    }
}

我们需要先定义一个本地加载 Class 的类,并且构造器里面传入classpath,classpath即 class 文件夹所在的目录。例如我们SpringBoot 项目编译后,会在项目模块目录下生产一个 target>classes层级目录,那么我们需要将 classes 这个目录的绝对路径定义为 classPath。接下来调用findClass找到对应的类即可。

可以这么调用,即可获取XxxUtil,接下来就可以直接调用

def XxxUtil = new FrLocalClassLoader("path/to/classes").loadClass("some.package.XxxUtil")

那么如果需要加载一个有构造器的类呢?也很简单,只要获取到类以后,再调用getConstructor,传入对应的参数类型即可

Constructor<?> constructor = new FrLocalClassLoader("path/to/classes").loadClass("some.package.User").getConstructor(String.class, int.class);

User instance = constructor.newInstance("Alice", 30);

远程 Jar 加载的形式

@Grab("org.apache.commons:commons-lang3:3.12.0")
import org.apache.commons.lang3.StringUtils
if(StringUtils.isNotBlank("")){
    //some logic
}

通过 @Grab("groupId:artifactId:version") 注解非常简单的将 jar 包的加载进来,并且 import 相对应的类,后面再直接调用。


Kings
1 声望1 粉丝