alibaba jarslink框架教程

demo的github地址:https://github.com/superRabbitMan/jarslink-demo
<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
<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; /** * 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 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文件中不需要使用<bean id=”” name=”” class=””
/>配置信息,而是在调用的时候扫描指定的包即可,下面是关键的代码。
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是否有更新,如果有更新就进行加载。

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信