当前位置: 首页 > article >正文

springBoot动态加载jar,将类注册到IOC

具体实现

Service

public interface JarService {
    Boolean loadJarByName(LoadJarDTO dto);
}

impl:


@Service
@RequiredArgsConstructor
@Slf4j
public class JarServiceImpl implements JarService {

    private final SpringContextUtil springContextUtil;
    @Override
    public Boolean loadJarByName(LoadJarDTO dto) {
        //初始化File-加载jar所在目录
        File jarFile = new File(dto.getJarPath());
        if (!jarFile.exists()){
            return false;
        }
        List<String> loadClassList = this.getLoadClass(jarFile.getAbsolutePath());
        if (CollectionUtils.isEmpty(loadClassList)){
            return false;
        }
        //加载jar
        ClassLoader classLoader = ClassLoaderUtil.getJarClassLoader(jarFile);
        for (String loadClassPath : loadClassList) {
            Class<?> clazz = null;
            try {
                clazz = classLoader.loadClass(loadClassPath);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
            if(!this.isLoadClass(clazz)){
                continue;
            }
            //生成需要注册到ioc的bean名称
            // clazz.getSimpleName()用于获取表示该类的简单名称(不包括包名)。简单名称就是类名本身,而不带任何修饰或包的前缀。
            String beanName = getBeanName(dto.getPreBeanName(),clazz.getSimpleName()) ;
            //加载需要加载的
            if (!dto.getIsOverLoad() && springContextUtil.containsBeanDefinition(beanName)){
                continue;
            }
            if (dto.getIsOverLoad() && springContextUtil.containsBeanDefinition(beanName)){
                springContextUtil.unregisterBean(beanName);
            }
            springContextUtil.registerBean(beanName,clazz);
        }

        return true;
    }

    private static String getBeanName(String name, String className) {
        return StringUtils.uncapitalize(name) + StringUtils.capitalize(className);
    }


    private boolean isLoadClass(Class<?> clazz) {
        if (clazz == null){
            return false;
        }
        //是否是接口
        if (clazz.isInterface()){
            return false;
        }
        //是否是抽象类
        if (Modifier.isAbstract(clazz.getModifiers())){
            return false;
        }
        if (clazz.getAnnotation(Service.class) != null){
            return true;
        }
        if (clazz.getAnnotation(Component.class) != null){
            return true;
        }
        if (clazz.getAnnotation(Repository.class) != null){
            return true;
        }
        if (clazz.getAnnotation(Configuration.class) != null){
            return true;
        }
        return false;
    }

    private List<String> getLoadClass(String jarPath) {
        Set<String> classPathList = new HashSet<>();
        File file = new File(jarPath);
        //获取jar的流,打开jar文件
        try ( JarInputStream jarInputStream = new JarInputStream(FileUtil.getInputStream(file))){
            //逐个获取jar种文件
            JarEntry jarEntry = jarInputStream.getNextJarEntry();
            //遍历
            while (jarEntry != null){
                //获取文件路径
                String name = jarEntry.getName();
                if (name.endsWith(".class")){
                    String classNamePath = name.replace(".class", "").replace("/",".");
                    classPathList.add(classNamePath);
                }
                jarEntry = jarInputStream.getNextJarEntry();
            }
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new RuntimeException("获取加载类路径失败");
        }
        return new ArrayList<>(classPathList);
    }
}

使用:

新建一模块,写一个简单类:

@Service
public class CalculateServiceImpl implements CalculateService {
    @Override
    public int add(int a, int b) {
        return a + b;
    }

    @Override
    public int minus(int a, int b) {
        return a - b;
    }
}

建立一个公共接口,放在公共模块,以供加载jar时候,可以获取接口方法

public interface CalculateService {
    int add(int a,int b);

    int minus(int a ,int b);
}

然后 cleam-install打成jar

建立一加载使用:

    @GetMapping("/calculate/{beanName}/{a}/{b}")
    private Integer calculate( @PathVariable(value = "beanName") String beanName,
            @PathVariable(value = "a") Integer a, @PathVariable("b") Integer b){
        return jarService.calculate(beanName,a,b);
    }

 @Override
    public Integer calculate(String beanName, Integer a, Integer b) {
        CalculateService calculateService = SpringContextUtil.getBean(getBeanName(beanName,beanName+"Impl"), CalculateService.class);
        int add = calculateService.add(a, b);
        return add;
    }
    private static String getBeanName(String name, String className) {
        return StringUtils.uncapitalize(name) + StringUtils.capitalize(className);
    }


http://www.kler.cn/a/384454.html

相关文章:

  • 【LeetCode】【算法】148. 排序链表
  • 浅谈Spring MVC
  • 高防服务器和高防IP的区别是什么?
  • 单链表反转
  • Java版ERP管理系统源码解析:利用Spring Cloud Alibaba和Spring Boot实现微服务架构
  • 107. 二叉树的层序遍历 II 队列+迭代
  • MongoDB笔记01-概念与安装
  • <网络> 协议
  • go 集成viper 配置管理
  • 简易抽奖器源码以及打包操作
  • 【网络-交换机】生成树协议、环路检测
  • Java 8 Stream API 详解
  • 实时金融股票数据API接口websocket接入方法
  • WRF-LES与PALM模型:风能资源评估、风力发电、大涡模拟、大尺度湍流涡旋、大雾预报、局地环流模拟、城市热岛效应、流场模拟
  • 香港服务器怎么搭建docker加速器
  • flutter 项目初建碰到的控制台报错无法启动问题
  • 地理空间-Java实现航迹稀释
  • 【北京迅为】《STM32MP157开发板嵌入式开发指南》-第七十二章 Debian文件系统
  • Java反射原理及其性能优化
  • C#实战:使用腾讯云识别服务轻松提取火车票信息
  • 科研绘图系列:R语言组合连线图和箱线图(linechart+boxplot)
  • Vue实战学习(2)(Vue快速入门(快速构建一个局部Vue项目))
  • xftp连接中不成功 + sudo vim 修改sshd_config不成功的解决方法
  • 斗破QT编程入门系列之二:GUI应用程序设计基础:UI文件(四星斗师)
  • 【C++】哈希表封装 unordered_map 和 unordered_set 的实现过程
  • 信息安全工程师(80)网络安全测评技术与工具