springBoot动态加载jar及如何将类注册到IOC

 更新时间:2024年11月05日 10:09:47   作者:又是努力搬砖的一年  
在SpringBoot项目中动态加载jar文件并将其类注册到IOC容器是一种高级应用方式,,这种方法为SpringBoot项目提供了更灵活的扩展能力,使得项目可以在不修改原有代码的基础上增加新的功能模块,感兴趣的朋友一起看看吧

具体实现

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);
    }

到此这篇关于springBoot动态加载jar,将类注册到IOC的文章就介绍到这了,更多相关springBoot动态加载jar内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java的垃圾回收机制实例分析

    Java的垃圾回收机制实例分析

    这篇文章主要介绍了Java的垃圾回收机制,结合实例形式分析了垃圾回收机制的原理及相关操作技巧,需要的朋友可以参考下
    2019-08-08
  • springboot 启动如何排除某些bean的注入

    springboot 启动如何排除某些bean的注入

    这篇文章主要介绍了springboot 启动如何排除某些bean的注入方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • 使用Mock进行业务逻辑层Service测试详解

    使用Mock进行业务逻辑层Service测试详解

    这篇文章主要介绍了使用Mock进行业务逻辑层Service测试详解,mock是一种模拟对象的技术,用于在测试过程中替代真实的对象,通过mock,我们可以控制被模拟对象的行为和返回值,以便进行更加精确的测试,需要的朋友可以参考下
    2023-08-08
  • java开发非公平锁不可打断源码示例解析

    java开发非公平锁不可打断源码示例解析

    这篇文章主要为大家介绍了java开发非公平锁不可打断源码示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • java实现一个简单TCPSocket聊天室功能分享

    java实现一个简单TCPSocket聊天室功能分享

    这篇文章主要为大家分享了java实现的一个简单TCPSocket聊天室功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2016-04-04
  • Springboot详解整合SpringSecurity实现全过程

    Springboot详解整合SpringSecurity实现全过程

    Spring Security基于Spring开发,项目中如果使用Springboot作为基础,配合Spring Security做权限更加方便,而Shiro需要和Spring进行整合开发。因此作为spring全家桶中的Spring Security在java领域很常用
    2022-07-07
  • 基于Mybatis实现动态数据源切换的示例代码

    基于Mybatis实现动态数据源切换的示例代码

    在当今的互联网应用中,微服务大行其道,随着业务的发展和扩展,单一的数据库无法满足日益增长的数据需求,本文将基于 JDK17 + Spring Boot 3 和 MyBatis 框架实现动态切换数据源功能,需要的朋友可以参考下
    2024-09-09
  • 详解SpringBoot实现ApplicationEvent事件的监听与发布

    详解SpringBoot实现ApplicationEvent事件的监听与发布

    这篇文章主要为大家详细介绍了SpringBoot如何实现ApplicationEvent事件的监听与发布,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2023-03-03
  • Jvm调优和SpringBoot项目优化的详细教程

    Jvm调优和SpringBoot项目优化的详细教程

    这篇文章主要介绍了Jvm调优和SpringBoot项目优化,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • 在Windows系统下安装Thrift的方法与使用讲解

    在Windows系统下安装Thrift的方法与使用讲解

    今天小编就为大家分享一篇关于在Windows系统下安装Thrift的方法与使用讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12

最新评论