当前位置:网站首页>alibaba jarslink
alibaba jarslink
2022-06-27 11:26:00 【飘然渡沧海】
alibaba jarslink框架教程
demo的github地址:https://github.com/superRabbitMan/jarslink-demo
什么是jarslink
JarsLink (原名Titan)是一个基于JAVA的模块化开发框架,它提供在运行时动态加载模块(一个JAR包)、卸载模块和模块间调用的API。
为什么使用jarslink
隔离性
- 类隔离:框架为每个模块的Class使用单独的ClassLoader来加载,每个模块可以依赖同一种框架的不同的版本。
- 实例隔离:框架为每个模块创建了一个独立的Spring上下文,来加载模块中的BEAN,实例化失败不会影响其他模块。
- 资源隔离:后续会支持模块之间的资源隔离,每个模块使用独立的CPU和内存资源。
动态性
- 动态发布:模块能在运行时动态加载到系统中,实现不需要重启和发布系统新增功能。支持突破双亲委派机制,在运行时加载父加载器已经加载过的类,实现模块升级依赖包不需要系统发布。
- 动态卸载:模块能在运行时被动态卸载干净,实现快速下线不需要功能。
易用性
- 提供了通用灵活的API让系统和模块进行交互。
下载
\1. 官网:https://github.com/alibaba/jarslink
\2. 其它途径:https://oss.sonatype.org/#nexus-search;quick~jarslink
引入项目
至于如何创建一个Maven项目这里不多介绍,自己百度即可
#主要POM,这里请使用1.6以上的版本,因为接下来介绍有个功能1.6极其以上版本才支持
<dependency>
<groupId>com.alipay.jarslink</groupId>
<artifactId>jarslink-api</artifactId>
<version>1.6.1.20180301</version>
</dependency>
#依赖POM
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.5.RELEASE</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.3</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.1</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>17.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>
引入模块jar包
模块jar文件引入是不用buildpath导入项目的,你可以放在CDEF盘任意位置都可以,因为这个模块jar文件是不随项目启动的,我们使用jarslink框架去引用它。
为了方便调用,我放在项目的resources文件下:

