轻量级 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 {
@Autowired
private Extension extension;

/**
 * 测试接口
 */
@GetMapping
public 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);

// 添加到框架 ClassLoader
JarIndexClassLoader 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 {

@Override
public String getId() {
return "default";
}

@Override
public boolean isCritical() {
return false;
}

@Override
public byte[] getValue() {
return new byte[0];
}

@Override
public 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 {

@Override
public String getId() {
return "example";
}

@Override
public boolean isCritical() {
return false;
}

@Override
public byte[] getValue() {
return new byte[0];
}

@Override
public 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,原因是卸载了之前加载的启动器,条件注解生效,实现类又变化了!

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


相關推薦

2025-06-11

全量刷新上下文代码示例: 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.annotat

2024-06-18

loveqq-framework 轻量级 ioc/aop 框架,比 spring 更强大的条件注解推断,打包后支持 jar index 启动。 本次更新: 正式更名为:loveqq-famework 新增:loveqq-boot-starter-mybatis 新增:loveqq-boot-starter-pagehelper 新增:loveqq-boot-starter-shiro

2024-07-26

cache-redis,整合 redisson 响应式缓存支持 优化:loveqq-boot-starter-netty,优化过滤器、拦截器均为响应式接口 响应式缓存示例: 下面的示例展示了缓存注解用法,并且实现了响应式/命令式一致的操作体验 @RestController public class

2024-05-09

​ kfyty-framework 轻量级 ioc/aop 框架,比 spring 更强大的条件注解推断,打包后支持 jar index 启动,启动速度更快 注解式 ioc/aop、自动装配、异步事件、动态代理、注解式 mvc(支持 Restful)、嵌入式 tomcat、 注解式 jdbc 框架、

2025-05-28

代理生效 新增:mybatis-flex-loveqq-starter,新增 mybatis-flex 启动器,可到 mybatis-flex 仓库查看 优化:新增 docker 打包示例

2024-07-12

本次更新: 新增: loveqq-boot-starter-mail,整合 java mail 新增:loveqq-boot-starter-logback,整合 logback 新增:loveqq-cache,支持注解式缓存配置,默认提供 ConcurrentHashMap 实现 新增:loveqq-cache-redis,整合 redisson 缓存支持 新增

2025-06-19

介绍 @Async:支持自动将普通方法转为异步调用 但是该功能有一个小问题,就是某些业务又需要同步调用时难以实现,特别是返回值为 void 时,这时候只能修改代码兼容两种逻辑 @Async.Await:该注解支持将异步调用自动转为同步

2023-07-09

YMP 是一个非常简单、易用的轻量级 Java 应用开发框架,涵盖 AOP、IoC、WebMVC、ORM、Validation、Plugin、Serv、Cache 等特性,主要技术特点: 采用组件化、模块方式打包,可按需装配,灵活可扩展; 采用微内核实现 AutoScan、AOP、

2025-05-03

; <ul style="list-style-type:disc"> <li> 内建 HTTP Server 启动器,快速部署 Web 服务; </li> <li> 支持<span> </span><code>Runner</code>、<code>Job</code>、<code>Server</code><span> </span>三类

2023-11-30

系统   开源项目主页 本次更新内容: - [pangu app starter] 整合集成 uni-app 和uview ui 提供移动端快速开发脚手架。 - [pangu app starter] 发布 pagu app starter 的 H5 版本、微信小程序版本、Android 原生版本的示例程序。 - [pangu] 解决

2022-05-26

构部署方案 关于 Solon Solon 是一个更现代感的应用开发框架,轻量、开放生态型的。支持 Web、Data、Job、Remoting、Cloud 等任何开发场景。 强调,克制 + 简洁 + 开放 + 生态的原则 力求,更小、更少、更快、更自由的体验

2023-05-16

Guice 7.0.0 现已发布。Guice 是 Google 开发的轻量级依赖注入框架,目标是使开发和调试更容易,更快速。具体更新内容包括: 自 Guice 5.1.0 以来的变化 JEE Jakarta Transition Guice 7.0 仅支持jakarta.inject、jakarta.servlet和 jakarta.pe

2023-11-06

力,借助此能力可针对不同页面设置差异化的切换动效;轻量级ArkUI框架支持定义全局数据对象,可进行应用内页面间的数据共享。 框架能力增强,包括:全局API支持Stage模型多实例场景,支持Rosen渲染后端等。 对富文本

2025-05-22

Weaviate 的 20 种不同的向量数据库。 Spring AI 包含一个轻量级、可配置的 ETL(提取、转换、加载)框架,可简化将数据导入向量存储的过程。它通过可插拔的 DocumentReader 组件支持多种输入源,包括本地文件系统、网页、GitHub