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

轻量级 ioc 框架 loveqq,支持接口上传 jar 格式的 starter 启动器并支持热加载其中的 bean

轻量级 ioc 框架 loveqq,支持接口上传 jar 格式的 starter 启动器并支持热加载其中的 bean


热加载 starter 启动器代码示例:

package com.kfyty.demo;import com.kfyty.loveqq.framework.boot.K;
import com.kfyty.loveqq.framework.boot.context.ContextRefresher;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Autowired;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.BootApplication;
import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;
import com.kfyty.loveqq.framework.core.autoconfig.condition.annotation.ConditionalOnMissingBean;
import com.kfyty.loveqq.framework.core.lang.JarIndexClassLoader;
import com.kfyty.loveqq.framework.core.utils.IOC;
import com.kfyty.loveqq.framework.web.core.annotation.GetMapping;
import com.kfyty.loveqq.framework.web.core.annotation.RequestMapping;
import com.kfyty.loveqq.framework.web.core.annotation.RestController;
import com.kfyty.loveqq.framework.web.core.autoconfig.annotation.EnableWebMvc;
import com.kfyty.loveqq.framework.web.core.multipart.MultipartFile;
import lombok.extern.slf4j.Slf4j;import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.Extension;
import java.util.Collections;
import java.util.UUID;
import java.util.jar.JarFile;@Slf4j
@EnableWebMvc
@RestController
@BootApplication
@RequestMapping(expose = true)                  // 自动暴露 public 方法为 POST http 接口
public class Main {@Autowiredprivate Extension extension;/*** 测试接口*/@GetMappingpublic String sayHello() {return extension.getId();}/*** 加载插件** @param jar jar 包 启动器* @return 上传后的 jar 包绝对路径,卸载启动器时需要提供该返回值*/public String loadPlugin(MultipartFile jar) throws Exception {// 保存到本地String filePath = "D:\\temp\\jar\\" + UUID.randomUUID().toString().replace("-", "") + "\\" + jar.getOriginalFilename();File jarFile = new File(filePath);jar.transferTo(jarFile);// 添加到框架 ClassLoaderJarIndexClassLoader classLoader = (JarIndexClassLoader) IOC.class.getClassLoader();classLoader.addJarIndex(Collections.singletonList(new JarFile(jarFile)));// 刷新上下文ContextRefresher.refresh(IOC.getApplicationContext());return jarFile.getAbsolutePath();}/*** 卸载启动器** @param jarPath {@link #loadPlugin(MultipartFile)} 的返回值*/public String unloadPlugin(String jarPath) throws Exception {// 构建 File 对象File jarFile = new File(jarPath);// 从框架 ClassLoader 移除JarIndexClassLoader classLoader = (JarIndexClassLoader) IOC.class.getClassLoader();classLoader.removeJarIndex(Collections.singletonList(new JarFile(jarFile)));// 刷新上下文ContextRefresher.refresh(IOC.getApplicationContext());return "ok";}public static void main(String[] args) throws Exception {K.run(Main.class, args);}/*** 默认实现*/@Component@ConditionalOnMissingBean(Extension.class)public static class DefaultExtension implements Extension {@Overridepublic String getId() {return "default";}@Overridepublic boolean isCritical() {return false;}@Overridepublic byte[] getValue() {return new byte[0];}@Overridepublic void encode(OutputStream out) throws IOException {}}
}

然后,新建一个项目,添加如下类:

package com.kfyty.graal.example;import com.kfyty.loveqq.framework.core.autoconfig.annotation.Component;import java.io.IOException;
import java.io.OutputStream;
import java.security.cert.Extension;/*** 动态加载示例实现*/
@Component
public class ExampleExtension implements Extension {@Overridepublic String getId() {return "example";}@Overridepublic boolean isCritical() {return false;}@Overridepublic byte[] getValue() {return new byte[0];}@Overridepublic void encode(OutputStream out) throws IOException {}
}

并在 k.factories 中添加:

com.kfyty.loveqq.framework.core.autoconfig.annotation.EnableAutoConfiguration=com.kfyty.graal.example.ExampleExtension

然后打成 jar 包,就是一个启动器了。

接着启动第一段代码的 main 方法后:

先访问:http://localhost:8080/sayHello,将返回 default

然后使用 postman 上传启动器 jar 包:http://127.0.0.1:8080/loadPlugin,此时将动态加载上传的启动器,并刷新 ioc 容器

然后再访问:http://localhost:8080/sayHello,将返回 example,原因是加载了新的启动器,条件注解生效,实现类变化了!

然后再访问:http://127.0.0.1:8080/unloadPlugin,将第二步的返回值作为入参传入,此时将卸载启动器,并刷新 ioc 容器

然后再访问:http://localhost:8080/sayHello,将返回 default,原因是卸载了之前加载的启动器,条件注解生效,实现类又变化了!

从而实现了启动器的热加载,感兴趣的同学可以试一下。

gitee/github/gitcode: loveqq-framework

http://www.xdnf.cn/news/13865.html

相关文章:

  • 经济系统的「资源死锁」与「架构重构」:从通缩陷阱到可持续模型设计
  • MySQL(多表设计、多表查询)
  • Android S - 重复播放按键音(上下左右、OK)
  • Java详解LeetCode 热题 100(32):LeetCode 138. 随机链表的复制
  • Linux常用命令加强版替代品
  • 探索弹性弦行为:从绘图到问题解决-AI云计算数值分析和代码验证
  • 永不休眠:Linux 守护进程的工作原理
  • visual studio小番茄插件某些快捷键失效
  • 1万美元iO bounty破解之旅
  • android aosp源码下编码时避免引用aidl文件飘红不自动提示的方法
  • 神经网络压缩
  • 本地windows搭建kafka
  • 青少年编程与数学 01-011 系统软件简介 17 Hadoop大数据处理框架
  • NLP进化史:从规则模板到思维链推理,七次范式革命全解析
  • Vue3 + TypeScript + Element Plus 开启边框 > 调整列宽(拖动表头)> 保存列宽(本地存储)> 加载列宽(读取本地数据)
  • 基于物品的协同过滤推荐算法实现(Java电商平台)
  • 基于用户的协同过滤推荐算法实现(Java电商平台)
  • 微服务--Gateway网关
  • 开源组件hive页面安全问题
  • 【IEEE/EI/Scopus检索】2025年第六届模式识别与数据挖掘国际会议 (PRDM 2025)
  • Python爬虫进阶:气象数据爬取中的多线程优化与异常处理技巧
  • Java并发进阶系列:深度讨论高并发跳表数据结构ConcurrentSkipListMap的源代码实现(上)
  • python类成员概要
  • 当空间与数据联动,会展中心如何打造智慧运营新范式?
  • 当机床开始“思考”,传统“制造”到“智造”升级路上的法律暗礁
  • 驱动开发前传及led驱动(s5pv210)
  • 深度学习——基于PyTorch的MNIST手写数字识别详解
  • Python数据结构与算法(6.1)——树
  • 使用 Spring Boot 和 dynamic-datasource 实现多数据源集成
  • 从 0 开始理解 Spring 的核心思想 —— IoC 和 DI(1)