最重要的对象
<!-- 模块加载引擎,负责加载模块--><bean name="moduleLoader" class="com.alipay.jarslink.api.impl.ModuleLoaderImpl"></bean>
<!-- 模块管理器,负责注册,卸载,查找模块以及执行Action --><bean name="moduleManager" class="com.alipay.jarslink.api.impl.ModuleManagerImpl"></bean>
配置jarslink.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--模块加载引擎-->
<bean id="moduleLoader" name="moduleLoader" class="com.alipay.jarslink.api.impl.ModuleLoaderImpl" />
<!--模块管理器-->
<bean id="moduleManager" name="moduleManager" class="com.alipay.jarslink.api.impl.ModuleManagerImpl" />
</beans>
配置模块信息
public static ModuleConfig buildModuleConfig() {
URL demoModule = Thread.currentThread().getContextClassLoader().getResource("jarslink-module-demo-1.0.0.jar");//加载模块jar包,可以在任意路径下
ModuleConfig moduleConfig = new ModuleConfig();
moduleConfig.setName("hello-world");//设置模块名称
moduleConfig.setEnabled(true);
moduleConfig.setVersion("1.0.0");//设置版本
moduleConfig.setProperties(ImmutableMap.of("svnPath", new Object()));
moduleConfig.setModuleUrl(ImmutableList.of(demoModule));
return moduleConfig;
}
第一个调用demo
package com.alibaba.test;
import com.alipay.jarslink.api.Action;
import com.alipay.jarslink.api.Module;
import com.alipay.jarslink.api.ModuleLoader;
import com.alipay.jarslink.api.ModuleManager;
import com.alipay.jarslink.api.impl.AbstractModuleRefreshScheduler;
import com.alipay.jarslink.api.impl.ModuleManagerImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Map;
import java.util.Set;
/** * Created by HASEE on 2018/4/22. */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath*:jarslink.xml"})
public class JarsLinkTest {
@Autowired
private ModuleLoader moduleLoader;
@Autowired
private ModuleManager moduleManager;
@Test
public void test1() {
// System.out.println("moduleLoader = " + moduleLoader);
// System.out.println("moduleManager = " + moduleManager);
Module module = moduleLoader.load(ModuleRefreshSchedulerImpl.buildModuleConfig());//加载模块,加载一个模块
moduleManager.register(module);//注册模块信息
/*获取指定的Action,执行方式一*/
Module mod = moduleManager.find("hello-world");
Map<String, Action> actions = mod.getActions();
// Set<String> keys = actions.keySet();
// for (String key : keys) {
// System.out.println(key + ", " + actions.get(key));
// }
Action xmlaction = actions.get("XMLACTION");
System.out.println(xmlaction.execute("hello world"));
/*获取指定的Action,执行方式二*/
//doAction参数:模块中action的名称,action中execute方法的参数
String result = module.doAction("XMLACTION", "hello world");
System.out.println(result);
}
}
总结
Jarslink的使用就这么简单,1)加载模块jar。2)注册模块。3)调用模块的Action
开发模块(新建一个maven项目)
模块和Action的关系,一个jar包就是一个模块,模块中有一个或多个Action类,我们调用的就是模块的Action获取功能。所有开发模块其实就是开发Action。
Action的开发也比较简单,只要实现com.alipay.jarslink.api.Action<R,T>类即可,Action有2个泛型类,R表示传入参数,T表示返回参数。
Action一共要实现两个方法,1)T execute(Rvar1);。2)String getActionName();。execute方法是Action提供的功能方法。getActionName方法是获取的名称,该名称必须唯一,如果不唯一那么将不知道要执行模块的那个Action。
package com.alibaba.action;
import com.alipay.jarslink.api.Action;
/** * Created by HASEE on 2018/4/22. */
public class HelloWorldAction implements Action<String, String> {
@Override
public String execute(String s) {
return s + ":hello world";
}
@Override
public String getActionName() {
return "hello-world-action";
}
}
配置xml文件
配置文件的存放目录请注意,resources/META-INF/spring/*.xml,加载模块的时候会到这个目录下去读取配置信息。

配置信息如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:webflow="http://www.springframework.org/schema/webflow-config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/webflow-config http://www.springframework.org/schema/webflow-config/spring-webflow-config-2.0.xsd" default-autowire="byName">
<context:annotation-config/>
<!--创建Action-->
<bean id="helloWorldAction" class="com.alibaba.action.HelloWorldAction"/>
<bean id="welComeAction" class="com.alibaba.action.WelComeAction" />
</beans>
编译文件然后到处Jar包,这样一个模块就开发完成了,这个模块包含了一个HelloworldAction的类。
将导出的jar包引入到第一个案例的resources文件夹下,就可以调用了。
第二个调用demo
配置自己开发的模块
public static ModuleConfig buildModuleConfig_Demo() {
URL demoModule = Thread.currentThread().getContextClassLoader().getResource("jarslink-demo-action-1.0-SNAPSHOT.jar");
ModuleConfig moduleConfig = new ModuleConfig();
moduleConfig.setName("demo-action");
moduleConfig.setEnabled(true);
moduleConfig.setVersion("1.0.0");
//配置自定义的properties信息
moduleConfig.setProperties(ImmutableMap.of("svnPath", new Object()));
moduleConfig.setModuleUrl(ImmutableList.of(demoModule));
return moduleConfig;
}
package com.alibaba.test;
import com.alipay.jarslink.api.Action;
import com.alipay.jarslink.api.Module;
import com.alipay.jarslink.api.ModuleLoader;
import com.alipay.jarslink.api.ModuleManager;
import com.alipay.jarslink.api.impl.AbstractModuleRefreshScheduler;
import com.alipay.jarslink.api.impl.ModuleManagerImpl;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Map;
import java.util.Set;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath*:jarslink.xml"})
public class JarsLinkTest {
@Autowired
private ModuleLoader moduleLoader;
@Autowired
private ModuleManager moduleManager;
@Test
public void test2() {
//加载和注册模块
Module module = moduleLoader.load(ModuleRefreshSchedulerImpl.buildModuleConfig_Demo());//加载模块,加载一个模块
moduleManager.register(module);
String result = module.doAction("hello-world-action", "rabbit");
System.out.println("result = " + result);
}
}
总结
一个模块的Action开发就是这么简单,1)创建自己的Action。2)配置文件中配置bean信息。问题在于每次开发一个Action就要配置文件中加配置文件<beanid=”” name=”” class=”” />,一旦类多了,这样管理比较麻烦,还好在1.6版本中提供了扫描包的功能。
扫描包功能
Action的开发过程是一样的,只不过在xml文件中不需要使用配置信息,而是在调用的时候扫描指定的包即可,下面是关键的代码。
package com.alibaba.test;
import com.alipay.jarslink.api.Module;
import com.alipay.jarslink.api.ModuleConfig;
import com.alipay.jarslink.api.ModuleLoader;
import com.alipay.jarslink.api.ModuleManager;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.net.URL;
/** * Created by HASEE on 2018/4/23. */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {
"classpath*:jarslink.xml"})
public class AnnoJarsLinkTest {
@Autowired
private ModuleLoader moduleLoader;
@Autowired
private ModuleManager moduleManager;
@Test
public void test1() {
URL demoModule = Thread.currentThread().getContextClassLoader().getResource("jarslink-demo-anno-action-1.0-SNAPSHOT.jar");
ModuleConfig moduleConfig = new ModuleConfig();
moduleConfig.setName("anno-action");
moduleConfig.setEnabled(true);
moduleConfig.setVersion("1.0.0");
moduleConfig.setProperties(ImmutableMap.of("svnPath", new Object()));
moduleConfig.setModuleUrl(ImmutableList.of(demoModule));
//扫描模块下的Action
moduleConfig.addScanPackage("com.alibaba.action");
Module module = moduleLoader.load(moduleConfig);
moduleManager.register(module);
System.out.println("string to long " + module.doAction("string-to-long", "500"));
}
}
最佳实践
HTTP请求转发
通过请求路径来确定请求的模块和action
private ModuleManager moduleManager;
@RequestMapping(value = "module/{moduleName}/{actionName}/process.json", method = {
RequestMethod.GET,RequestMethod.POST })
public Object process(HttpServletRequest request, HttpServletResponse response) {
Map<String, String> pathVariables = resolvePathVariables(request);
String moduleName = pathVariables.get("moduleName").toUpperCase()
String actionName = pathVariables.get("actionName").toUpperCase()
String actionRequest = XXX;
return moduleManager.doAction(moduleName,
actionName, actionRequest);
}
private Map<String, String> resolvePathVariables(HttpServletRequest request) {
return (Map<String, String>) request
.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
}
如何发布模块
有两个方案:
方案1 拉模式
- 1:在本地编译代码打包成JAR包。
- 2:把JAR上传到一个远程文件服务器,比如阿里云的OSS。
- 3:应用从远程服务器下载JAR,可以把配置信息存放在JAR里,比如版本号,JAR名。
方案2 推模式
- 1:在本地编译代码打包成JAR包。
- 2:把JAR直接SCP到服务器上的某个目录。
- 3:应用检查服务指定目录的JAR是否有更新,如果有更新就进行加载。
边栏推荐
- 器审科普:创新医疗器械系列科普——胸骨板产品
- NAACL 2022 | TAMT:通过下游任务无关掩码训练搜索可迁移的BERT子网络
- Drive to APasS!使用明道云管理F1赛事
- 【TcaplusDB知识库】TcaplusDB分析型文本导出介绍
- Qstype implementation of self drawing interface project practice (I)
- 【TcaplusDB知识库】TcaplusDB-tcaplusadmin工具介绍
- AutoCAD - three pruning methods
- L'utilisation de C language 0 length Array
- Prevent being rectified after 00? I. The company's recruitment requires that employees cannot sue the company
- FileOutputStream
猜你喜欢

