轻量级 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,原因是卸载了之前加载的启动器,条件注解生效,实现类又变化了!
从而实现了启动器的热加载,感兴趣的同学可以试一下。
gitee/github/gitcode: loveqq-framework