├── .gitignore ├── README.md ├── conf └── ark │ ├── bootstrap.properties │ └── log │ └── logback-conf.xml ├── dynamic-facade ├── pom.xml └── src │ └── main │ └── java │ └── io │ └── sofastack │ └── dynamic │ └── facade │ └── StrategyService.java ├── dynamic-provider ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── sofastack │ │ └── dynamic │ │ └── provider │ │ ├── ProviderApplication.java │ │ └── impl │ │ └── StrategyServiceImpl.java │ └── resources │ └── application.properties ├── dynamic-stock-mng ├── pom.xml └── src │ └── main │ ├── java │ └── io │ │ └── sofastack │ │ └── stockmng │ │ ├── StockMngApplication.java │ │ ├── controller │ │ └── SortedController.java │ │ ├── facade │ │ └── SortedStrategyFacade.java │ │ ├── impl │ │ ├── DatabaseSeed.java │ │ └── SortedStrategyImpl.java │ │ ├── mapper │ │ └── StockMngMapper.java │ │ ├── model │ │ ├── BalanceResponse.java │ │ ├── ProductInfo.java │ │ └── Success.java │ │ └── util │ │ └── CommonUtil.java │ └── resources │ ├── application.properties │ ├── logback-spring.xml │ └── templates │ └── index.html ├── formatter.xml └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | bin 3 | bak 4 | .pmd 5 | .project 6 | .settings 7 | .classpath 8 | .idea.xml 9 | .idea 10 | *.class 11 | *.bak 12 | *.iml 13 | *.ipr 14 | *.iws 15 | .DS_Store 16 | nb-configuration.xml 17 | coverage-report 18 | logs 19 | *.log -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SOFABoot 动态模块实践 2 | 3 | **注意:您需要自行部署后端环境依赖,并修改示例中的服务依赖地址即可使用。** 4 | 5 | * [实验背景](#%E5%AE%9E%E9%AA%8C%E8%83%8C%E6%99%AF) 6 | * [实验内容](#%E5%AE%9E%E9%AA%8C%E5%86%85%E5%AE%B9) 7 | * [任务](#%E4%BB%BB%E5%8A%A1) 8 | * [任务准备](#1%E4%BB%BB%E5%8A%A1%E5%87%86%E5%A4%87) 9 | * [将 SOFABoot 应用打包成 ark 包](#2%E5%B0%86-sofaboot-%E5%BA%94%E7%94%A8%E6%89%93%E5%8C%85%E6%88%90-ark-%E5%8C%85) 10 | * [修改动态模块名称](#step1--%E4%BF%AE%E6%94%B9%E5%8A%A8%E6%80%81%E6%A8%A1%E5%9D%97%E5%90%8D%E7%A7%B0) 11 | * [配置动态模块的打包插件](#step2--%E9%85%8D%E7%BD%AE%E5%8A%A8%E6%80%81%E6%A8%A1%E5%9D%97%E7%9A%84%E6%89%93%E5%8C%85%E6%8F%92%E4%BB%B6) 12 | * [构建宿主应用](#3%E6%9E%84%E5%BB%BA%E5%AE%BF%E4%B8%BB%E5%BA%94%E7%94%A8) 13 | * [引入动态模块依赖](#step1--%E5%BC%95%E5%85%A5%E5%8A%A8%E6%80%81%E6%A8%A1%E5%9D%97%E4%BE%9D%E8%B5%96) 14 | * [宿主应用配置](#step2--%E5%AE%BF%E4%B8%BB%E5%BA%94%E7%94%A8%E9%85%8D%E7%BD%AE) 15 | * [打包 & 启动宿主应用](#4%E6%89%93%E5%8C%85--%E5%90%AF%E5%8A%A8%E5%AE%BF%E4%B8%BB%E5%BA%94%E7%94%A8) 16 | * [SOFADashboard 添加版本&管理应用](#5sofadashboard-%E7%AE%A1%E6%8E%A7%E7%AB%AF%E6%B7%BB%E5%8A%A0%E7%89%88%E6%9C%AC) 17 | * [查看详情 & 推送安装命令](#6%E6%9F%A5%E7%9C%8B%E8%AF%A6%E6%83%85--%E6%8E%A8%E9%80%81%E5%AE%89%E8%A3%85%E5%91%BD%E4%BB%A4) 18 | 19 | ## 实验背景 20 | 21 | [kc-sofastack-demo](https://github.com/sofastack-guides/kc-sofastack-demo) 分享中已经通过 SOFAStack 快速构建了一个电商微服务应用, 22 | 并且完成了对应用服务调用链路的跟踪及应用状态的监控。 23 | 24 | 在电商系统中,平台方往往不会满足商品的自然排序展示,必定会根据某种规则来将部分商品放置在列表最瞩目的地方, 25 | 当然也可能是平台方通过收集用户行为动态的为每个不同的用户推荐不同的商品展示列表。 26 | 27 | 本实验背景就是基于[kc-sofastack-demo](https://github.com/sofastack-guides/kc-sofastack-demo)的基础上, 28 | 根据现场同学对每个商品的购买总数(通过订单统计)来对商品列表进行动态排序。 29 | 30 | ## 实验内容 31 | 32 | 通过 SOFABoot 提供的动态模块能力及 SOFADashboard 的动态模块管控能力,实现商品列表排序策略的动态变更。通过在不重启宿主机,不更改应用配置的情况下实现 33 | 应用行为的改变。 34 | 35 | * 项目工程架构图如下 36 | 37 | ![image.png](https://gw.alipayobjects.com/mdn/rms_565baf/afts/img/A*ECEjR5hY0h0AAAAAAAAAAABkARQnAQ) 38 | 39 | ## 任务 40 | 41 | ### 1、任务准备 42 | 43 | 从 github 上将 demo 工程克隆到本地 44 | 45 | ```bash 46 | git clone https://github.com/sofastack-guides/kc-sofastack-dynamic-demo.git 47 | ``` 48 | 49 | 然后将工程导入到 IDEA 或者 eclipse。 50 | 51 | ### 2、将 SOFABoot 应用打包成 ark 包 52 | 53 | 54 | 55 | #### step1 : 修改动态模块名称 56 | 57 | > 在实际的应用场景中,不需要对其进行任何修改 58 | 59 | 如下图所示,对 dynamic-module/pom.xml 中的 artifactId 进行修改,将 {your-number} 修改为当前座位上的编号 60 | 61 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*3aiqQpJL7VwAAAAAAAAAAABkARQnAQ) 62 | 63 | #### step2 : 配置动态模块的打包插件 64 | 65 | 在 dynamic-provider/pom.xml 中,增加 ark 打包插件,并进行配置: 66 | 67 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*y2BvRKG14JUAAAAAAAAAAABkARQnAQ) 68 | 69 | 70 | ```xml 71 | 72 | com.alipay.sofa 73 | sofa-ark-maven-plugin 74 | 0.6.0 75 | 76 | 77 | 78 | 79 | repackage 80 | 81 | 82 | 83 | 84 | true 85 | 86 | target 87 | 88 | executable-ark 89 | 90 | 200 91 | 92 | ../ 93 | 94 | 95 | 96 | 97 | ``` 98 | 99 | ### 3、构建宿主应用 100 | 101 | 在已下载下来的工程中,dynamic-stock-mng 作为实验的宿主应用工程模型。通过此任务,将 dynamic-stock-mng 构建成为动态模块的宿主应用。 102 | 103 | #### step1 : 引入动态模块依赖 104 | 105 | > 动态模块是通过 SOFAArk 组件来实现的,因此次数需要引入 SOFAArk 相关的依赖即可。关于 SOFAArk 可以参考[SOFABoot 类隔离](https://www.sofastack.tech/projects/sofa-boot/sofa-ark-readme/) 106 | 一节进行了解。 107 | 108 | ![image.png](https://gw.alipayobjects.com/mdn/rms_565baf/afts/img/A*lM_1SoNIXIYAAAAAAAAAAABkARQnAQ) 109 | 110 | * SOFAArk 相关依赖 111 | 112 | ```xml 113 | 114 | com.alipay.sofa 115 | sofa-ark-springboot-starter 116 | 117 | 118 | com.alipay.sofa 119 | web-ark-plugin 120 | 121 | 122 | com.alipay.sofa 123 | config-ark-plugin 124 | 125 | 126 | io.sofastack 127 | dynamic-provider-{your-number} 128 | 1.0.0 129 | ark-biz 130 | 131 | ``` 132 | 将此配置文件中的 {your-number} 替换为当前座位编号 133 | 134 | * 宿主应用打包插件 135 | 136 | ```xml 137 | 138 | com.alipay.sofa 139 | sofa-ark-maven-plugin 140 | 0.6.0 141 | 142 | 143 | default-cli 144 | 145 | repackage 146 | 147 | 148 | 149 | 150 | 100 151 | ../ 152 | stock-mng-{your-number} 153 | 154 | 155 | ``` 156 | 157 | 将打包插件中的 {your-number} 替换为当前座位上的编号,同样在实际的场景中是不需要的。这里是希望通过应用名来进行隔离,已达到各位在实际操作中不会相互干扰。 158 | 159 | #### step2 : 宿主应用配置 160 | 161 | * 动态模块配置 162 | 163 | 在当前项目的根目录 /conf/ark/bootstrap.properties 配置文件中添加配置如下: 164 | 165 | ```properties 166 | # 日志根目录 167 | logging.path=./logs 168 | # 配置服务器地址 169 | com.alipay.sofa.ark.config.address=zookeeper://116.62.20.143:2181,116.62.148.186:2181,121.43.174.16:2181 170 | # 宿主应用名 171 | com.alipay.sofa.ark.master.biz=stock-mng-{your-number} 172 | ``` 173 | com.alipay.sofa.ark.master.biz 配置项为指定的动态模块宿主应用的名称,需与宿主应用打包插件中的 bizName 配置项保持一致。 174 | 因此需要将 {your-number} 也替换为当前座位前的编号。 175 | 176 | * SOFADashboard 客户端配置 177 | 178 | 在 dynamic-stock-mng 的 resource/application.properties 配置文件中添加配置如下: 179 | 180 | ```properties 181 | management.endpoints.web.exposure.include=* 182 | com.alipay.sofa.dashboard.zookeeper.address=116.62.20.143:2181,116.62.148.186:2181,121.43.174.16:2181 183 | #skip jvm health check to startup host-app 184 | com.alipay.sofa.boot.skip-jvm-reference-health-check=true 185 | ``` 186 | 187 | 同时将此配置文件中的 {your-number} 替换为当前座位编号: 188 | 189 | ```properties 190 | # 替换 {your-number} 为当前座位编号 191 | spring.application.name=stock-mng-{your-number} 192 | ``` 193 | 194 | ### 4、打包 & 启动宿主应用 195 | 196 | #### 执行 mvn clean package 197 | 198 | 配置完成之后,执行 mvn clean package 进行打包,此时 dynamic-provider 会被打包成动态模块包,如下图所示: 199 | 200 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*c5enTa0foPsAAAAAAAAAAABkARQnAQ) 201 | 202 | > 比如如果你填写的 {your-number} 为 00 ,则打包成功之后,会生成 dynamic-module/target 目录下 生成 dynamic-provider-00-1.0.0-ark-biz.jar 文件 203 | 204 | #### 启动宿主应用 205 | 206 | ```bash 207 | java -jar dynamic-stock-mng/target/dynamic-stock-mng-1.0.0.jar 208 | ``` 209 | 210 | 启动成功之后日志信息如下: 211 | 212 | ![image.png](https://gw.alipayobjects.com/mdn/rms_565baf/afts/img/A*3N_nS6P223IAAAAAAAAAAABkARQnAQ) 213 | 214 | ### 5、SOFADashboard 管控端添加版本 215 | 216 | 在实际的操作中,一般需要手动录入动态模块信息,本次 workshop 中为了方便大家操作,已经事先将00-99 100 个插件录入到了数据库中。 217 | 218 | 请先现场下载:`sofa-dashboard-web-1.0.0-SNAPSHOT.jar` 这个已经打包好的 sofa-dashborad 启动包。 219 | 220 | 然后运行 `java -jar sofa-dashboard-web-1.0.0-SNAPSHOT.jar` 将它启动起来。 221 | 222 | 我们访问 http://localhost:8099/ 看到 sofa-dashboard 界面。 223 | 224 | 我们打开「Ark 管控 - 模块列表」菜单,可以看下如下信息: 225 | 226 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*F-RGTLZJYj8AAAAAAAAAAABkARQnAQ) 227 | 228 | 在查询框中输入你当前座位的编号,(例如你的编号为66): 229 | 230 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*x836RaqJ9QkAAAAAAAAAAABkARQnAQ) 231 | 232 | 点击查询之后将会索引到你的插件,此时可以基于此插件进行应用关联和版本添加。 233 | 234 | * 关联应用 235 | 236 | 点击关联应用,将插件绑定到宿主应用。此处的宿主应用名为 dynamic-stock-mng application.properties 中的 spring.application.name 的值, 237 | 如 spring.application.name=stock-mng-66,则你当前操作的宿主应用名即为 stock-mng-66 238 | 239 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*ZdXDS6YCQp4AAAAAAAAAAABkARQnAQ) 240 | 241 | * 添加版本 242 | 243 | 目前 SOFADashboard 支持两种协议的文件获取方式,一种是基于 http 协议的,一种是基于 file 协议的。基于 http 协议即你可以将自己的动态模块包放在一个http 244 | 服务器上,例如:http://ip:port/filePth 类型路径;基于 file 协议则是直接从文件系统获取动态模块包,例如:file://filePath。这里因为都是基于本地打包,所以使用 file 245 | 协议。 246 | 247 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*ce6hR79Z-eQAAAAAAAAAAABkARQnAQ) 248 | 249 | 例如我打包之后的文件位于 /Users/guolei.sgl/Downloads/kubecon/kc-sofastack-dynamic-demo/dynamic-provider/target 目录下,则需要在添加版本中填入的文件地址为: 250 | file:///Users/guolei.sgl/Downloads/kubecon/kc-sofastack-dynamic-demo/dynamic-provider/target/dynamic-provider-00-1.0.0-ark-biz.jar 251 | 252 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*b0wcQbCFOasAAAAAAAAAAABkARQnAQ) 253 | 254 | > dynamic-provider-00-1.0.0-ark-biz.jar 中 00 为你当前座位的编号 255 | 256 | ### 6、查看详情 & 推送安装命令 257 | 258 | 在执行安装之前,可以 先访问下 http://localhost:8080 ,此处因为还没有模块提供 jvm 服务,因此展示的是默认的排序顺序,如下所示: 259 | 260 | ![image.png](https://gw.alipayobjects.com/mdn/rms_565baf/afts/img/A*cKbZQIpM7GkAAAAAAAAAAABkARQnAQ) 261 | 262 | 点击当前插件后面的详情,进入插件详情页 263 | 264 | ![image.png](https://gw.alipayobjects.com/mdn/rms_565baf/afts/img/A*9gkxSoxPnqUAAAAAAAAAAABkARQnAQ) 265 | 266 | 然后点击安装,延迟1~2s之后,状态变更为 ACTIVATED ,为激活状态 267 | 268 | ![image.png](https://gw.alipayobjects.com/mdn/rms_565baf/afts/img/A*Eft7SbV1xFEAAAAAAAAAAABkARQnAQ) 269 | 270 | 此时再次访问 http://localhost:8080 ,结果如下: 271 | 272 | ![image.png](https://gw.alipayobjects.com/mdn/rms_ff360b/afts/img/A*-34JS7hBxAcAAAAAAAAAAABkARQnAQ) 273 | 274 | 275 | > 此结果仅供参考,排序结果随商品对应的订单量而动态改变 276 | 277 | 278 | ## 更多 279 | 280 | - [下载本次 Demo 幻灯片](https://gw.alipayobjects.com/os/basement_prod/763325e6-81c9-4961-9d24-5a4ba9970b36.pdf)。 281 | -------------------------------------------------------------------------------- /conf/ark/bootstrap.properties: -------------------------------------------------------------------------------- 1 | # 动态模块配置 2 | -------------------------------------------------------------------------------- /conf/ark/log/logback-conf.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | true 22 | 23 | error 24 | ACCEPT 25 | DENY 26 | 27 | ${logging.path}/sofa-ark/common-error.log 28 | 29 | ${logging.path}/sofa-ark/common-error.log.%d{yyyy-MM-dd} 30 | 30 31 | 32 | 33 | %d %-5p %-32t - %m%n 34 | ${file.encoding} 35 | 36 | 37 | 38 | 39 | true 40 | 41 | ${logging.level.com.alipay.sofa.ark} 42 | ACCEPT 43 | DENY 44 | 45 | ${logging.path}/sofa-ark/ark-default.log 46 | 47 | ${logging.path}/sofa-ark/common-default.log.%d{yyyy-MM-dd} 48 | 30 49 | 50 | 51 | %d %-5p %-32t - %m%n 52 | ${file.encoding} 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /dynamic-facade/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | kc-sofastack-dynamic-demo 7 | io.sofastack 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | dynamic-facade 13 | 14 | -------------------------------------------------------------------------------- /dynamic-facade/src/main/java/io/sofastack/dynamic/facade/StrategyService.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.dynamic.facade; 2 | 3 | /** 4 | * @author: guolei.sgl (guolei.sgl@antfin.com) 2019/6/19 10:21 AM 5 | * @since: 6 | **/ 7 | public interface StrategyService { 8 | String strategy(); 9 | } 10 | -------------------------------------------------------------------------------- /dynamic-provider/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | kc-sofastack-dynamic-demo 7 | io.sofastack 8 | 1.0.0 9 | 10 | 4.0.0 11 | 12 | dynamic-provider-{your-number} 13 | 14 | 15 | 16 | io.sofastack 17 | dynamic-facade 18 | 19 | 20 | com.alipay.sofa 21 | runtime-sofa-boot-plugin 22 | 23 | 24 | com.alipay.sofa 25 | healthcheck-sofa-boot-starter 26 | 27 | 28 | curator-client 29 | org.apache.curator 30 | 31 | 32 | curator-framework 33 | org.apache.curator 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /dynamic-provider/src/main/java/io/sofastack/dynamic/provider/ProviderApplication.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.dynamic.provider; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | /** 7 | * @author: guolei.sgl (guolei.sgl@antfin.com) 2019/6/12 7:48 PM 8 | * @since: 9 | **/ 10 | @SpringBootApplication 11 | public class ProviderApplication { 12 | public static void main(String[] args) { 13 | SpringApplication.run(ProviderApplication.class, args); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dynamic-provider/src/main/java/io/sofastack/dynamic/provider/impl/StrategyServiceImpl.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.dynamic.provider.impl; 2 | 3 | import com.alipay.sofa.runtime.api.annotation.SofaService; 4 | import io.sofastack.dynamic.facade.StrategyService; 5 | import org.springframework.stereotype.Service; 6 | 7 | /** 8 | * @author: guolei.sgl (guolei.sgl@antfin.com) 2019/6/12 7:49 PM 9 | * @since: 10 | **/ 11 | @Service 12 | @SofaService 13 | public class StrategyServiceImpl implements StrategyService { 14 | 15 | @Override 16 | public String strategy() { 17 | return "order"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /dynamic-provider/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | spring.application.name=dynamic-provider 2 | server.port=8801 3 | logging.path=./logs/provider -------------------------------------------------------------------------------- /dynamic-stock-mng/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | kc-sofastack-dynamic-demo 7 | io.sofastack 8 | 1.0.0 9 | 10 | 4.0.0 11 | dynamic-stock-mng 12 | 13 | 14 | org.springframework.boot 15 | spring-boot-starter-thymeleaf 16 | 17 | 18 | org.springframework.boot 19 | spring-boot-starter-web 20 | 21 | 22 | com.alipay.sofa 23 | runtime-sofa-boot-starter 24 | 25 | 26 | org.mybatis.spring.boot 27 | mybatis-spring-boot-starter 28 | 29 | 30 | mysql 31 | mysql-connector-java 32 | 33 | 34 | io.sofastack 35 | dynamic-facade 36 | 37 | 38 | com.alipay.sofa 39 | sofa-dashboard-client 40 | 41 | 42 | curator-client 43 | org.apache.curator 44 | 45 | 46 | curator-framework 47 | org.apache.curator 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/StockMngApplication.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class StockMngApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(StockMngApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/controller/SortedController.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.controller; 2 | 3 | import io.sofastack.stockmng.facade.SortedStrategyFacade; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.stereotype.Controller; 6 | import org.springframework.ui.Model; 7 | import org.springframework.web.bind.annotation.RequestMapping; 8 | 9 | /** 10 | * @author: guolei.sgl (guolei.sgl@antfin.com) 2019/6/19 5:44 PM 11 | * @since: 12 | **/ 13 | @Controller 14 | public class SortedController { 15 | 16 | @Autowired 17 | private SortedStrategyFacade sortedStrategyFacade; 18 | 19 | @RequestMapping("/") 20 | public String index(Model model) { 21 | model.addAttribute("productList", sortedStrategyFacade.getSorted()); 22 | return "index"; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/facade/SortedStrategyFacade.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.facade; 2 | 3 | import io.sofastack.stockmng.model.ProductInfo; 4 | 5 | import java.util.List; 6 | 7 | /** 8 | * @author: guolei.sgl (guolei.sgl@antfin.com) 2019/6/19 10:41 AM 9 | * @since: 10 | **/ 11 | public interface SortedStrategyFacade { 12 | /** 13 | * 获取排序后的商品列表 14 | * 15 | * @return 16 | */ 17 | List getSorted(); 18 | } 19 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/impl/DatabaseSeed.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.impl; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class DatabaseSeed { 6 | public static String[] name = new String[] { "未来架构: 从服务化到云原生", 7 | "Cloud Native Go: 构建基于Go和React的云原生Web应用与微服务", 8 | "云原生Java: Spring Boot、Spring Cloud与Cloud Foundry弹性系统设计", 9 | "Python云原生: 构建应对海量用户数据的高可扩展Web应用", "深入浅出Istio: Service Mesh快速入门与实践" }; 10 | 11 | public static BigDecimal[] price = new BigDecimal[] { new BigDecimal(99), 12 | new BigDecimal(69), new BigDecimal(128), new BigDecimal(89), new BigDecimal(79), }; 13 | 14 | public static String[] description = new String[] { 15 | "{\n" 16 | + " \"description\": " 17 | + "\"
互联网架构不断演化,经历了从集中式架构到分布式架构,再到云原生架构的过程。云原生因能解决传统应用升级缓慢、架构臃肿、无法快速迭代等问题而成了未来云端应用的目标。《未来架构:从服务化到云原生》首先介绍架构演化过程及云原生的概念,让读者对基础概念有一个准确的了解,接着阐述分布式、服务化、可观察性、容器调度、Service Mesh、云数据库等技术体系及原理,并介绍相关的SkyWalking、Dubbo、Spring Cloud、Kubernetes、Istio等开源解决方案,最后深度揭秘开源分布式数据库生态圈ShardingSphere的设计、实现,以及进入Apache基金会的历程,非常适合架构师、云计算从业人员阅读、学习。

张亮

京东数科数据研发负责人,Apache Sharding-Sphere发起人兼PPMC成员。热爱分享,拥抱开源,主张代码优雅化,擅长以Java为主的分布式架构及以Kubernetes和Mesos为主的云平台的构建。ShardingSphere已进入Apache软件基金会,是京东集团首个进入Apache的开源项目,也是Apache首个分布式数据库中间件。

吴晟

Apache SkyWalking创始人及PPMC成员,Apache ShardingSphere原型作者及PPMC成员,Apache Zipkin贡献者,Apache孵化器导师,CNCF基金会OpenTracing标准化委员会成员,W3C Trace Context规范贡献者。擅长分布式架构、性能监控与诊断、分布式追踪、云原生监控等领域。

敖小剑

具有十七年软件开发经验,资深码农,微服务专家,Cloud Native拥护者,敏捷实践者,ServiceMesh布道师,ServicelMesher中文社区联合创始人。专注于基础架构建设,对微服务、云计算等相关技术有着深入研究和独到见解。

宋净超

蚂蚁金服云原生布道师,ServiceMesher中文社区联合创始人,Kubemetes社区成员,Istio社区成员,《Cloud Native Go》《Python云原生》《云原生Java》等图书译者。

\",\n" 19 | + " \"author\": \"张亮, 吴晟, 敖小剑, 宋净超\",\n" 20 | + " \"image_url\": \"http://reserved-antcloud-cnshnfpub-opsware-v2.oss-cn-shanghai.aliyuncs" 21 | + ".com/fas/books/1.png?OSSAccessKeyId=RZU9wKztYEqaBQGB&Expires=1647166160&Signature=xCS%2FpJtY8" 22 | + "%2FVcdbLqfjHUp6z%2FoOw%3D\"\n" + "}\n", 23 | 24 | "{\n" 25 | + " \"description\": \"

本书旨在向开发人员展示如何构建适用于大流量、高并发场景下的云原生Web应用。本书从搭建开发测试环境开始,逐步介绍使用Go" 26 | + "语言构建微服务的方法,通过引入CI/CD流程和Wercker、Docker等工具将应用推送到云中。结合微服务构建中的后端服务、数据服务、事件溯源和CQRS模式、基于React和Flux的UI" 27 | + "设计等,本书最后构建了一个基于Web的RPG游戏World of FluxCraft,可以作为使用Go构建云原生Web应用的参考,适合于云计算与Go语言编程从业者们阅读。

1" 28 | + ".云原生是云计算时代的发展趋势和必然结果

《Cloud Native " 29 | + "Go:构建基于Go和React的云原生Web应用与微服务》通过一个云原生应用项目的构建,为大家介绍了云原生的道与术,引导读者了解云原生理念的产生、应用场景、优势。

2" 30 | + ".集现今诸多热点技术之大成

《Cloud Native Go:构建基于Go和React的云原生Web应用与微服务》在构建云原生项目时,涉及Docker、持续集成、微服务、DevOps" 31 | + "、事件溯源与CQRS等众多备受关注的技术热点,无疑会让读者受益匪浅。

3.Go语言助理云开发完美实现

Go" 32 | + "语言以其简单优雅、快速安全、支持高并发等特性,成为云计算时代的最优语言。《Cloud Native " 33 | + "Go:构建基于Go和React的云原生Web应用与微服务》将带领读者正确认识Go语言,掌握用Go构建应用程序的方法。

4.流程完整,示例具体详细

《Cloud Native " 34 | + "Go:构建基于Go和React的云原生Web应用与微服务》从搭建平台开始,逐步带领读者开发一个完整的云上项目。其中的每一环节都有详细讲解。示例具有代表性,代码详细,帮助读者轻松掌握云原生开发的关键。

\",\n" 36 | + " \"author\": \"Kevin Hoffman, 宋净超\",\n" 37 | + " \"image_url\": \"http://reserved-antcloud-cnshnfpub-opsware-v2.oss-cn-shanghai.aliyuncs" 38 | + ".com/fas/books/2.png?OSSAccessKeyId=RZU9wKztYEqaBQGB&Expires=1647166182&Signature" 39 | + "=U4ep6Dsh4w8TqW6tLlDLoEopIm4%3D\"\n" + "}\n", 40 | 41 | "{\n" 42 | + " \"description\": \"

无论是传统IT行业,还是互联网行业,都正处于行业历史上最剧烈的变革中 :大量的系统正在从传统的IT架构转向基于云的架构, " 43 | + "开发模式也正在从开发和运维分工的传统模式,逐渐转向统一的“DevOps”模式。Java技术已经进入了新的生命周期,大量被用于构建现代的、基于云的应用程序。 " 44 | + "本书详细阐述了开发云原生应用程序的机遇和挑战,明确指出了成功实现的方向,并且重点介绍了微服务框架Spring Boot。Spring Boot可以轻松创建任何粒度的 " 45 | + "Spring服务,并部署到现代的容器环境中。本书主要面向正在使用 Spring Boot、SpringCloud和Cloud Foundry, 以便更快、更好地构建软件的Java/JVM " 46 | + "开发人员。本书一共分为4个部分共15章。第1章和第2章介绍了云原生思想产生的背景,然后介绍了Spring Foundry。第3章介绍了如何配置Spring " 47 | + "Boot应用程序。第4章介绍了如何测试Spring应用程序,从如何测试最简单的组件到测试分布式系统。第5章介绍了可以将应用程序迁移到Cloud " 48 | + "Foundry等云平台的轻量级重构方式。第6章介绍了如何使用Spring构建HTTP和RESTful服务。第7章介绍了在分布式系统中控制请求进出的常用方法。第8章介绍了如何构建一个响应外部请求的服务。第9" 49 | + "章介绍了如何使用Spring Data在Spring中管理数据。这为领域驱动的思想奠定了基础。第10章介绍了如何使用Spring中事件驱动、消息中心化的能力,来集成分布式服务和数据。第11" 50 | + "章介绍了如何利用云平台(如Cloud Foundry)的能力来处理长期运行的工作。第12章介绍了在分布式系统中管理状态的一些方法。第13章介绍了如何构建具备可观测性和可操作性的系统。第14" 51 | + "章介绍了如何构建类似于Cloud Foundry平台的服务代理。第15章介绍了持续交付背后的思想。

1. 基础知识

了解云原生思维背后的动机;配置和测试Spring " 52 | + "Boot应用程序;将您的传统应用程序迁移至云端

2. 微服务

使用Spring构建HTTP和RESTful服务;在分布式系统中路由请求;建立更接近数据的边缘服务

3. " 53 | + "数据整合

使用Spring Data管理数据,并将分布式服务与——Spring对事件驱动、以消息传递为中心架构的支持——集成起来

4. " 54 | + "生产

让您的系统可观察;使用服务代理来连接有状态的服务;了解持续交付背后的重要思想

\",\n" 55 | + " \"author\": \"Josh Long, 张若飞, 宋净超\",\n" 56 | + " \"image_url\": \"http://reserved-antcloud-cnshnfpub-opsware-v2.oss-cn-shanghai.aliyuncs" 57 | + ".com/fas/books/3.png?OSSAccessKeyId=RZU9wKztYEqaBQGB&Expires=1647166193&Signature" 58 | + "=WfYCQ1S8XLuqj7oCGxHYTH3VNdc%3D\"\n" + "}\n", 59 | 60 | "{\n" 61 | + " \"description\": \"

《Python云原生:构建应对海量用户数据的高可扩展Web应用》以一个应用开发贯穿始终,从云原生和微服务的概念原理讲起,使用Python" 62 | + "构建云原生应用,并使用React构建Web视图。为了应对大规模的互联网流量,使用了Flux构建UI和事件溯源及CQRS模式。考虑到Web应用的安全性,《Python" 63 | + "云原生:构建应对海量用户数据的高可扩展Web应用》对此也给出了解决方案。书中对于关键步骤进行了详细讲解并给出运行结果。读者可以利用Docker容器、CI/CD工具,敏捷构建和发布本书示例中的应用到AWS" 64 | + "、Azure这样的公有云平台上,再利用平台工具对基础设施和应用的运行进行持续监控。

云原生是云计算时代的发展趋势和必然结果

云原生将持续领航云时代架构理念

用Python语言进行开发

易如门,易掌握,集现今诸多热点技术之大成

流程完整,示例具体详细

一个实际开发案例贯穿始终,全面开放代码

\",\n" 67 | + " \"author\": \"Manish Sethi, 宋净超\",\n" 68 | + " \"image_url\": \"http://reserved-antcloud-cnshnfpub-opsware-v2.oss-cn-shanghai.aliyuncs" 69 | + ".com/fas/books/4.png?OSSAccessKeyId=RZU9wKztYEqaBQGB&Expires=1647178695&Signature" 70 | + "=9l4JHy7eMQVj3T3mXgRpAN9wdPI%3D\"\n" + "}\n", 71 | 72 | "{\n" 73 | + " \"description\": \"

Google联合IBM、Lyft推出的Istio,一经问世就受到了人们的普遍关注,其热度迅速攀升,成为Service " 74 | + "Mesh(服务网格)方案的代表项目。本书整理了Istio中的部分概念和案例,以快速入门的形式,对Istio的基础用法一一进行讲解,并在书末给出一些试用方面的建议。
在本书中,前3" 75 | + "章从微服务和服务网格的简短历史开始,讲述了服务网格的诞生过程、基本特性及Istio的核心功能,若对这些内容已经有所了解,则可以直接从第4章开始阅读;第4、5章分别讲解了Istio的配置和部署过程;第6" 76 | + "章至第9章,通过多个场景来讲解Istio的常用功能;第10章结合了笔者的实践经验,为读者提供了Istio的一系列试用建议。本书没有采用官方复杂的Book " 77 | + "Info应用案例,而是采用客户端+简单HTTP服务端的案例,读者随时都能在短时间内启动一个小的测试。
本书面向对服务网格技术感兴趣,并希望进一步了解和学习Istio" 78 | + "的中高级技术人员,假设读者已经了解Kubernetes的相关概念并能够在Kubernetes上熟练部署和管理微服务。若希望全面、深入地学习Kubernetes,可参考《Kubernetes " 79 | + "权威指南:从Docker到Kubernetes实践全接触》和《Kubernetes 权威指南:企业级容器云实战》。

快速入门Service " 80 | + "Mesh和实践

手把手快速入门Service Mesh和实践,并根据Istio 1.1版本的升级,将源码及内容同步更新至GitHub

作者为Kubernetes " 81 | + "权威指南作者之一

作者为Kubernetes 权威指南作者之一,Istio、Kubernetes项目成员,Istio" 82 | + ".io主要贡献者之一

知名大咖热评

知名大咖敖小剑、马全一、张琦及《Kubernetes 权威指南》作者龚正等热评!

\",\n" 83 | + " \"author\": \"崔秀龙\",\n" 84 | + " \"image_url\": \"http://reserved-antcloud-cnshnfpub-opsware-v2.oss-cn-shanghai.aliyuncs" 85 | + ".com/fas/books/5.png?OSSAccessKeyId=RZU9wKztYEqaBQGB&Expires=1647179151&Signature=LIY" 86 | + "%2F56jF8Out5eHsxAU1hkUOp7o%3D\"\n" + "}\n", }; 87 | } 88 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/impl/SortedStrategyImpl.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.impl; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.alipay.sofa.runtime.api.annotation.SofaReference; 5 | import io.sofastack.dynamic.facade.StrategyService; 6 | import io.sofastack.stockmng.facade.SortedStrategyFacade; 7 | import io.sofastack.stockmng.mapper.StockMngMapper; 8 | import io.sofastack.stockmng.model.ProductInfo; 9 | import io.sofastack.stockmng.util.CommonUtil; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.beans.factory.annotation.Autowired; 13 | import org.springframework.stereotype.Service; 14 | 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | /** 21 | * @author: guolei.sgl (guolei.sgl@antfin.com) 2019/6/19 10:41 AM 22 | * @since: 23 | **/ 24 | @Service 25 | public class SortedStrategyImpl implements SortedStrategyFacade { 26 | 27 | private static final Logger LOGGER = LoggerFactory.getLogger(SortedStrategyImpl.class); 28 | 29 | @SofaReference 30 | private StrategyService strategyService; 31 | 32 | @Autowired 33 | private StockMngMapper stockMngMapper; 34 | 35 | @Override 36 | public List getSorted() { 37 | List result = new ArrayList<>(); 38 | try { 39 | String strategy = strategyService.strategy(); 40 | Map map = new HashMap<>(); 41 | LOGGER.info("Begin to execute dynamic sort strategy,[strategy = " + strategy + "]"); 42 | // 按照订单量排序 43 | if ("order".equals(strategy)) { 44 | List productCodes = stockMngMapper.queryAllProductCode(); 45 | final List products = initProducts(); 46 | for (String productCode : productCodes) { 47 | int totalOrderCount = stockMngMapper.queryCountByProductCode(productCode); 48 | ProductInfo productInfo = getProductInfoByCode(productCode, products); 49 | if (productInfo != null) { 50 | map.put(productInfo, totalOrderCount); 51 | } 52 | } 53 | result = CommonUtil.sorted(map); 54 | result.forEach((productInfo) -> { 55 | if (map.get(productInfo) != null){ 56 | productInfo.setName(productInfo.getName()+"("+map.get(productInfo)+")"); 57 | } 58 | }); 59 | } 60 | } catch (Throwable t) { 61 | LOGGER.error("Error to getSorted.", t); 62 | result = initProducts(); 63 | } 64 | return result; 65 | } 66 | 67 | private ProductInfo getProductInfoByCode(String productCode, List products) { 68 | for (ProductInfo productInfo : products) { 69 | if (productInfo.getProductCode().equals(productCode)) { 70 | return productInfo; 71 | } 72 | } 73 | return null; 74 | } 75 | 76 | /** 77 | * 初始化默认展示列表,为了实验效果,此处初始化的列表与实际列表是相反的,但是实际排序结果与现场购买订单直接挂钩 78 | * 79 | * @return 80 | */ 81 | private List initProducts() { 82 | List products = new ArrayList<>(5); 83 | for (int i = 4; i >= 0; i--) { 84 | ProductInfo productInfo = new ProductInfo(); 85 | productInfo.setName(DatabaseSeed.name[i]); 86 | productInfo.setDescription(DatabaseSeed.description[i]); 87 | JSONObject jsonObject = JSONObject.parseObject(DatabaseSeed.description[i]); 88 | productInfo.setSrc(jsonObject.get("image_url").toString()); 89 | productInfo.setAuthor(jsonObject.get("author").toString()); 90 | productInfo.setPrice(DatabaseSeed.price[i]); 91 | productInfo.setProductCode("0000" + (i + 1)); 92 | products.add(productInfo); 93 | } 94 | return products; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/mapper/StockMngMapper.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.mapper; 2 | 3 | import org.apache.ibatis.annotations.Mapper; 4 | import org.apache.ibatis.annotations.Param; 5 | import org.apache.ibatis.annotations.Select; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface StockMngMapper { 11 | @Select("select DISTINCT(product_code) from order_tb ") 12 | List queryAllProductCode(); 13 | 14 | @Select("select sum(count) from order_tb where product_code=#{productCode}") 15 | Integer queryCountByProductCode(@Param("productCode") String productCode); 16 | } 17 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/model/BalanceResponse.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.model; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class BalanceResponse { 6 | 7 | private BigDecimal balance; 8 | 9 | public BigDecimal getBalance() { 10 | return balance; 11 | } 12 | 13 | public void setBalance(BigDecimal balance) { 14 | this.balance = balance; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/model/ProductInfo.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.model; 2 | 3 | import java.math.BigDecimal; 4 | 5 | public class ProductInfo { 6 | 7 | private String productCode; 8 | private BigDecimal price; 9 | private String name; 10 | private Integer ownedCount; 11 | private Integer stockCount; 12 | private String description; 13 | private String src; 14 | private String author; 15 | 16 | public Integer getStockCount() { 17 | return stockCount; 18 | } 19 | 20 | public void setStockCount(Integer stockCount) { 21 | this.stockCount = stockCount; 22 | } 23 | 24 | public String getDescription() { 25 | return description; 26 | } 27 | 28 | public void setDescription(String description) { 29 | this.description = description; 30 | } 31 | 32 | public String getProductCode() { 33 | return productCode; 34 | } 35 | 36 | public void setProductCode(String productCode) { 37 | this.productCode = productCode; 38 | } 39 | 40 | public BigDecimal getPrice() { 41 | return price; 42 | } 43 | 44 | public void setPrice(BigDecimal price) { 45 | this.price = price; 46 | } 47 | 48 | public String getName() { 49 | return name; 50 | } 51 | 52 | public void setName(String name) { 53 | this.name = name; 54 | } 55 | 56 | public Integer getOwnedCount() { 57 | return ownedCount; 58 | } 59 | 60 | public void setOwnedCount(Integer ownedCount) { 61 | this.ownedCount = ownedCount; 62 | } 63 | 64 | public String getSrc() { 65 | return src; 66 | } 67 | 68 | public void setSrc(String src) { 69 | this.src = src; 70 | } 71 | 72 | public String getAuthor() { 73 | return author; 74 | } 75 | 76 | public void setAuthor(String author) { 77 | this.author = author; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/model/Success.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.model; 2 | 3 | public class Success { 4 | 5 | private String success; 6 | 7 | public String getSuccess() { 8 | return success; 9 | } 10 | 11 | public void setSuccess(String success) { 12 | this.success = success; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/java/io/sofastack/stockmng/util/CommonUtil.java: -------------------------------------------------------------------------------- 1 | package io.sofastack.stockmng.util; 2 | 3 | import io.sofastack.stockmng.model.ProductInfo; 4 | 5 | import java.util.ArrayList; 6 | import java.util.Collections; 7 | import java.util.Comparator; 8 | import java.util.Iterator; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * @author: guolei.sgl (guolei.sgl@antfin.com) 2019/6/12 9:32 PM 14 | * @since: 15 | **/ 16 | public class CommonUtil { 17 | 18 | private static class ValueComparator implements Comparator> { 19 | @Override 20 | public int compare(Map.Entry m, Map.Entry n) { 21 | return n.getValue() - m.getValue(); 22 | } 23 | } 24 | 25 | public static List sorted(Map map) { 26 | List result = new ArrayList<>(); 27 | List> list = new ArrayList<>(); 28 | 29 | list.addAll(map.entrySet()); 30 | ValueComparator vc = new ValueComparator(); 31 | Collections.sort(list, vc); 32 | 33 | for (Iterator> it = list.iterator(); it.hasNext();) { 34 | result.add(it.next().getKey()); 35 | } 36 | return result; 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8080 2 | # logging 3 | logging.level.io.sofastack=INFO 4 | logging.path=./logs/stock-mng 5 | # thymeleaf 6 | spring.thymeleaf.cache=false 7 | spring.thymeleaf.prefix=classpath:/templates/ 8 | spring.thymeleaf.check-template-location=true 9 | spring.thymeleaf.suffix=.html 10 | spring.thymeleaf.encoding=UTF-8 11 | spring.thymeleaf.mode=HTML5 12 | 13 | # database config 14 | spring.datasource.driver-class-name=com.mysql.jdbc.Driver 15 | spring.datasource.url=jdbc:mysql://localhost:3306/stock_db?useSSL=true 16 | spring.datasource.username=root 17 | spring.datasource.password=root 18 | 19 | 20 | # 替换 {your-number} 为当前座位编号 21 | spring.application.name=stock-mng-{your-number} 22 | 23 | ### 添加 Dashboard 客户端配置 24 | 25 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/resources/logback-spring.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | %d{HH:mm:ss.SSS} %-5level %logger{80} - %msg%n 11 | 12 | 13 | 14 | 15 | true 16 | 17 | 18 | error 19 | 20 | 21 | ${logging.path}/common-error.log 22 | 23 | 24 | 25 | ${logging.path}/common-error.log.%d{yyyy-MM-dd} 26 | 27 | 30 28 | 29 | 30 | 31 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 32 | 33 | UTF-8 34 | 35 | 36 | 37 | 38 | true 39 | 40 | ${logging.level} 41 | 42 | ${logging.path}/default.log 43 | 44 | 45 | 46 | ${logging.path}/default.log.%d{yyyy-MM-dd} 47 | 48 | 49 | 30 50 | 51 | 52 | 53 | %d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n 54 | 55 | UTF-8 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /dynamic-stock-mng/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 72 | 73 | 74 | 75 |
76 |
77 | 78 |
79 | 80 |
81 | 82 |
83 |
84 |
85 |
86 |
87 |
88 | 89 |
90 |
91 | 92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | 101 | -------------------------------------------------------------------------------- /formatter.xml: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | pom 6 | 7 | dynamic-stock-mng 8 | dynamic-provider 9 | dynamic-facade 10 | 11 | 12 | 13 | com.alipay.sofa 14 | sofaboot-dependencies 15 | 3.1.4 16 | 17 | 18 | io.sofastack 19 | kc-sofastack-dynamic-demo 20 | 1.0.0 21 | kc-sofastack-dynamic-demo 22 | Demo project for SofaStack Dynamic Module 23 | 24 | 25 | 1.8 26 | 0.6.0 27 | 1.0.0 28 | 2.9.1 29 | 1.3.2 30 | 5.1.46 31 | 32 | 33 | 34 | 35 | org.springframework.boot 36 | spring-boot-starter 37 | 38 | 39 | 40 | org.springframework.boot 41 | spring-boot-starter-test 42 | test 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | com.alipay.sofa 51 | sofa-dashboard-client 52 | ${dashboard.client} 53 | 54 | 55 | 56 | 57 | com.alipay.sofa 58 | web-ark-plugin 59 | ${ark.version} 60 | 61 | 62 | 63 | 64 | com.alipay.sofa 65 | config-ark-plugin 66 | ${ark.version} 67 | 68 | 69 | 70 | curator-client 71 | org.apache.curator 72 | ${curator.version} 73 | 74 | 75 | curator-framework 76 | org.apache.curator 77 | ${curator.version} 78 | 79 | 80 | 81 | org.mybatis.spring.boot 82 | mybatis-spring-boot-starter 83 | ${mybatis.version} 84 | 85 | 86 | mysql 87 | mysql-connector-java 88 | ${mysql.version} 89 | 90 | 91 | 92 | io.sofastack 93 | dynamic-facade 94 | ${project.version} 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | org.apache.maven.plugins 104 | maven-surefire-plugin 105 | 2.21.0 106 | 107 | 108 | 109 | 110 | 111 | --------------------------------------------------------------------------------