创建一个工程,包含3个模块

父工程里面的配置
父工程的Pom文件,管理版本
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<packaging>pom</packaging>
<modules>
<module>dynamic-stock-mng</module>
<module>dynamic-provider</module>
<module>dynamic-facade</module>
</modules>
<parent>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofaboot-dependencies</artifactId>
<version>3.2.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>io.sofastack</groupId>
<artifactId>sofachannel-demo</artifactId>
<version>1.0.0</version>
<name>sofachannel-demo</name>
<description>Demo project for SofaStack Dynamic Module</description>
<properties>
<java.version>1.8</java.version>
<ark.version>1.0.0</ark.version>
<dashboard.client>1.0.0</dashboard.client>
<curator.version>2.9.1</curator.version>
<mybatis.version>1.3.2</mybatis.version>
<mysql.version>5.1.46</mysql.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-dashboard-client</artifactId>
<version>${dashboard.client}</version>
</dependency>
<!-- 引用ark web插件-->
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>web-ark-plugin</artifactId>
<version>${ark.version}</version>
</dependency>
<!-- 引用ark 配置推送扩展插件-->
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>config-ark-plugin</artifactId>
<version>${ark.version}</version>
</dependency>
<dependency>
<artifactId>curator-client</artifactId>
<groupId>org.apache.curator</groupId>
<version>${curator.version}</version>
</dependency>
<dependency>
<artifactId>curator-framework</artifactId>
<groupId>org.apache.curator</groupId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>io.sofastack</groupId>
<artifactId>dynamic-facade</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.21.0</version>
</plugin>
</plugins>
</build>
</project>
在facade里面定义方法
在provider里面实现facade里的方法
如果业务经常会涉及controller层的变动,也可以再provider里面写controller层
provider的pom文件,代码如下
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sofachannel-demo</artifactId>
<groupId>io.sofastack</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dynamic-provider</artifactId>
<version>1.0.1</version>
<dependencies>
<!--facade模块依赖-->
<dependency>
<groupId>io.sofastack</groupId>
<artifactId>dynamic-facade</artifactId>
</dependency>
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>runtime-sofa-boot-plugin</artifactId>
</dependency>
<!--健康检查能力依赖-->
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>healthcheck-sofa-boot-starter</artifactId>
</dependency>
<!-- <dependency>-->
<!-- <artifactId>curator-client</artifactId>-->
<!-- <groupId>org.apache.curator</groupId>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <artifactId>curator-framework</artifactId>-->
<!-- <groupId>org.apache.curator</groupId>-->
<!-- </dependency>-->
<!--增加web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--子模块如果要添加了web依赖,必须要添加这个类隔离的依赖,否则项目启动不了,-->
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-ark-springboot-starter</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<!--这里添加ark 打包插件-->
<plugin>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-ark-maven-plugin</artifactId>
<executions>
<execution>
<!--goal executed to generate executable-ark-jar -->
<goals>
<goal>repackage</goal>
</goals>
<!--ark-biz 包的打包配置 -->
<configuration>
<!--是否打包、安装和发布 ark biz,详细参考 Ark Biz 文档,默认为false-->
<attach>true</attach>
<!--ark 包和 ark biz 的打包存放目录,默认为工程 build 目录-->
<outputDirectory>target</outputDirectory>
<!--default none-->
<arkClassifier>executable-ark</arkClassifier>
<!-- ark-biz 包的启动优先级,值越小,优先级越高-->
<priority>200</priority>
<!--设置应用的根目录,用于读取 ${base.dir}/conf/ark/bootstrap.application 配置文件,默认为 ${project.basedir}-->
<baseDir>../</baseDir>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
最后是master biz
BizController可以通过接口来install 和 uninstall ark biz
package io.sofastack.stockmng.controller;
import com.alipay.sofa.ark.api.ArkClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
@RestController
@Slf4j
public class BizController {
@RequestMapping(value = "/installBiz", method = RequestMethod.POST)
public String installBiz(@RequestParam(value = "url") String url) throws Throwable {
log.info("url为:{}",url);
File file = new File(url);
ArkClient.installBiz(file);
return "调用成功";
}
@RequestMapping(value = "/uninstallBiz", method = RequestMethod.POST)
public void uninstallBiz(String bizName, String bizVersion) throws Throwable {
ArkClient.uninstallBiz(bizName, bizVersion);
}
@RequestMapping(value = "/switchBiz", method = RequestMethod.POST)
public void switchBiz(String bizName, String bizVersion) {
ArkClient.switchBiz(bizName, bizVersion);
}
}
indexController来测试改变provider里面的实现方法能否改变已经运行的项目的业务逻辑
package io.sofastack.stockmng.controller;
import com.alipay.sofa.runtime.api.annotation.SofaReference;
import io.sofastack.dynamic.facade.StrategyService;
import io.sofastack.dynamic.model.ProductInfo;
import io.sofastack.stockmng.data.DatabaseSeed;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.ArrayList;
import java.util.List;
@Controller
public class IndexController {
@SofaReference
private StrategyService strategyService;
@RequestMapping("/")
public String index(Model model) {
model.addAttribute("productList", strategyService.strategy(initProducts()));
return "index";
}
@ResponseBody
@RequestMapping("/sort")
public String sort() {
String test = strategyService.test();
return test;
}
/**
* 初始化默认展示列表,为了实验效果,此处初始化的列表与实际列表是相反的,但是实际排序结果与现场购买订单直接挂钩
*
* @return
*/
private List<ProductInfo> initProducts() {
List<ProductInfo> products = new ArrayList<>(5);
for (int i = 4; i >= 0; i--) {
ProductInfo productInfo = new ProductInfo();
productInfo.setName(DatabaseSeed.name[i]);
productInfo.setOrderCount(DatabaseSeed.orderCount[i]);
productInfo.setSrc(DatabaseSeed.imageUrls[i]);
productInfo.setAuthor(DatabaseSeed.authors[i]);
products.add(productInfo);
}
return products;
}
}
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>sofachannel-demo</artifactId>
<groupId>io.sofastack</groupId>
<version>1.0.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>dynamic-stock-mng</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--此组件提供异步初始化 Spring Bean 能力-->
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>runtime-sofa-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.sofastack</groupId>
<artifactId>dynamic-facade</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 这里添加动态模块相关依赖 -->
<!--类隔离组件 sofa-ark-springboot-starter-->
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-ark-springboot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alipay.sofa</groupId>
<artifactId>web-ark-plugin</artifactId>
</dependency>
<!--引入子模块的biz-->
<dependency>
<groupId>io.sofastack</groupId>
<artifactId>dynamic-provider</artifactId>
<version>1.0.0</version>
<classifier>ark-biz</classifier>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 这里配置动态模块打包插件 -->
<plugin>
<groupId>com.alipay.sofa</groupId>
<artifactId>sofa-ark-maven-plugin</artifactId>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
<configuration>
<priority>100</priority>
<baseDir>../</baseDir>
<bizName>stock-mng</bizName>
</configuration>
</plugin>
</plugins>
</build>
</project>
测试,直接package整个项目,拿到master biz的ark-excutable.jar这个jar包,运行
通过postman测试master biz的接口
再看看provider biz的接口
test2是被注释掉的,所以没有办法调用。
接下来修改provider
实现的方法改成654321
把第二个接口放出来
修改pom文件里面的version
重新package
获取provider 1.0.1版本的ark-biz的jar包
此时我们可以通过telnet命令连接到ark
可以看到之前provider的版本是1.0.0,如果你的provider没有web依赖,不提供controller层,只是负责实现service的具体方法,可以在直接install上去再切换provider的版本。但如果你的provider要提供controller接口,那么必须先把之前的1.0.0版本的provider uninstall之后才能install上去。因为只要install上去之后,controller层就会加载好。而你1.0.1版本的server.servlet.context-path 跟1.0.0版本是相同的,会导致失败,所以需要先uninstall。如果你把1.0.1版本的server.servlet.context-path修改一下,install上去之后,就算不处于激活状态,1.0.1版本的接口也是可以访问的。
在这里我们先uninstall
系统提示正在uninstall ,我们再看看版本
此时,provider已经卸载掉了,再去调用provider提供的接口会报404,去调用sort接口会报500
我们把1.0.1版本给他install上,我在网上看到的教程都是可以通过biz -i 指令进行install,但是我一直install不上去。
如上画所示,虽然提示了正在install,但是等了很久,我再去查看,依然只有孤零零的一个master biz
好在我们提供了接口,通过bizController接口调用ark内置的命令来install,也就是我们之前写的BizController里面的方法。
我们来调用一下
提示成功了,去看一下呢
已经成功install了,我们去看一下接口
sort的业务逻辑已经改变了,返回的数字变成了654321
1.0.1版本provider提供的两个controller接口也调用成功。
这里我们的demo测试基本完成了,但是我还是遇到了一个小问题,当我不需要某个provider biz的jar包的时候,删不掉,提示我正在被占用,有没有哪位大佬能告诉我怎么解决啊。