最近遇到一个需求,我需要将别人Jar包里的东西打包为模型放到容器中运行,做为一个服务发布,那么问题来了:如何动态的获取外部Jar,将里面的方法打包为一个Bean。
居然有人收藏了,我决定写完整他。。。。不明白的可以交流再说。2023年3月27日
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**所有的异常我都不自己处理了**/
@Slf4j
@Component
public class CalculatorLoaderImpl<T> extends ClassMethodName implements CalculatorLoader<T> {
/**
* 类加载器!
*/
private URLClassLoader urlClassLoader;
/**
* 初始化URLClassLoader, 读取jarPath文件
*
* @param jarPath Jar文件路径
*/
private URLClassLoader initURLClassLoader(String jarPath) throws CanNotLoadJarException {
urlClassLoader = new URLClassLoader(new URL[] { new URL("file:" + jarPath) },
Thread.currentThread().getContextClassLoader());
return urlClassLoader;
}
/**
* 从Jar中加载获得的某个具体类
*/
private Class<?> clazz;
/**
* 从jarPath所在的jar文件中,获得某个具体的类
*
* @param urlClassLoader 类加载器
* @param calculatorReferencePath (我自己的模型)某个类的具体路径,例如com.xxx.CalculatorImpl
*/
private Class<?> initClass(URLClassLoader urlClassLoader, String calculatorReferencePath)
throws CanNotLoadClassException {
clazz = urlClassLoader.loadClass(calculatorReferencePath);
return clazz;
}
// 我自己的模型
private Object calculator;
/**
* 计算器的实体模型,里面包含了计算执行方法 {@link CalculatorModel}
* 貌似直接返回一个Model也可以
*/
private Object initCalculator() throws CanNotLoadMethodException {
calculator = clazz.getDeclaredConstructor().newInstance();
return calculator;
}
@Override
@SuppressWarnings("unchecked")
public CalculatorModelDTO getCalculatorModelFromFile(String jarPath, String calculatorReferencePath) {
// 这里不影响代码,这是我写了一个缓存,注释掉不影响代码
if (CachedCalculatorModel.contains(jarPath, calculatorReferencePath)) {
log.info("Using cached\t" + jarPath + calculatorReferencePath);
CalculatorModel<?> model = CachedCalculatorModel.getModel(jarPath + calculatorReferencePath);
return new CalculatorModelDTO().success(model);
}
try {
// 1. 初始化类加载器
initURLClassLoader(jarPath);
} catch (Exception e) {
return new CalculatorModelDTO().fail(e);
}
try {
// 2. 初始化类 声明类
initClass(urlClassLoader, calculatorReferencePath);
} catch (CanNotLoadClassException e) {
return new CalculatorModelDTO().fail(e.getMessage());
}
try {
// 3. 创建类 实际创建
initCalculator();
} catch (CanNotLoadMethodException e) {
return new CalculatorModelDTO().fail(e);
}
try {
urlClassLoader.close();
} catch (IOException e) {
return new CalculatorModelDTO().fail(this.getClass() + "关闭urlClassloader异常");
}
// 4. 转换类型
// 这里绝对是重要的
/**
下面这个CalculatorModel<T>是我自己的类,是写在我当前项目里面的,
外边的JAR包是继承了这个接口的,实现了这个接口的方法
所以强转一下就可以用了
**/
CalculatorModel<T> model = (CalculatorModel<T>) this.calculator;
CachedCalculatorModel.addCalculatorModel(jarPath, calculatorReferencePath, model);
return new CalculatorModelDTO().success(model);
}
}
改天再更----------
下周一再更新!2022年9月4日