如何在Springboot启动/运行时动态加载外部Jar包里的方法

最近遇到一个需求,我需要将别人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日

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值