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

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