JarsLink (原名Titan) 是一个基于JAVA的模块化开发框架,它提供在运行时动态加载模块(一个JAR包)、卸载模块和模块间调用的API。也是阿里巴巴的开源项目之一 https://github.com/alibaba/jarslink,目前在微贷事业群广泛使用。
github例子地址:https://github.com/zhuquanwen/jarslink-demo
使用介绍参见:https://yq.aliyun.com/articles/555104
一、编写两个jar包版本
1、引入jarslink-api等依赖(这里用的gradle,maven的类似)
dependencies {
compile ('com.alipay.jarslink:jarslink-api:1.5.0.20180213')
testCompile group: 'junit', name: 'junit', version: '4.12'
compile group: 'com.iscas', name: 'base', version: '2.0-RELEASE'
compile ('org.springframework:spring-web:5.1.6.RELEASE')
compile ('org.springframework:spring-context:5.1.6.RELEASE')
}
这里的base 就是一个接口而已,没什么特别的,只是个例子
2、resources下创建/META-INF/spring/xxx.xml文件
3、编写action
@Component
public class TTT implements Action, TTInterface {
@Autowired
private Use use;
public TTT() {
/*System.out.println("2.5");*/
}
@Override
public void ttt() {
use.t();
}
@Override
public String execute(ModuleConfig actionRequest) {
ttt();
return "success";
}
@Override
public String getActionName() {
return "ttt";
}
}
@Component
public class Use {
public void t() {
System.out.println("2.9-ttt");
}
}
TTInterface就是base内的一个接口
这里在测试方法中输出版本号,方便测试版本的隔离有没有成功
4、打两个jar包,更改一下版本号,和上一步的输出,我这里用的gradle的showJar插件,打包后传入了本地maven私服
group 'com.iscas'
version '2.9-RELEASE'
//上传至nexus
publishing {
publications {
maven(MavenPublication) {
groupId project.group
artifactId project.name
version project.version
//若是war包,就写components.web,若是jar包,就写components.java
// from components.java
artifact shadowJar
}
}
repositories {
maven {
if (project.version.endsWith('-SNAPSHOT')) {
url = "http://192.168.100.88:8081/repository/maven-snapshots/"
} else {
url = "http://192.168.100.88:8081/repository/maven-releases/"
}
credentials {
username 'admin'
password 'admin123'
}
}
}
}
二、调用
1、构建一个springboot项目,将两个jar拷贝至resources下META-INF
2、注册ModuleConfig
public class ModuleRefreshSchedulerImpl extends AbstractModuleRefreshScheduler {
@Override
public List queryModuleConfigs() {
return ImmutableList.of(buildModuleConfig()/*, buildModuleConfig2()*/);
}
public static ModuleConfig buildModuleConfig() {
URL demoModule = Thread.currentThread().getContextClassLoader().getResource("META-INF/demo-2.8-RELEASE.jar");
ModuleConfig moduleConfig = new ModuleConfig();
//通过该方法构建的配置都是使用注解形式扫描bean的
// String scanBase = "com.alipay.jarslink.main";
moduleConfig.setOverridePackages(Arrays.asList("com.iscas.demo"));
moduleConfig.setName("demo");
moduleConfig.setEnabled(true);
moduleConfig.setVersion("2.8");
// moduleConfig.setProperties(ImmutableMap.of("lalala", new Object()));
moduleConfig.setModuleUrl(ImmutableList.of(demoModule));
return moduleConfig;
}
public static ModuleConfig buildModuleConfig2() {
URL demoModule = Thread.currentThread().getContextClassLoader().getResource("META-INF/demo-2.9-RELEASE.jar");
ModuleConfig moduleConfig = new ModuleConfig();
moduleConfig.setName("demo");
moduleConfig.setEnabled(true);
moduleConfig.setVersion("2.9");
// moduleConfig.setProperties(ImmutableMap.of("svnPath", new Object()));
moduleConfig.setModuleUrl(ImmutableList.of(demoModule));
return moduleConfig;
}
}
3、注册bean
@Configuration
public class BeanConfig {
@Bean
public ModuleLoader moduleLoader() {
return new ModuleLoaderImpl();
}
@Bean
public ModuleManager moduleManager() {
return new ModuleManagerImpl();
}
@Bean
public ModuleRefreshSchedulerImpl moduleRefreshScheduler() {
ModuleRefreshSchedulerImpl moduleRefreshScheduler = new ModuleRefreshSchedulerImpl();
ModuleManager moduleManager = moduleManager();
ModuleLoader moduleLoader = moduleLoader();
moduleRefreshScheduler.setModuleLoader(moduleLoader);
moduleRefreshScheduler.setModuleManager(moduleManager);
return moduleRefreshScheduler;
}
}
4、测试调用
@RestController
public class Controller {
@Autowired
private ModuleRefreshSchedulerImpl moduleRefreshScheduler;
@Autowired
private ModuleManager moduleManager;
@Autowired
private ModuleLoader moduleLoader;
@GetMapping("/test/{version}")
public String test(@PathVariable String version) {
List moduleConfigs = moduleRefreshScheduler.queryModuleConfigs();
Module runModule = moduleManager.find("demo");
if (runModule == null || runModule.getActions().size() == 0 || !Objects.equals(version, runModule.getVersion())) {
if (Objects.equals("2.8", version)) {
runModule = moduleLoader.load(ModuleRefreshSchedulerImpl.buildModuleConfig());
Module removedModule = moduleManager.register(runModule);
} else if (Objects.equals("2.9", version)) {
runModule = moduleLoader.load(ModuleRefreshSchedulerImpl.buildModuleConfig2());
Module removedModule = moduleManager.register(runModule);
} else {
throw new RuntimeException("版本错误");
}
}
String result = runModule.doAction("ttt", new ModuleConfig());
return result;
}
}
5、结果
http://localhost:8080/test/2.8
http://localhost:8080/test/2.9