Unity shader learning (II) the first shader

【TcaplusDB知识库】TcaplusDB单据受理-事务执行介绍

C/s architecture

Youboxun attended the openharmony technology day to create a new generation of secure payment terminals

【值得收藏】Centos7 安装mysql完整操作命令

QStyle实现自绘界面项目实战(一)

Prevent being rectified after 00? I. The company's recruitment requires that employees cannot sue the company

【TcaplusDB知识库】TcaplusDB运维单据介绍

Redis 分布式锁15问,看看你都掌握了哪些?

【TcaplusDB知识库】TcaplusDB-tcapsvrmgr工具介绍(一)
随机推荐
Qstype implementation of self drawing interface project practice (I)
Deep learning in finance in cross sectional sectional predictions for random forests
Precautions for use of IO interface interrupt of Jerry [chapter]
Unity Shader学习(二)第一个Shader
杰理之增加一个输入捕捉通道【篇】
Istio related information
[tcapulusdb knowledge base] Introduction to tcapulusdb tcapsvrmgr tool (I)
【TcaplusDB知识库】TcaplusDB-tcaplusadmin工具介绍
Jerry's adding timer interrupt [chapter]
杰理之无缝循环播放【篇】
AutoCAD - three pruning methods
L'utilisation de C language 0 length Array
【值得收藏】Centos7 安装mysql完整操作命令
The wonderful use of 0 length array in C language
[tcapulusdb knowledge base] tcapulusdb doc acceptance - create business introduction
深入理解 happens-before 原则
Leetcode 522 longest special sequence ii[enumeration double pointer] leetcode path of heroding
Glide caching mechanism
Detailed explanation of interprocess communication
星际争霸的虫王IA退役2年搞AI,自叹不如了