diff --git a/samples/springboot-samples/slimming/README.md b/samples/springboot-samples/slimming/README.md index efa385569..ece7376f2 100644 --- a/samples/springboot-samples/slimming/README.md +++ b/samples/springboot-samples/slimming/README.md @@ -83,9 +83,6 @@ biz1 包含两个打包插件,一个常规 springboot 插件, 构建普通 spr true ./target biz1 - - - rules.txt biz1 true @@ -106,6 +103,25 @@ biz1 包含两个打包插件,一个常规 springboot 插件, 构建普通 spr ``` +瘦身配置在 biz1 的 `biz1/src/main/resources/application.properties` 文件中, +``` +# 按 jar 名称( artifactId:version )排除,多个 jar 按照逗号分隔,可以使用换行符号 +excludes=tracer-core:3.0.10,tracer-core:3.0.11 + +# 按 artifactId 排除,支持通配符,多个 artifactId 按照逗号分隔,可以使用换行符号 +excludeArtifactIds=commons-collections,commons-httpclient,commons-io,commons-lang + +# 按 groupId 排除,支持通配符,多个 group 按照逗号分隔,可以使用换行符号 +excludeGroupIds=aopalliance*,asm*,cglib*,com.alibaba.common.lang*,com.alibaba.common.resourcebundle*,com.alibaba.tbase*,com.alipay*,com.antcloud.antvip*,com.caucho.hessian*,com.ctc.wstx*,\ + com.fasterxml*,com.google.code*,com.google.common*,com.google.gson*,com.google.guava*,com.google.http-client*,com.google.inject*,com.google.protobuf*,com.ibatis*,com.iwallet.biz*,com.lmax*,\ + com.taobao.config*,com.taobao.hsf*,com.taobao.notify*,com.taobao.remoting*,com.taobao.tair*,groovy*,io.fury*,io.grpc*,io.mosn.layotto*,io.netty*,io.openmessaging*,io.prometheus*,javax*,javax.el*,\ + javax.script*,javax.servlet*,javax.validation*,loccs-bcprov*,log4j*,mysql*,net.sf.acegisecurity*,net.sf.cglib*,netty*,ognl*,org.aopalliance*,org.apache*,org.aspectj*,org.codehaus*,org.codehaus.groovy*,\ + org.codehaus.xfire*,org.dom4j*,org.hibernate.validator*,org.junit*,org.mvel2*,org.mybatis*,org.mybatis.spring*,org.mybatis.spring.boot.autoconfigure*,org.projectlombok*,org.quartz*,org.reflections*,\ + org.slf4j*,org.springframework*,org.yaml*,xerces*,xml-apis*,xpp3*,jakarta*,ch.qos.logback*,org.latencyutils*,org.hdrhistogram*,io.micrometer*,ch.qos.logback*,com.squareup.okhttp3*,com.squareup.okhttp*,\ + net.sf.ehcache*,redis.clients* +``` + + ## 实验任务 ### 执行 mvn clean package -DskipTests 可在各 biz1 bundle 的 target 目录里查看到打包生成的 ark-biz jar 包 和 普通 springboot 包, 明显经过模块瘦身的 ark-biz jar 包大小更小 diff --git a/samples/springboot-samples/slimming/log4j2/biz1/src/main/resources/application.properties b/samples/springboot-samples/slimming/log4j2/biz1/src/main/resources/application.properties index 5d0ab5342..95d05c317 100644 --- a/samples/springboot-samples/slimming/log4j2/biz1/src/main/resources/application.properties +++ b/samples/springboot-samples/slimming/log4j2/biz1/src/main/resources/application.properties @@ -5,3 +5,12 @@ logging.level.com.alipay.sofa=DEBUG logging.level.root=INFO logging.level.com.alipay.sofa.arklet=INFO logging.config=classpath:log4j2-spring.xml +excludes=tracer-core:3.0.10,tracer-core:3.0.11 +excludeArtifactIds=commons-collections,commons-httpclient,commons-io,commons-lang +excludeGroupIds=aopalliance*,asm*,cglib*,com.alibaba.common.lang*,com.alibaba.common.resourcebundle*,com.alibaba.tbase*,com.alipay*,com.antcloud.antvip*,com.caucho.hessian*,com.ctc.wstx*,\ + com.fasterxml*,com.google.code*,com.google.common*,com.google.gson*,com.google.guava*,com.google.http-client*,com.google.inject*,com.google.protobuf*,com.ibatis*,com.iwallet.biz*,com.lmax*,\ + com.taobao.config*,com.taobao.hsf*,com.taobao.notify*,com.taobao.remoting*,com.taobao.tair*,groovy*,io.fury*,io.grpc*,io.mosn.layotto*,io.netty*,io.openmessaging*,io.prometheus*,javax*,javax.el*,\ + javax.script*,javax.servlet*,javax.validation*,loccs-bcprov*,log4j*,mysql*,net.sf.acegisecurity*,net.sf.cglib*,netty*,ognl*,org.aopalliance*,org.apache*,org.aspectj*,org.codehaus*,org.codehaus.groovy*,\ + org.codehaus.xfire*,org.dom4j*,org.hibernate.validator*,org.junit*,org.mvel2*,org.mybatis*,org.mybatis.spring*,org.mybatis.spring.boot.autoconfigure*,org.projectlombok*,org.quartz*,org.reflections*,\ + org.slf4j*,org.springframework*,org.yaml*,xerces*,xml-apis*,xpp3*,jakarta*,ch.qos.logback*,org.latencyutils*,org.hdrhistogram*,io.micrometer*,ch.qos.logback*,com.squareup.okhttp3*,com.squareup.okhttp*,\ + net.sf.ehcache*,redis.clients* diff --git a/samples/springboot3-samples/config/apollo/README.md b/samples/springboot3-samples/config/apollo/README.md new file mode 100644 index 000000000..edcccffb7 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/README.md @@ -0,0 +1,52 @@ +# 实验内容 + + +1. 不同模块使用不同的 app id, 独立配置 +2. 不同模块使用相同 app id,独立配置默认就已经支持 + +## 实验任务 +### 不同模块使用不同的 app id, 独立配置 +#### base 代码改造 +1. application.properties 里增加如下配置,用来解决 jmx 注册 bean 冲突问题 +```properties +spring.jmx.default-domain=${spring.application.name} +``` +2. 配置 apollo 服务端地址 +```java +// 默认 apollo 使用 Eureka 获取服务地址,由于本地 docker 采用 bridge 网络模式,通过 Eureka 获取到的是虚拟子网服务地址 +// 在本地无法直接调用,所以这里直接通过自定义配置 `apollo.configService` 指定为 localhost + +System.setProperty("apollo.configService", "http://localhost:8080"); +System.setProperty("apollo.config-service", "http://localhost:8080"); +System.setProperty("env", "DEV"); +``` +3. pom 里引入 apollo 依赖 + +4. 基座和模块代码里都添加 apollo 多应用治理类 `com.ctrip.framework.apollo.spring.boot.ApolloApplicationContextInitializer` +引入覆盖 apollo 原有逻辑的治理类,与原生的类实现的区别在于如下一行 +![diff.png](imgs/diff.png) + +5. 基座和模块里都添加 apollo 配置文件 `/META-INF/app.properties` +由于注释了 initializeSystemProperty 方法,导致无法通过 application.properties 对 apollo 进行配置, 初始化 `app.id`。所以模块里需要使用 `/META-INF/app.properties` 进行配置。 +![init.png](imgs/init.png) + +#### 实验步骤 +1. cd 进入 config 目录,执行如下命令启动 apollo 服务端 +```shell +docker-compose up +``` +2. 登录 apollo 管理后台 `localhost:8080`,创建 app id 为 `biz1` 的项目和 key=data.name 的配置,创建 app id 为 `biz2` 的项目和 key=data.name 的配置,具体查看 https://www.apolloconfig.com/#/zh/deployment/quick-start + +![apps.png](imgs/apps.png) + +![app-data-name.png](imgs/app-data-name.png) + +3. 执行 `mvn clean package -DskipTests`,然后启动基座 +4. 进入 apollo 目录,执行 `arkctl deploy biz1/target/biz1-apollo-0.0.1-SNAPSHOT-ark-biz.jar`, 安装 biz1 模块 +5. 进入 apollo 目录,执行 `arkctl deploy biz2/target/biz2-apollo-0.0.1-SNAPSHOT-ark-biz.jar`, 安装 biz2 模块 +6. 执行 `curl http://localhost:8081/biz1/getValue` 获取到 biz1 的配置值,修改 biz1 的 data.name,再次执行 `curl http://localhost:8081/biz1/getValue` 能获取到新的 biz1 的配置值 +7. 执行 `curl http://localhost:8081/biz1/getValue` 获取到 biz2 的配置值,修改 biz2 的 data.name,再次执行 `curl http://localhost:8081/biz2/getValue` 能获取到新的 biz2 的配置值,也不会影响 biz1 或基座的配置值 + +### 不同模块使用相同 app id,独立配置默认就已经支持 +模块统一使用[自动排包能力](https://sofaserverless.gitee.io/docs/tutorials/module-development/module-slimming/#%E4%B8%80%E9%94%AE%E8%87%AA%E5%8A%A8%E7%98%A6%E8%BA%AB),在 rules.txt 文件里确保有这个配置 `excludeGroupIds=com.ctrip.framework.apollo*`,将 apollo client 委托给基座加载即可达到效果。 +注意 application.properties 里增加 `spring.jmx.default-domain=${spring.application.name}` diff --git a/samples/springboot3-samples/config/apollo/base/pom.xml b/samples/springboot3-samples/config/apollo/base/pom.xml new file mode 100644 index 000000000..c5f4a918a --- /dev/null +++ b/samples/springboot3-samples/config/apollo/base/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + com.alipay.sofa.config + apollo + 0.0.1-SNAPSHOT + ../pom.xml + + base-apollo + 0.0.1-SNAPSHOT + + + + + com.alipay.sofa.serverless + sofa-serverless-base-starter + ${sofa.serverless.runtime.version} + pom + + + com.alipay.sofa + web-ark-plugin + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot + spring-boot-autoconfigure + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.springframework.boot + spring-boot-configuration-processor + true + + + com.ctrip.framework.apollo + apollo-client + 2.2.0 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.cloud + spring-cloud-context + + + + com.google.inject + guice + 6.0.0 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + + + + diff --git a/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java b/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java new file mode 100644 index 000000000..785ee7171 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java @@ -0,0 +1,23 @@ +package com.alipay.sofa.config.apollo; + +import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.context.properties.EnableConfigurationProperties; + +@EnableConfigurationProperties +@EnableApolloConfig +@SpringBootApplication +public class ApolloApplication { + + public static void main(String[] args) { + // 默认 apollo 使用 Eureka 获取服务地址,由于本地 docker 采用 bridge 网络模式,通过 Eureka 获取到的是虚拟子网服务地址 + // 在本地无法直接调用,所以这里直接通过自定义配置 `apollo.configService` 指定为 localhost + + System.setProperty("apollo.configService", "http://localhost:8080"); + System.setProperty("apollo.config-service", "http://localhost:8080"); + System.setProperty("env", "DEV"); + + SpringApplication.run(ApolloApplication.class, args); + } +} diff --git a/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java b/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java new file mode 100644 index 000000000..441c6b7f9 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java @@ -0,0 +1,24 @@ +package com.alipay.sofa.config.apollo.config; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Service; + +@ConfigurationProperties(prefix = "data") +@Service +@Data +@RefreshScope +@Slf4j +public class DataConfig implements InitializingBean { + + private String name; + + @Override + public void afterPropertiesSet() { + log.info("DataConfig: {}", this); + } +} diff --git a/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java b/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java new file mode 100644 index 000000000..83bdc140e --- /dev/null +++ b/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java @@ -0,0 +1,31 @@ +package com.alipay.sofa.config.apollo.config; + +import com.ctrip.framework.apollo.model.ConfigChange; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.context.scope.refresh.RefreshScope; +import org.springframework.stereotype.Component; + +/** + * @Author: ZYL + * @Date: 2021/8/17 13:48 + * @Description: Apollo 配置热更新 + */ +@Slf4j +@Component +public class PropertiesRefresher { + + @Autowired + private RefreshScope refreshScope; + + @ApolloConfigChangeListener + public void changeListener(ConfigChangeEvent changeEvent) { + changeEvent.changedKeys().stream().forEach(changeKey -> { + ConfigChange configChange = changeEvent.getChange(changeKey); + log.info("Apollo base config change, propertyName:[{}], oldValue:{}, newValue:{}", configChange.getPropertyName(), configChange.getOldValue(), configChange.getNewValue()); + }); + refreshScope.refreshAll(); + } +} \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java b/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java new file mode 100644 index 000000000..2a692aa05 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/base/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java @@ -0,0 +1,18 @@ +package com.alipay.sofa.config.apollo.rest; + +import com.alipay.sofa.config.apollo.config.DataConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SimpleController { + + @Autowired + private DataConfig dataConfig; + + @GetMapping("/getValue") + public String getValue() { + return dataConfig.getName(); + } +} diff --git a/samples/springboot3-samples/config/apollo/base/src/main/resources/META-INF/app.properties b/samples/springboot3-samples/config/apollo/base/src/main/resources/META-INF/app.properties new file mode 100644 index 000000000..f221423f0 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/base/src/main/resources/META-INF/app.properties @@ -0,0 +1,10 @@ +app.id=SampleApp +apollo.bootstrap.enabled=true +apollo.bootstrap.eagerLoad.enabled=true +apollo.bootstrap.namespaces=application +apollo.autoUpdateInjectedSpringProperties=true + +# ?? ???? docker ?? bridge ?????? Eureka ?????? apollo ????? +# ????????????????????????? meta ???????????????? +# ?????? System.setProperty("apollo.configService", "http://localhost:8080")???????????? +apollo.meta=http://localhost:8080 \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/base/src/main/resources/application.properties b/samples/springboot3-samples/config/apollo/base/src/main/resources/application.properties new file mode 100644 index 000000000..81f05cbaa --- /dev/null +++ b/samples/springboot3-samples/config/apollo/base/src/main/resources/application.properties @@ -0,0 +1,12 @@ +spring.application.name=base-apollo +server.port=8082 + +app.id=SampleApp +apollo.bootstrap.enabled=true +apollo.bootstrap.eagerLoad.enabled=true +apollo.bootstrap.namespaces=application +apollo.autoUpdateInjectedSpringProperties=true + + + +data.name=timeout diff --git a/samples/springboot3-samples/config/apollo/base/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java b/samples/springboot3-samples/config/apollo/base/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java new file mode 100644 index 000000000..c3ce17a09 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/base/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java @@ -0,0 +1,13 @@ +package com.alipay.sofa.config.apollo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApolloApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/samples/springboot-samples/slimming/log4j2/biz1/conf/ark/rules.txt b/samples/springboot3-samples/config/apollo/biz1/conf/ark/rules.txt similarity index 89% rename from samples/springboot-samples/slimming/log4j2/biz1/conf/ark/rules.txt rename to samples/springboot3-samples/config/apollo/biz1/conf/ark/rules.txt index c83835b04..842d0e54d 100644 --- a/samples/springboot-samples/slimming/log4j2/biz1/conf/ark/rules.txt +++ b/samples/springboot3-samples/config/apollo/biz1/conf/ark/rules.txt @@ -5,6 +5,7 @@ excludeArtifactIds=commons-lang excludeGroupIds=aopalliance* excludeGroupIds=asm* excludeGroupIds=cglib* +excludeGroupIds=org.springframework* excludeGroupIds=com.alibaba.common.lang* excludeGroupIds=com.alibaba.common.resourcebundle* excludeGroupIds=com.alibaba.tbase* @@ -13,10 +14,11 @@ excludeGroupIds=com.antcloud.antvip* excludeGroupIds=com.caucho.hessian* excludeGroupIds=com.ctc.wstx* excludeGroupIds=com.fasterxml* -excludeGroupIds=com.google.code* excludeGroupIds=com.google.common* excludeGroupIds=com.google.gson* +excludeGroupIds=com.google.code* excludeGroupIds=com.google.guava* +excludeGroupIds=com.google.j2objc* excludeGroupIds=com.google.http-client* excludeGroupIds=com.google.inject* excludeGroupIds=com.google.protobuf* @@ -64,18 +66,26 @@ excludeGroupIds=org.projectlombok* excludeGroupIds=org.quartz* excludeGroupIds=org.reflections* excludeGroupIds=org.slf4j* -excludeGroupIds=org.springframework* excludeGroupIds=org.yaml* excludeGroupIds=xerces* excludeGroupIds=xml-apis* excludeGroupIds=xpp3* excludeGroupIds=jakarta* -excludeGroupIds=ch.qos.logback* excludeGroupIds=org.latencyutils* excludeGroupIds=org.hdrhistogram* excludeGroupIds=io.micrometer* +excludeGroupIds=io.micrometer* excludeGroupIds=ch.qos.logback* excludeGroupIds=com.squareup.okhttp3* excludeGroupIds=com.squareup.okhttp* excludeGroupIds=net.sf.ehcache* excludeGroupIds=redis.clients* +excludeGroupIds=net.bytebuddy* +excludeGroupIds=com.taobao.text* +excludeGroupIds=net.java.dev.jna* +excludeGroupIds=com.google.errorprone* +excludeGroupIds=com.github.oshi* +excludeGroupIds=org.checkerframework* + + +excludeArtifactIds=fastjson \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/biz1/pom.xml b/samples/springboot3-samples/config/apollo/biz1/pom.xml new file mode 100644 index 000000000..e3e640245 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz1/pom.xml @@ -0,0 +1,95 @@ + + + 4.0.0 + + com.alipay.sofa.config + apollo + 0.0.1-SNAPSHOT + ../pom.xml + + biz1-apollo + 0.0.1-SNAPSHOT + + + + com.google.code.gson + gson + 2.10.1 + + + + org.springframework.boot + spring-boot-autoconfigure + + + + org.springframework.boot + spring-boot-starter + provided + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.ctrip.framework.apollo + apollo-client + 2.2.0 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.cloud + spring-cloud-context + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + provided + + + + + + + com.alipay.sofa + sofa-ark-maven-plugin + ${sofa.ark.version} + + + default-cli + + repackage + + + + + true + ./target + biz1-apollo + biz1 + true + rules.txt + + + + + + + + + diff --git a/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java b/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java new file mode 100644 index 000000000..6e708e50b --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java @@ -0,0 +1,24 @@ +package com.alipay.sofa.config.apollo; + +import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.ResourceLoader; + +@EnableConfigurationProperties +@EnableApolloConfig +@SpringBootApplication +public class ApolloApplication { + + public static void main(String[] args) { + SpringApplicationBuilder builder = new SpringApplicationBuilder(ApolloApplication.class); + + // set biz to use resource loader. + ResourceLoader resourceLoader = new DefaultResourceLoader(ApolloApplication.class.getClassLoader()); + builder.resourceLoader(resourceLoader); + builder.build().run(args); + } +} diff --git a/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java b/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java new file mode 100644 index 000000000..4f8f29ee8 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java @@ -0,0 +1,23 @@ +package com.alipay.sofa.config.apollo.config; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Service; + +@ConfigurationProperties(prefix = "data") +@Service +@Data +@RefreshScope +@Slf4j +public class DataConfig implements InitializingBean { + + private String name; + + @Override + public void afterPropertiesSet() { + log.info("DataConfig: {}", this); + } +} diff --git a/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java b/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java new file mode 100644 index 000000000..210869012 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java @@ -0,0 +1,32 @@ +package com.alipay.sofa.config.apollo.config; + +import com.ctrip.framework.apollo.model.ConfigChange; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.context.scope.refresh.RefreshScope; +import org.springframework.stereotype.Component; + +/** + * @Author: ZYL + * @Date: 2021/8/17 13:48 + * @Description: Apollo 配置热更新 + */ +@Slf4j +@Component +public class PropertiesRefresher { + + @Autowired + private RefreshScope refreshScope; + + @ApolloConfigChangeListener + public void changeListener(ConfigChangeEvent changeEvent) { + changeEvent.changedKeys().stream().forEach(changeKey -> { + ConfigChange configChange = changeEvent.getChange(changeKey); + log.info("Apollo biz1 config change, propertyName:[{}], oldValue:{}, newValue:{}", + configChange.getPropertyName(), configChange.getOldValue(), configChange.getNewValue()); + }); + refreshScope.refreshAll(); + } +} \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java b/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java new file mode 100644 index 000000000..2a692aa05 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz1/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java @@ -0,0 +1,18 @@ +package com.alipay.sofa.config.apollo.rest; + +import com.alipay.sofa.config.apollo.config.DataConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SimpleController { + + @Autowired + private DataConfig dataConfig; + + @GetMapping("/getValue") + public String getValue() { + return dataConfig.getName(); + } +} diff --git a/samples/springboot3-samples/config/apollo/biz1/src/main/resources/META-INF/app.properties b/samples/springboot3-samples/config/apollo/biz1/src/main/resources/META-INF/app.properties new file mode 100644 index 000000000..fae6683bc --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz1/src/main/resources/META-INF/app.properties @@ -0,0 +1,10 @@ +app.id=biz1 +apollo.bootstrap.enabled=true +apollo.bootstrap.eagerLoad.enabled=true +apollo.bootstrap.namespaces=application +apollo.autoUpdateInjectedSpringProperties=true + +# ?? ???? docker ?? bridge ?????? Eureka ?????? apollo ????? +# ????????????????????????? meta ???????????????? +# ?????? System.setProperty("apollo.configService", "http://localhost:8080")???????????? +apollo.meta=http://localhost:8080 \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/biz1/src/main/resources/application.properties b/samples/springboot3-samples/config/apollo/biz1/src/main/resources/application.properties new file mode 100644 index 000000000..bc47a10aa --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz1/src/main/resources/application.properties @@ -0,0 +1,17 @@ +spring.application.name=biz1-apollo + +server.port=8082 +data.name=timeout + +spring.jmx.default-domain=${spring.application.name} + +app.id=biz1 +apollo.bootstrap.enabled=true +apollo.bootstrap.eagerLoad.enabled=true +apollo.bootstrap.namespaces=application +apollo.autoUpdateInjectedSpringProperties=true + +# ?? ???? docker ?? bridge ?????? Eureka ?????? apollo ????? +# ????????????????????????? meta ???????????????? +# ?????? System.setProperty("apollo.configService", "http://localhost:8080")???????????? +apollo.meta=http://localhost:8080 diff --git a/samples/springboot3-samples/config/apollo/biz1/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java b/samples/springboot3-samples/config/apollo/biz1/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java new file mode 100644 index 000000000..c3ce17a09 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz1/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java @@ -0,0 +1,13 @@ +package com.alipay.sofa.config.apollo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApolloApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/samples/springboot3-samples/config/apollo/biz2/pom.xml b/samples/springboot3-samples/config/apollo/biz2/pom.xml new file mode 100644 index 000000000..d4e300610 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz2/pom.xml @@ -0,0 +1,94 @@ + + + 4.0.0 + + com.alipay.sofa.config + apollo + 0.0.1-SNAPSHOT + ../pom.xml + + biz2-apollo + 0.0.1-SNAPSHOT + + + + com.google.code.gson + gson + 2.10.1 + + + + org.springframework.boot + spring-boot-autoconfigure + + + + org.springframework.boot + spring-boot-starter + provided + + + + org.springframework.boot + spring-boot-starter-test + test + + + + com.ctrip.framework.apollo + apollo-client + 2.2.0 + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.cloud + spring-cloud-context + + + org.springframework.boot + spring-boot-configuration-processor + true + + + + org.projectlombok + lombok + provided + + + + + + com.alipay.sofa + sofa-ark-maven-plugin + ${sofa.ark.version} + + + default-cli + + repackage + + + + + true + ./target + biz2-apollo + biz2 + true + rules.txt + + + + + + + + + diff --git a/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java b/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java new file mode 100644 index 000000000..3f0dd5a1c --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/ApolloApplication.java @@ -0,0 +1,25 @@ +package com.alipay.sofa.config.apollo; + +import com.ctrip.framework.apollo.spring.annotation.EnableApolloConfig; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.WebApplicationType; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.core.io.DefaultResourceLoader; +import org.springframework.core.io.ResourceLoader; + +@EnableConfigurationProperties +@EnableApolloConfig +@SpringBootApplication +public class ApolloApplication { + + public static void main(String[] args) { + SpringApplicationBuilder builder = new SpringApplicationBuilder(ApolloApplication.class); + + // set biz to use resource loader. + ResourceLoader resourceLoader = new DefaultResourceLoader(ApolloApplication.class.getClassLoader()); + builder.resourceLoader(resourceLoader); + builder.build().run(args); + } +} diff --git a/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java b/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java new file mode 100644 index 000000000..4f8f29ee8 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/config/DataConfig.java @@ -0,0 +1,23 @@ +package com.alipay.sofa.config.apollo.config; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Service; + +@ConfigurationProperties(prefix = "data") +@Service +@Data +@RefreshScope +@Slf4j +public class DataConfig implements InitializingBean { + + private String name; + + @Override + public void afterPropertiesSet() { + log.info("DataConfig: {}", this); + } +} diff --git a/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java b/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java new file mode 100644 index 000000000..f47b78797 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/config/PropertiesRefresher.java @@ -0,0 +1,31 @@ +package com.alipay.sofa.config.apollo.config; + +import com.ctrip.framework.apollo.model.ConfigChange; +import com.ctrip.framework.apollo.model.ConfigChangeEvent; +import com.ctrip.framework.apollo.spring.annotation.ApolloConfigChangeListener; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.context.scope.refresh.RefreshScope; +import org.springframework.stereotype.Component; + +/** + * @Author: ZYL + * @Date: 2021/8/17 13:48 + * @Description: Apollo 配置热更新 + */ +@Slf4j +@Component +public class PropertiesRefresher { + + @Autowired + private RefreshScope refreshScope; + + @ApolloConfigChangeListener + public void changeListener(ConfigChangeEvent changeEvent) { + changeEvent.changedKeys().stream().forEach(changeKey -> { + ConfigChange configChange = changeEvent.getChange(changeKey); + log.info("Apollo biz2 config change, propertyName:[{}], oldValue:{}, newValue:{}", configChange.getPropertyName(), configChange.getOldValue(), configChange.getNewValue()); + }); + refreshScope.refreshAll(); + } +} \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java b/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java new file mode 100644 index 000000000..2a692aa05 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz2/src/main/java/com/alipay/sofa/config/apollo/rest/SimpleController.java @@ -0,0 +1,18 @@ +package com.alipay.sofa.config.apollo.rest; + +import com.alipay.sofa.config.apollo.config.DataConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class SimpleController { + + @Autowired + private DataConfig dataConfig; + + @GetMapping("/getValue") + public String getValue() { + return dataConfig.getName(); + } +} diff --git a/samples/springboot3-samples/config/apollo/biz2/src/main/resources/META-INF/app.properties b/samples/springboot3-samples/config/apollo/biz2/src/main/resources/META-INF/app.properties new file mode 100644 index 000000000..59fe6b4a2 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz2/src/main/resources/META-INF/app.properties @@ -0,0 +1,10 @@ +app.id=biz2 +apollo.bootstrap.enabled=true +apollo.bootstrap.eagerLoad.enabled=true +apollo.bootstrap.namespaces=application +apollo.autoUpdateInjectedSpringProperties=true + +# ?? ???? docker ?? bridge ?????? Eureka ?????? apollo ????? +# ????????????????????????? meta ???????????????? +# ?????? System.setProperty("apollo.configService", "http://localhost:8080")???????????? +apollo.meta=http://localhost:8080 \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/biz2/src/main/resources/application.properties b/samples/springboot3-samples/config/apollo/biz2/src/main/resources/application.properties new file mode 100644 index 000000000..82f486239 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz2/src/main/resources/application.properties @@ -0,0 +1,17 @@ +spring.application.name=biz2-apollo + +server.port=8082 +data.name=timeout +spring.jmx.default-domain=${spring.application.name} + + +app.id=biz2 +apollo.bootstrap.enabled=true +apollo.bootstrap.eagerLoad.enabled=true +apollo.bootstrap.namespaces=application +apollo.autoUpdateInjectedSpringProperties=true + +# ?? ???? docker ?? bridge ?????? Eureka ?????? apollo ????? +# ????????????????????????? meta ???????????????? +# ?????? System.setProperty("apollo.configService", "http://localhost:8080")???????????? +apollo.meta=http://localhost:8080 diff --git a/samples/springboot3-samples/config/apollo/biz2/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java b/samples/springboot3-samples/config/apollo/biz2/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java new file mode 100644 index 000000000..c3ce17a09 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/biz2/src/test/java/com/alipay/sofa/config/apollo/ApolloApplicationTests.java @@ -0,0 +1,13 @@ +package com.alipay.sofa.config.apollo; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ApolloApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/samples/springboot3-samples/config/apollo/config/docker-compose.yml b/samples/springboot3-samples/config/apollo/config/docker-compose.yml new file mode 100644 index 000000000..39410abd6 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/config/docker-compose.yml @@ -0,0 +1,48 @@ +version: '2.1' + +services: + apollo-quick-start: + image: nobodyiam/apollo-quick-start + container_name: apollo-quick-start + depends_on: + apollo-db: + condition: service_healthy + ports: + - "8080:8080" + - "8070:8070" + - "8090:8090" + links: + - apollo-db + #environment: + #JAVA_OPTS: '-Xms100m -Xmx1000m -Xmn100m -Xss256k -XX:MetaspaceSize=10m -XX:MaxMetaspaceSize=250m' + #APOLLO_CONFIG_DB_USERNAME: 'root' + #APOLLO_CONFIG_DB_PASSWORD: 'apollo' + #APOLLO_PORTAL_DB_USERNAME: 'root' + #APOLLO_PORTAL_DB_PASSWORD: 'apollo' + + apollo-db: + image: mysql:8.0 + container_name: apollo-db + environment: + TZ: Asia/Shanghai + MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' + #MYSQL_ROOT_PASSWORD: 'apollo' + healthcheck: + test: ["CMD", "mysqladmin" ,"ping", "-h", "localhost"] + interval: 5s + timeout: 1s + retries: 10 + depends_on: + - apollo-dbdata + ports: + - "13306:3306" + volumes: + - ./sql:/docker-entrypoint-initdb.d + volumes_from: + - apollo-dbdata + + apollo-dbdata: + image: alpine:latest + container_name: apollo-dbdata + volumes: + - /var/lib/mysql \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/config/sql/apolloconfigdb.sql b/samples/springboot3-samples/config/apollo/config/sql/apolloconfigdb.sql new file mode 100644 index 000000000..e85585117 --- /dev/null +++ b/samples/springboot3-samples/config/apollo/config/sql/apolloconfigdb.sql @@ -0,0 +1,483 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +# Create Database +# ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloConfigDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloConfigDB; + +# Dump of table app +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `App`; + +CREATE TABLE `App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +# Dump of table appnamespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `AppNamespace`; + +CREATE TABLE `AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +# Dump of table audit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Audit`; + +CREATE TABLE `Audit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `EntityName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '表名', + `EntityId` int(10) unsigned DEFAULT NULL COMMENT '记录ID', + `OpName` varchar(50) NOT NULL DEFAULT 'default' COMMENT '操作类型', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='日志审计表'; + + + +# Dump of table cluster +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Cluster`; + +CREATE TABLE `Cluster` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT '集群名字', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'App id', + `ParentClusterId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '父cluster', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `IX_ParentClusterId` (`ParentClusterId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='集群'; + + + +# Dump of table commit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Commit`; + +CREATE TABLE `Commit` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `ChangeSets` longtext NOT NULL COMMENT '修改变更集', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Comment` varchar(500) DEFAULT NULL COMMENT '备注', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `AppId` (`AppId`), + KEY `ClusterName` (`ClusterName`(191)), + KEY `NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='commit 历史表'; + +# Dump of table grayreleaserule +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `GrayReleaseRule`; + +CREATE TABLE `GrayReleaseRule` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'branch name', + `Rules` varchar(16000) DEFAULT '[]' COMMENT '灰度规则', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '灰度对应的release', + `BranchStatus` tinyint(2) DEFAULT '1' COMMENT '灰度分支状态: 0:删除分支,1:正在使用的规则 2:全量发布', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='灰度规则表'; + + +# Dump of table instance +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Instance`; + +CREATE TABLE `Instance` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `DataCenter` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Data Center Name', + `Ip` varchar(32) NOT NULL DEFAULT '' COMMENT 'instance ip', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`AppId`,`ClusterName`,`Ip`,`DataCenter`), + KEY `IX_IP` (`Ip`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='使用配置的应用实例'; + + + +# Dump of table instanceconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `InstanceConfig`; + +CREATE TABLE `InstanceConfig` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `InstanceId` int(11) unsigned DEFAULT NULL COMMENT 'Instance Id', + `ConfigAppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'Config App Id', + `ConfigClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Cluster Name', + `ConfigNamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'Config Namespace Name', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `ReleaseDeliveryTime` timestamp NULL DEFAULT NULL COMMENT '配置获取时间', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `IX_UNIQUE_KEY` (`InstanceId`,`ConfigAppId`,`ConfigNamespaceName`), + KEY `IX_ReleaseKey` (`ReleaseKey`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Valid_Namespace` (`ConfigAppId`,`ConfigClusterName`,`ConfigNamespaceName`,`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用实例的配置信息'; + + + +# Dump of table item +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Item`; + +CREATE TABLE `Item` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `Key` varchar(128) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Type` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '配置项类型,0: String,1: Number,2: Boolean,3: JSON', + `Value` longtext NOT NULL COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `LineNum` int(10) unsigned DEFAULT '0' COMMENT '行号', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_GroupId` (`NamespaceId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置项目'; + + + +# Dump of table namespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Namespace`; + +CREATE TABLE `Namespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Cluster Name', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'Namespace Name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_ClusterName_NamespaceName_DeletedAt` (`AppId`,`ClusterName`(191),`NamespaceName`(191),`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_NamespaceName` (`NamespaceName`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='命名空间'; + + + +# Dump of table namespacelock +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `NamespaceLock`; + +CREATE TABLE `NamespaceLock` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id', + `NamespaceId` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '集群NamespaceId', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + `IsDeleted` bit(1) DEFAULT b'0' COMMENT '软删除', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_NamespaceId_DeletedAt` (`NamespaceId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='namespace的编辑锁'; + + + +# Dump of table release +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Release`; + +CREATE TABLE `Release` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `ReleaseKey` varchar(64) NOT NULL DEFAULT '' COMMENT '发布的Key', + `Name` varchar(64) NOT NULL DEFAULT 'default' COMMENT '发布名字', + `Comment` varchar(256) DEFAULT NULL COMMENT '发布说明', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `Configurations` longtext NOT NULL COMMENT '发布配置', + `IsAbandoned` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否废弃', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ReleaseKey_DeletedAt` (`ReleaseKey`,`DeletedAt`), + KEY `AppId_ClusterName_GroupName` (`AppId`,`ClusterName`(191),`NamespaceName`(191)), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布'; + + +# Dump of table releasehistory +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ReleaseHistory`; + +CREATE TABLE `ReleaseHistory` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `ClusterName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'ClusterName', + `NamespaceName` varchar(32) NOT NULL DEFAULT 'default' COMMENT 'namespaceName', + `BranchName` varchar(32) NOT NULL DEFAULT 'default' COMMENT '发布分支名', + `ReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '关联的Release Id', + `PreviousReleaseId` int(11) unsigned NOT NULL DEFAULT '0' COMMENT '前一次发布的ReleaseId', + `Operation` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '发布类型,0: 普通发布,1: 回滚,2: 灰度发布,3: 灰度规则更新,4: 灰度合并回主分支发布,5: 主分支发布灰度自动发布,6: 主分支回滚灰度自动发布,7: 放弃灰度', + `OperationContext` longtext NOT NULL COMMENT '发布上下文信息', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_Namespace` (`AppId`,`ClusterName`,`NamespaceName`,`BranchName`), + KEY `IX_ReleaseId` (`ReleaseId`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PreviousReleaseId` (`PreviousReleaseId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布历史'; + + +# Dump of table releasemessage +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ReleaseMessage`; + +CREATE TABLE `ReleaseMessage` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Message` varchar(1024) NOT NULL DEFAULT '' COMMENT '发布的消息内容', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Message` (`Message`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='发布消息'; + + + +# Dump of table serverconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ServerConfig`; + +CREATE TABLE `ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Cluster` varchar(32) NOT NULL DEFAULT 'default' COMMENT '配置对应的集群,default为不针对特定的集群', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_Cluster_DeletedAt` (`Key`,`Cluster`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + +# Dump of table accesskey +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `AccessKey`; + +CREATE TABLE `AccessKey` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Secret` varchar(128) NOT NULL DEFAULT '' COMMENT 'Secret', + `IsEnabled` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: enabled, 0: disabled', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Secret_DeletedAt` (`AppId`,`Secret`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='访问密钥'; + + +# Dump of table serviceregistry +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ServiceRegistry`; + +CREATE TABLE `ServiceRegistry` ( + `Id` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ServiceName` VARCHAR(64) NOT NULL COMMENT '服务名', + `Uri` VARCHAR(64) NOT NULL COMMENT '服务地址', + `Cluster` VARCHAR(64) NOT NULL COMMENT '集群,可以用来标识apollo.cluster或者网络分区', + `Metadata` VARCHAR(1024) NOT NULL DEFAULT '{}' COMMENT '元数据,key value结构的json object,为了方面后面扩展功能而不需要修改表结构', + `DataChange_CreatedTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE INDEX `IX_UNIQUE_KEY` (`ServiceName`, `Uri`), + INDEX `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='注册中心'; + + +# Config +# ------------------------------------------------------------ +INSERT INTO `ServerConfig` (`Key`, `Cluster`, `Value`, `Comment`) +VALUES + ('eureka.service.url', 'default', 'http://localhost:8080/eureka/', 'Eureka服务Url,多个service以英文逗号分隔'), + ('namespace.lock.switch', 'default', 'false', '一次发布只能有一个人修改开关'), + ('item.key.length.limit', 'default', '128', 'item key 最大长度限制'), + ('item.value.length.limit', 'default', '20000', 'item value最大长度限制'), + ('config-service.cache.enabled', 'default', 'false', 'ConfigService是否开启缓存,开启后能提高性能,但是会增大内存消耗!'); + +# Sample Data +# ------------------------------------------------------------ +INSERT INTO `App` (`AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`) +VALUES + ('SampleApp', 'Sample App', 'TEST1', '样例部门1', 'apollo', 'apollo@acme.com'); + +INSERT INTO `AppNamespace` (`Name`, `AppId`, `Format`, `IsPublic`, `Comment`) +VALUES + ('application', 'SampleApp', 'properties', 0, 'default app namespace'); + +INSERT INTO `Cluster` (`Name`, `AppId`) +VALUES + ('default', 'SampleApp'); + +INSERT INTO `Namespace` (`Id`, `AppId`, `ClusterName`, `NamespaceName`) +VALUES + (1, 'SampleApp', 'default', 'application'); + + +INSERT INTO `Item` (`NamespaceId`, `Key`, `Value`, `Comment`, `LineNum`) +VALUES + (1, 'timeout', '100', 'sample timeout配置', 1); + +INSERT INTO `Release` (`ReleaseKey`, `Name`, `Comment`, `AppId`, `ClusterName`, `NamespaceName`, `Configurations`) +VALUES + ('20161009155425-d3a0749c6e20bc15', '20161009155424-release', 'Sample发布', 'SampleApp', 'default', 'application', '{\"timeout\":\"100\"}'); + +INSERT INTO `ReleaseHistory` (`AppId`, `ClusterName`, `NamespaceName`, `BranchName`, `ReleaseId`, `PreviousReleaseId`, `Operation`, `OperationContext`, `DataChange_CreatedBy`, `DataChange_LastModifiedBy`) +VALUES + ('SampleApp', 'default', 'application', 'default', 1, 0, 0, '{}', 'apollo', 'apollo'); + +INSERT INTO `ReleaseMessage` (`Message`) +VALUES + ('SampleApp+default+application'); + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/config/sql/apolloportaldb.sql b/samples/springboot3-samples/config/apollo/config/sql/apolloportaldb.sql new file mode 100644 index 000000000..3ed8a43ff --- /dev/null +++ b/samples/springboot3-samples/config/apollo/config/sql/apolloportaldb.sql @@ -0,0 +1,421 @@ +-- +-- Copyright 2023 Apollo Authors +-- +-- Licensed under the Apache License, Version 2.0 (the "License"); +-- you may not use this file except in compliance with the License. +-- You may obtain a copy of the License at +-- +-- http://www.apache.org/licenses/LICENSE-2.0 +-- +-- Unless required by applicable law or agreed to in writing, software +-- distributed under the License is distributed on an "AS IS" BASIS, +-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +-- See the License for the specific language governing permissions and +-- limitations under the License. +-- +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; +/*!40101 SET NAMES utf8 */; +/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; +/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; +/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; + +# Create Database +# ------------------------------------------------------------ +CREATE DATABASE IF NOT EXISTS ApolloPortalDB DEFAULT CHARACTER SET = utf8mb4; + +Use ApolloPortalDB; + +# Dump of table app +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `App`; + +CREATE TABLE `App` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_Name` (`Name`(191)) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用表'; + + + +# Dump of table appnamespace +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `AppNamespace`; + +CREATE TABLE `AppNamespace` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增主键', + `Name` varchar(32) NOT NULL DEFAULT '' COMMENT 'namespace名字,注意,需要全局唯一', + `AppId` varchar(64) NOT NULL DEFAULT '' COMMENT 'app id', + `Format` varchar(32) NOT NULL DEFAULT 'properties' COMMENT 'namespace的format类型', + `IsPublic` bit(1) NOT NULL DEFAULT b'0' COMMENT 'namespace是否为公共', + `Comment` varchar(64) NOT NULL DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_Name_DeletedAt` (`AppId`,`Name`,`DeletedAt`), + KEY `Name_AppId` (`Name`,`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='应用namespace定义'; + + + +# Dump of table consumer +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Consumer`; + +CREATE TABLE `Consumer` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Name` varchar(500) NOT NULL DEFAULT 'default' COMMENT '应用名', + `OrgId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '部门Id', + `OrgName` varchar(64) NOT NULL DEFAULT 'default' COMMENT '部门名字', + `OwnerName` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerName', + `OwnerEmail` varchar(500) NOT NULL DEFAULT 'default' COMMENT 'ownerEmail', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_AppId_DeletedAt` (`AppId`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='开放API消费者'; + + + +# Dump of table consumeraudit +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ConsumerAudit`; + +CREATE TABLE `ConsumerAudit` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `Uri` varchar(1024) NOT NULL DEFAULT '' COMMENT '访问的Uri', + `Method` varchar(16) NOT NULL DEFAULT '' COMMENT '访问的Method', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_ConsumerId` (`ConsumerId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer审计表'; + + + +# Dump of table consumerrole +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ConsumerRole`; + +CREATE TABLE `ConsumerRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'Consumer Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_ConsumerId_RoleId_DeletedAt` (`ConsumerId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer和role的绑定表'; + + + +# Dump of table consumertoken +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ConsumerToken`; + +CREATE TABLE `ConsumerToken` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `ConsumerId` int(11) unsigned DEFAULT NULL COMMENT 'ConsumerId', + `Token` varchar(128) NOT NULL DEFAULT '' COMMENT 'token', + `Expires` datetime NOT NULL DEFAULT '2099-01-01 00:00:00' COMMENT 'token失效时间', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Token_DeletedAt` (`Token`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='consumer token表'; + +# Dump of table favorite +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Favorite`; + +CREATE TABLE `Favorite` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '主键', + `UserId` varchar(32) NOT NULL DEFAULT 'default' COMMENT '收藏的用户', + `AppId` varchar(64) NOT NULL DEFAULT 'default' COMMENT 'AppID', + `Position` int(32) NOT NULL DEFAULT '10000' COMMENT '收藏顺序', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_AppId_DeletedAt` (`UserId`,`AppId`,`DeletedAt`), + KEY `AppId` (`AppId`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB AUTO_INCREMENT=23 DEFAULT CHARSET=utf8mb4 COMMENT='应用收藏表'; + +# Dump of table permission +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Permission`; + +CREATE TABLE `Permission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `PermissionType` varchar(32) NOT NULL DEFAULT '' COMMENT '权限类型', + `TargetId` varchar(256) NOT NULL DEFAULT '' COMMENT '权限对象类型', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_TargetId_PermissionType_DeletedAt` (`TargetId`,`PermissionType`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='permission表'; + + + +# Dump of table role +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Role`; + +CREATE TABLE `Role` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleName` varchar(256) NOT NULL DEFAULT '' COMMENT 'Role name', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleName_DeletedAt` (`RoleName`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表'; + + + +# Dump of table rolepermission +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `RolePermission`; + +CREATE TABLE `RolePermission` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `PermissionId` int(10) unsigned DEFAULT NULL COMMENT 'Permission Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_RoleId_PermissionId_DeletedAt` (`RoleId`,`PermissionId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_PermissionId` (`PermissionId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色和权限的绑定表'; + + + +# Dump of table serverconfig +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `ServerConfig`; + +CREATE TABLE `ServerConfig` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Key` varchar(64) NOT NULL DEFAULT 'default' COMMENT '配置项Key', + `Value` varchar(2048) NOT NULL DEFAULT 'default' COMMENT '配置项值', + `Comment` varchar(1024) DEFAULT '' COMMENT '注释', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Key_DeletedAt` (`Key`,`DeletedAt`), + KEY `DataChange_LastTime` (`DataChange_LastTime`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='配置服务自身配置'; + + + +# Dump of table userrole +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `UserRole`; + +CREATE TABLE `UserRole` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `UserId` varchar(128) DEFAULT '' COMMENT '用户身份标识', + `RoleId` int(10) unsigned DEFAULT NULL COMMENT 'Role Id', + `IsDeleted` bit(1) NOT NULL DEFAULT b'0' COMMENT '1: deleted, 0: normal', + `DeletedAt` BIGINT(20) NOT NULL DEFAULT '0' COMMENT 'Delete timestamp based on milliseconds', + `DataChange_CreatedBy` varchar(64) NOT NULL DEFAULT 'default' COMMENT '创建人邮箱前缀', + `DataChange_CreatedTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `DataChange_LastModifiedBy` varchar(64) DEFAULT '' COMMENT '最后修改人邮箱前缀', + `DataChange_LastTime` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '最后修改时间', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_UserId_RoleId_DeletedAt` (`UserId`,`RoleId`,`DeletedAt`), + KEY `IX_DataChange_LastTime` (`DataChange_LastTime`), + KEY `IX_RoleId` (`RoleId`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户和role的绑定表'; + +# Dump of table Users +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Users`; + +CREATE TABLE `Users` ( + `Id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL DEFAULT 'default' COMMENT '用户登录账户', + `Password` varchar(512) NOT NULL DEFAULT 'default' COMMENT '密码', + `UserDisplayName` varchar(512) NOT NULL DEFAULT 'default' COMMENT '用户名称', + `Email` varchar(64) NOT NULL DEFAULT 'default' COMMENT '邮箱地址', + `Enabled` tinyint(4) DEFAULT NULL COMMENT '是否有效', + PRIMARY KEY (`Id`), + UNIQUE KEY `UK_Username` (`Username`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户表'; + + +# Dump of table Authorities +# ------------------------------------------------------------ + +DROP TABLE IF EXISTS `Authorities`; + +CREATE TABLE `Authorities` ( + `Id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增Id', + `Username` varchar(64) NOT NULL, + `Authority` varchar(50) NOT NULL, + PRIMARY KEY (`Id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + + +# Config +# ------------------------------------------------------------ +INSERT INTO `ServerConfig` (`Key`, `Value`, `Comment`) +VALUES + ('apollo.portal.envs', 'dev', '可支持的环境列表'), + ('organizations', '[{\"orgId\":\"TEST1\",\"orgName\":\"样例部门1\"},{\"orgId\":\"TEST2\",\"orgName\":\"样例部门2\"}]', '部门列表'), + ('superAdmin', 'apollo', 'Portal超级管理员'), + ('api.readTimeout', '10000', 'http接口read timeout'), + ('consumer.token.salt', 'someSalt', 'consumer token salt'), + ('admin.createPrivateNamespace.switch', 'true', '是否允许项目管理员创建私有namespace'), + ('configView.memberOnly.envs', 'dev', '只对项目成员显示配置信息的环境列表,多个env以英文逗号分隔'), + ('apollo.portal.meta.servers', '{}', '各环境Meta Service列表'); + + +INSERT INTO `Users` (`Username`, `Password`, `UserDisplayName`, `Email`, `Enabled`) +VALUES + ('apollo', '$2a$10$7r20uS.BQ9uBpf3Baj3uQOZvMVvB1RN3PYoKE94gtz2.WAOuiiwXS', 'apollo', 'apollo@acme.com', 1); + +INSERT INTO `Authorities` (`Username`, `Authority`) VALUES ('apollo', 'ROLE_user'); + +-- spring session (https://github.com/spring-projects/spring-session/blob/faee8f1bdb8822a5653a81eba838dddf224d92d6/spring-session-jdbc/src/main/resources/org/springframework/session/jdbc/schema-mysql.sql) +CREATE TABLE SPRING_SESSION ( + PRIMARY_ID CHAR(36) NOT NULL, + SESSION_ID CHAR(36) NOT NULL, + CREATION_TIME BIGINT NOT NULL, + LAST_ACCESS_TIME BIGINT NOT NULL, + MAX_INACTIVE_INTERVAL INT NOT NULL, + EXPIRY_TIME BIGINT NOT NULL, + PRINCIPAL_NAME VARCHAR(100), + CONSTRAINT SPRING_SESSION_PK PRIMARY KEY (PRIMARY_ID) +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +CREATE UNIQUE INDEX SPRING_SESSION_IX1 ON SPRING_SESSION (SESSION_ID); +CREATE INDEX SPRING_SESSION_IX2 ON SPRING_SESSION (EXPIRY_TIME); +CREATE INDEX SPRING_SESSION_IX3 ON SPRING_SESSION (PRINCIPAL_NAME); + +CREATE TABLE SPRING_SESSION_ATTRIBUTES ( + SESSION_PRIMARY_ID CHAR(36) NOT NULL, + ATTRIBUTE_NAME VARCHAR(200) NOT NULL, + ATTRIBUTE_BYTES BLOB NOT NULL, + CONSTRAINT SPRING_SESSION_ATTRIBUTES_PK PRIMARY KEY (SESSION_PRIMARY_ID, ATTRIBUTE_NAME), + CONSTRAINT SPRING_SESSION_ATTRIBUTES_FK FOREIGN KEY (SESSION_PRIMARY_ID) REFERENCES SPRING_SESSION(PRIMARY_ID) ON DELETE CASCADE +) ENGINE=InnoDB ROW_FORMAT=DYNAMIC; + +# Sample Data +# ------------------------------------------------------------ +INSERT INTO `App` (`AppId`, `Name`, `OrgId`, `OrgName`, `OwnerName`, `OwnerEmail`) +VALUES + ('SampleApp', 'Sample App', 'TEST1', '样例部门1', 'apollo', 'apollo@acme.com'); + +INSERT INTO `AppNamespace` (`Name`, `AppId`, `Format`, `IsPublic`, `Comment`) +VALUES + ('application', 'SampleApp', 'properties', 0, 'default app namespace'); + +INSERT INTO `Permission` (`Id`, `PermissionType`, `TargetId`) +VALUES + (1, 'CreateCluster', 'SampleApp'), + (2, 'CreateNamespace', 'SampleApp'), + (3, 'AssignRole', 'SampleApp'), + (4, 'ModifyNamespace', 'SampleApp+application'), + (5, 'ReleaseNamespace', 'SampleApp+application'); + +INSERT INTO `Role` (`Id`, `RoleName`) +VALUES + (1, 'Master+SampleApp'), + (2, 'ModifyNamespace+SampleApp+application'), + (3, 'ReleaseNamespace+SampleApp+application'); + +INSERT INTO `RolePermission` (`RoleId`, `PermissionId`) +VALUES + (1, 1), + (1, 2), + (1, 3), + (2, 4), + (3, 5); + +INSERT INTO `UserRole` (`UserId`, `RoleId`) +VALUES + ('apollo', 1), + ('apollo', 2), + ('apollo', 3); + +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; +/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; \ No newline at end of file diff --git a/samples/springboot3-samples/config/apollo/imgs/app-data-name.png b/samples/springboot3-samples/config/apollo/imgs/app-data-name.png new file mode 100644 index 000000000..43d154768 Binary files /dev/null and b/samples/springboot3-samples/config/apollo/imgs/app-data-name.png differ diff --git a/samples/springboot3-samples/config/apollo/imgs/apps.png b/samples/springboot3-samples/config/apollo/imgs/apps.png new file mode 100644 index 000000000..741a49efc Binary files /dev/null and b/samples/springboot3-samples/config/apollo/imgs/apps.png differ diff --git a/samples/springboot3-samples/config/apollo/imgs/diff.png b/samples/springboot3-samples/config/apollo/imgs/diff.png new file mode 100644 index 000000000..1445c4ce4 Binary files /dev/null and b/samples/springboot3-samples/config/apollo/imgs/diff.png differ diff --git a/samples/springboot3-samples/config/apollo/imgs/init.png b/samples/springboot3-samples/config/apollo/imgs/init.png new file mode 100644 index 000000000..1ca2750b2 Binary files /dev/null and b/samples/springboot3-samples/config/apollo/imgs/init.png differ diff --git a/samples/springboot3-samples/config/apollo/pom.xml b/samples/springboot3-samples/config/apollo/pom.xml new file mode 100644 index 000000000..e16590d5d --- /dev/null +++ b/samples/springboot3-samples/config/apollo/pom.xml @@ -0,0 +1,40 @@ + + + 4.0.0 + + com.alipay.sofa + springboot-samples + 0.0.1-SNAPSHOT + ../../pom.xml + + com.alipay.sofa.config + apollo + 0.0.1-SNAPSHOT + apollo + apollo + pom + + + 2023.0.0 + + + + + + org.springframework.cloud + spring-cloud-dependencies + ${spring-cloud.version} + pom + import + + + + + + base + biz1 + biz2 + + + diff --git a/samples/springboot3-samples/db/mybatis/base/pom.xml b/samples/springboot3-samples/db/mybatis/base/pom.xml index c13a01383..47add89ba 100644 --- a/samples/springboot3-samples/db/mybatis/base/pom.xml +++ b/samples/springboot3-samples/db/mybatis/base/pom.xml @@ -15,6 +15,11 @@ base for mybatis + + com.alipay.sofa.serverless + sofa-serverless-adapter-log4j2 + ${sofa.serverless.runtime.version} + org.springframework.boot spring-boot-starter-web @@ -31,7 +36,7 @@ org.mybatis.spring.boot mybatis-spring-boot-starter - 2.3.1 + 3.0.3 @@ -82,17 +87,6 @@ - - com.alipay.sofa - log-sofa-boot-starter - 3.9.1 - - - com.alipay.sofa.common - sofa-common-tools - - - com.alipay.sofa.common diff --git a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/facade/SampleService.java b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/facade/SampleService.java index 91e80f64f..c64366594 100644 --- a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/facade/SampleService.java +++ b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/facade/SampleService.java @@ -1,5 +1,8 @@ package com.alipay.sofa.base.facade; +import org.springframework.stereotype.Service; + +@Service public interface SampleService { /** diff --git a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/mapper/BookMapper.java b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/mapper/BookMapper.java index c36f02769..45bde6f46 100644 --- a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/mapper/BookMapper.java +++ b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/mapper/BookMapper.java @@ -1,8 +1,10 @@ package com.alipay.sofa.base.mapper; import com.alipay.sofa.base.model.Book; +import org.apache.ibatis.annotations.*; import java.util.List; +@Mapper public interface BookMapper { List getAll(); diff --git a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/mapper/UserMapper.java b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/mapper/UserMapper.java index 4e565549c..f5e343777 100644 --- a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/mapper/UserMapper.java +++ b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/mapper/UserMapper.java @@ -1,10 +1,7 @@ package com.alipay.sofa.base.mapper; import com.alipay.sofa.base.model.User; -import org.apache.ibatis.annotations.Delete; -import org.apache.ibatis.annotations.Insert; -import org.apache.ibatis.annotations.Select; -import org.apache.ibatis.annotations.Update; +import org.apache.ibatis.annotations.*; import java.util.List; @@ -12,6 +9,7 @@ * @author: chaya * @date: 2023/10/18 4:50 下午 */ +@Mapper public interface UserMapper { @Select("SELECT * FROM user") diff --git a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/model/Book.java b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/model/Book.java index d783d879a..b6e7c22c3 100644 --- a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/model/Book.java +++ b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/model/Book.java @@ -1,10 +1,13 @@ package com.alipay.sofa.base.model; +import lombok.Data; + /** * @author: chaya * @date: 2023/10/19 5:01 下午 */ +@Data public class Book { private Integer id; diff --git a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/rest/SampleController.java b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/rest/SampleController.java index 377e793d4..ccf522915 100644 --- a/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/rest/SampleController.java +++ b/samples/springboot3-samples/db/mybatis/base/src/main/java/com/alipay/sofa/base/rest/SampleController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; import java.util.List; @RestController diff --git a/samples/springboot3-samples/db/mybatis/base/src/main/resources/application.properties b/samples/springboot3-samples/db/mybatis/base/src/main/resources/application.properties index 76ed2ebb8..896e3f193 100644 --- a/samples/springboot3-samples/db/mybatis/base/src/main/resources/application.properties +++ b/samples/springboot3-samples/db/mybatis/base/src/main/resources/application.properties @@ -8,7 +8,7 @@ logging.config=classpath:log4j2-spring.xml spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root -spring.datasource.password=Zfj1995! +spring.datasource.password=chaya1993! spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false mybatis.mapper-locations=classpath:mappers/*.xml \ No newline at end of file diff --git a/samples/springboot3-samples/db/mybatis/biz1/pom.xml b/samples/springboot3-samples/db/mybatis/biz1/pom.xml index e1ec97354..92b88f497 100644 --- a/samples/springboot3-samples/db/mybatis/biz1/pom.xml +++ b/samples/springboot3-samples/db/mybatis/biz1/pom.xml @@ -31,7 +31,7 @@ org.mybatis.spring.boot mybatis-spring-boot-starter - 2.3.1 + 3.0.3 provided @@ -71,11 +71,21 @@ - - - - - + + com.alipay.sofa.serverless + sofa-serverless-adapter-log4j2 + ${sofa.serverless.runtime.version} + provided + + + + + com.alipay.sofa.serverless + sofa-serverless-base-starter + + ${sofa.serverless.runtime.version} + provided + diff --git a/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/model/Song.java b/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/model/Song.java index 9c8aecc29..d5e406435 100644 --- a/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/model/Song.java +++ b/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/model/Song.java @@ -1,9 +1,10 @@ package com.alipay.sofa.biz1.model; - +import lombok.Data; /** * @author: chaya.cy * @date: 2023/10/19 5:16 下午 */ +@Data public class Song { private Integer id; diff --git a/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/model/Student.java b/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/model/Student.java index fa24cf6e8..fe3d644f8 100644 --- a/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/model/Student.java +++ b/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/model/Student.java @@ -1,9 +1,10 @@ package com.alipay.sofa.biz1.model; - +import lombok.Data; /** * @author: chaya.cy * @date: 2023/10/18 8:47 下午 */ +@Data public class Student { private Integer id; diff --git a/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/rest/SampleController.java b/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/rest/SampleController.java index 4e32cc2a9..bf32dbcea 100644 --- a/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/rest/SampleController.java +++ b/samples/springboot3-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/rest/SampleController.java @@ -11,6 +11,7 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.Resource; import java.util.List; @RestController diff --git a/samples/springboot3-samples/db/mybatis/biz1/src/main/resources/application.properties b/samples/springboot3-samples/db/mybatis/biz1/src/main/resources/application.properties index bb2f1e25a..8b323fb65 100644 --- a/samples/springboot3-samples/db/mybatis/biz1/src/main/resources/application.properties +++ b/samples/springboot3-samples/db/mybatis/biz1/src/main/resources/application.properties @@ -8,7 +8,7 @@ logging.config=classpath:log4j2-spring.xml spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.datasource.username=root -spring.datasource.password=Zfj1995! +spring.datasource.password=chaya1993! spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false mybatis.mapper-locations=classpath:mappers/*.xml diff --git a/samples/springboot3-samples/logging/log4j2/base/pom.xml b/samples/springboot3-samples/logging/log4j2/base/pom.xml index 5eb5138be..09ffb9674 100644 --- a/samples/springboot3-samples/logging/log4j2/base/pom.xml +++ b/samples/springboot3-samples/logging/log4j2/base/pom.xml @@ -15,6 +15,18 @@ logging base for log4j2 + + com.alipay.sofa.serverless + sofa-serverless-adapter-log4j2 + ${sofa.serverless.runtime.version} + + + + com.alipay.sofa + sofa-boot-alipay-autoconfigure + + + org.springframework.boot spring-boot-starter-web @@ -50,17 +62,6 @@ - - com.alipay.sofa - log-sofa-boot-starter - 3.9.1 - - - com.alipay.sofa.common - sofa-common-tools - - - com.alipay.sofa.common diff --git a/samples/springboot3-samples/logging/log4j2/biz1/pom.xml b/samples/springboot3-samples/logging/log4j2/biz1/pom.xml index e32a43f6e..6461ccef4 100644 --- a/samples/springboot3-samples/logging/log4j2/biz1/pom.xml +++ b/samples/springboot3-samples/logging/log4j2/biz1/pom.xml @@ -17,13 +17,20 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-log4j2 provided - org.springframework.boot - spring-boot-starter-log4j2 + spring-boot-starter-web + provided + + + + com.alipay.sofa.serverless + sofa-serverless-base-starter + + ${sofa.serverless.runtime.version} provided diff --git a/samples/springboot3-samples/logging/log4j2/biz2/pom.xml b/samples/springboot3-samples/logging/log4j2/biz2/pom.xml index 8351e72c8..6ab6cc7c7 100644 --- a/samples/springboot3-samples/logging/log4j2/biz2/pom.xml +++ b/samples/springboot3-samples/logging/log4j2/biz2/pom.xml @@ -17,13 +17,20 @@ org.springframework.boot - spring-boot-starter-web + spring-boot-starter-log4j2 provided - org.springframework.boot - spring-boot-starter-log4j2 + spring-boot-starter-web + provided + + + + com.alipay.sofa.serverless + sofa-serverless-base-starter + + ${sofa.serverless.runtime.version} provided diff --git a/samples/springboot3-samples/logging/logback/base/pom.xml b/samples/springboot3-samples/logging/logback/base/pom.xml index cac4f4878..f9b4e8d4d 100644 --- a/samples/springboot3-samples/logging/logback/base/pom.xml +++ b/samples/springboot3-samples/logging/logback/base/pom.xml @@ -36,11 +36,6 @@ web-ark-plugin - - - com.alipay.sofa - log-sofa-boot-starter - diff --git a/samples/springboot3-samples/msg/kafka/base/pom.xml b/samples/springboot3-samples/msg/kafka/base/pom.xml index b8c03c0e7..03f30e8c2 100644 --- a/samples/springboot3-samples/msg/kafka/base/pom.xml +++ b/samples/springboot3-samples/msg/kafka/base/pom.xml @@ -61,17 +61,6 @@ - - com.alipay.sofa - log-sofa-boot-starter - 3.9.1 - - - com.alipay.sofa.common - sofa-common-tools - - - com.alipay.sofa.common diff --git a/samples/springboot3-samples/msg/kafka/biz1/pom.xml b/samples/springboot3-samples/msg/kafka/biz1/pom.xml index 58085494d..fa42590e2 100644 --- a/samples/springboot3-samples/msg/kafka/biz1/pom.xml +++ b/samples/springboot3-samples/msg/kafka/biz1/pom.xml @@ -39,12 +39,12 @@ test - - - - - - + + com.alipay.sofa.serverless + sofa-serverless-app-starter + ${sofa.serverless.runtime.version} + provided + org.springframework.kafka spring-kafka diff --git a/samples/springboot3-samples/msg/kafka/biz2/pom.xml b/samples/springboot3-samples/msg/kafka/biz2/pom.xml index c76a12933..4a12e3b76 100644 --- a/samples/springboot3-samples/msg/kafka/biz2/pom.xml +++ b/samples/springboot3-samples/msg/kafka/biz2/pom.xml @@ -43,13 +43,12 @@ spring-kafka provided - - - - - - - + + com.alipay.sofa.serverless + sofa-serverless-app-starter + ${sofa.serverless.runtime.version} + provided + diff --git a/samples/springboot3-samples/pom.xml b/samples/springboot3-samples/pom.xml index 60a3ec172..518d17652 100644 --- a/samples/springboot3-samples/pom.xml +++ b/samples/springboot3-samples/pom.xml @@ -20,7 +20,7 @@ 3.2.1 17 - 3.0.2-SNAPSHOT + 3.0.2 0.5.6-jdk17-SNAPSHOT 3.4.2 1.7.1 @@ -41,6 +41,12 @@ msg/kafka/biz2 db/mybatis/base db/mybatis/biz1 + web/webflux/biz + web/webflux/base + web/webflux/biz + config/apollo/base + config/apollo/biz1 + config/apollo/biz2 @@ -105,12 +111,6 @@ ${sofa.serverless.runtime.version} - - com.alipay.sofa - log-sofa-boot-starter - 3.9.1 - - com.alipay.sofa.common diff --git a/samples/springboot3-samples/web/tomcat/base/pom.xml b/samples/springboot3-samples/web/tomcat/base/pom.xml index f0dbf7921..a6f37a39c 100644 --- a/samples/springboot3-samples/web/tomcat/base/pom.xml +++ b/samples/springboot3-samples/web/tomcat/base/pom.xml @@ -52,17 +52,6 @@ - - com.alipay.sofa - log-sofa-boot-starter - 3.9.1 - - - com.alipay.sofa.common - sofa-common-tools - - - com.alipay.sofa.common diff --git a/samples/springboot3-samples/web/tomcat/biz1/pom.xml b/samples/springboot3-samples/web/tomcat/biz1/pom.xml index b87f7f13a..4d88aefe0 100644 --- a/samples/springboot3-samples/web/tomcat/biz1/pom.xml +++ b/samples/springboot3-samples/web/tomcat/biz1/pom.xml @@ -15,6 +15,14 @@ biz1 + + + com.alipay.sofa.serverless + sofa-serverless-base-starter + + ${sofa.serverless.runtime.version} + provided + org.springframework.boot diff --git a/samples/springboot3-samples/web/tomcat/biz2/pom.xml b/samples/springboot3-samples/web/tomcat/biz2/pom.xml index 6386a87e0..8682c8dca 100644 --- a/samples/springboot3-samples/web/tomcat/biz2/pom.xml +++ b/samples/springboot3-samples/web/tomcat/biz2/pom.xml @@ -15,6 +15,14 @@ biz2 + + + com.alipay.sofa.serverless + sofa-serverless-base-starter + + ${sofa.serverless.runtime.version} + provided + org.springframework.boot diff --git a/samples/springboot3-samples/web/webflux/README.md b/samples/springboot3-samples/web/webflux/README.md new file mode 100644 index 000000000..792a09529 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/README.md @@ -0,0 +1,183 @@ + +# 实验内容:基座、模块使用 webflux + +## 背景 + +基座、模块合并部署,使用 webflux 支持两种模式: + +### 多host模式 +1. 直接将基座和模块的server.port设置为不同端口 +2. 基座、模块通过不同端口访问各自web服务 + +### 单host模式 +1. 基座和模块使用相同的server.port,默认如8080 +2. 基座、模块通过相同端口、不同context path访问各自web服务 + +该实验验证基座、模块采用单host,多context path模式使用webflux + +## 实验应用 +### base +base 为普通 springboot 改造成的基座,改造内容为在 pom 里增加如下依赖,注意 ⚠️ netty-ark-plugin 版本要求 >= 2.2.5 +```xml + + + + + com.alipay.sofa.serverless + sofa-serverless-base-starter + ${sofa.serverless.runtime.version} + pom + + + + + + org.springframework.boot + spring-boot-starter-webflux + + + + + + com.alipay.sofa + netty-ark-plugin + + ${sofa.ark.version} + + + +``` + +### biz +biz 是普通 springboot,修改打包插件方式为 sofaArk biz 模块打包方式,打包为 ark biz jar 包,打包插件配置如下: +```xml + + com.alipay.sofa.serverless + sofa-serverless-app-starter + provided + + + + + com.alipay.sofa + sofa-ark-maven-plugin + ${sofa.ark.version} + + + default-cli + + repackage + + + + + true + ./target + ${bizName} + + /${bizName} + true + + +``` +注意这里将不同 biz 的web context path 修改成不同的值,以此才能成功在一个 netty host 里安装多个 web 应用。 + + +## 实验步骤 + +### 启动基座应用 base + +可以使用 IDEA run 启动基座应用 + +### 打包模块应用 biz + +在xx/samples/springboot-samples/web/webflux/biz 目录下执行 mvn clean package -Dmaven.test.skip=true 进行模块打包, 打包完成后可在各 bundle 的 target 目录里查看到打包生成的 ark-biz jar 包 + +### 安装模块应用 biz + +#### 执行 curl 命令安装 biz + +```shell +curl --location --request POST 'localhost:1238/installBiz' \ +--header 'Content-Type: application/json' \ +--data '{ + "bizName": "biz", + "bizVersion": "0.0.1-SNAPSHOT", + // local path should start with file://, alse support remote url which can be downloaded + "bizUrl": "file:///Users/xxxxx/sofa-serverless/samples/springboot-samples/web/webflux/biz/target/bizwebflux-0.0.1-SNAPSHOT-ark-biz.jar" +}' +``` + +### 发起请求验证 + +#### 1. 验证基座服务 + +访问基座 base 的 web 服务 +```shell +curl http://localhost:8080/hello +``` +返回 `Hello, city!` +```shell +curl curl http://localhost:8080/village +``` +返回 `Hello, village` + +且日志里能看到调用成功返回 + +#### 2. 验证模块服务 + +访问 biz 的 web 服务,由于是单host模式,模块服务也发布在8080端口,需要在path中添加在模块打包插件中配置的 /${bizName} 作为前缀访问 +```shell +curl http://localhost:8080/biz/biz +``` +返回 `Hello, biz webflux!` + +且日志里能看到调用成功返回 + +#### 3. 验证模块卸载后,基座服务可正常访问,模块服务无法再访问 + +访问基座 base 的 web 服务 +```shell +curl http://localhost:8080/hello +``` +返回 `Hello, city!` + +访问 biz 的 web 服务 +```shell +curl http://localhost:8080/biz/biz +``` +返回 `{"timestamp":"2023-11-22T08:56:11.508+00:00","path":"/biz/biz","status":404,"error":"Not Found","message":null,"requestId":"a7917dd5-6"}` +模块服务已经无法再访问,"status":404 + +#### 4. 模块重新安装后,基座服务可正常访问,模块新服务可正常访问 + +#### 执行 curl 命令安装 biz + +```shell +curl --location --request POST 'localhost:1238/installBiz' \ +--header 'Content-Type: application/json' \ +--data '{ + "bizName": "biz", + "bizVersion": "0.0.1-SNAPSHOT", + // local path should start with file://, alse support remote url which can be downloaded + "bizUrl": "file:///Users/xxxxx/sofa-serverless/samples/springboot-samples/web/webflux/biz/target/bizwebflux-0.0.1-SNAPSHOT-ark-biz.jar" +}' +``` +访问基座 base 的 web 服务 +```shell +curl http://localhost:8080/hello +``` +返回 `Hello, city!` + +访问 biz 的 web 服务 +```shell +curl http://localhost:8080/biz/biz +``` +返回 `Hello, biz webflux!` + + +## 注意事项 +1. 支持基座、模块合并部署时采用单host多context path需要 netty-ark-plugin 依赖版本 >= 2.2.5 +2. 支持模块多次安装、多次卸载 +3. 支持模块先卸后装,不支持先装后卸 diff --git a/samples/springboot3-samples/web/webflux/base/pom.xml b/samples/springboot3-samples/web/webflux/base/pom.xml new file mode 100644 index 000000000..33336ab9c --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/pom.xml @@ -0,0 +1,72 @@ + + + 4.0.0 + + com.alipay.sofa + springboot-samples + 0.0.1-SNAPSHOT + ../../../pom.xml + + om.alipay.sofa + demowebflux + 0.0.1-SNAPSHOT + demowebflux + Demo project for Spring Boot + + + + + com.alipay.sofa.serverless + sofa-serverless-base-starter + ${sofa.serverless.runtime.version} + pom + + + com.alipay.sofa.serverless + sofa-serverless-adapter-log4j2 + + + + + jakarta.validation + jakarta.validation-api + 3.0.1 + + + com.alipay.sofa + netty-ark-plugin + 3.0.2 + + + org.springframework.boot + spring-boot-starter-logging + + + org.springframework.boot + spring-boot-starter-webflux + 3.2.1 + + + org.springframework.boot + spring-boot-starter-test + test + + + + + base-demowebflux + + + org.springframework.boot + spring-boot-maven-plugin + + true + + + + + + diff --git a/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/CityHandler.java b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/CityHandler.java new file mode 100644 index 000000000..d8cbe5a66 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/CityHandler.java @@ -0,0 +1,25 @@ +package com.example.yuan.demowebflux; + +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +/** + * @author: yuanyuan + * @date: 2023/11/6 5:19 下午 + */ +@Component +public class CityHandler { + + public Mono helloCity(ServerRequest request) { + + return ServerResponse + .ok() + .contentType(MediaType.TEXT_PLAIN) + .body(BodyInserters.fromValue("Hello, city!")); + } + +} diff --git a/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/CountryHandler.java b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/CountryHandler.java new file mode 100644 index 000000000..cb489380f --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/CountryHandler.java @@ -0,0 +1,23 @@ +package com.example.yuan.demowebflux; + +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +/** + * @author: yuanyuan + * @date: 2023/11/6 5:28 下午 + */ +@Component +public class CountryHandler { + + public Mono helloCountry(ServerRequest request) { + return ServerResponse + .ok() + .contentType(MediaType.TEXT_PLAIN) + .body(BodyInserters.fromValue("Hello, country!")); + } +} diff --git a/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/DemowebfluxApplication.java b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/DemowebfluxApplication.java new file mode 100644 index 000000000..65dae46af --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/DemowebfluxApplication.java @@ -0,0 +1,14 @@ +package com.example.yuan.demowebflux; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class DemowebfluxApplication { + + public static void main(String[] args) { + SpringApplication.run(DemowebfluxApplication.class, args); + System.out.println("DemowebfluxApplication start!!!"); + } + +} diff --git a/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/RouterConfig.java b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/RouterConfig.java new file mode 100644 index 000000000..ebb5b3c57 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/RouterConfig.java @@ -0,0 +1,32 @@ +package com.example.yuan.demowebflux; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.server.RequestPredicates; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; + +/** + * @author: yuanyuan + * @date: 2023/11/6 5:23 下午 + */ +@Configuration +public class RouterConfig { + + @Autowired + private CityHandler cityHandler; + + @Autowired + private CountryHandler countryHandler; + + @Bean + public RouterFunction routeCity() { + return RouterFunctions + .route(RequestPredicates.GET("/hello").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), cityHandler::helloCity) + .andRoute(RequestPredicates.GET("/country").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), countryHandler::helloCountry); + } + +} diff --git a/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/VillageController.java b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/VillageController.java new file mode 100644 index 000000000..17aa2e373 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/src/main/java/com/example/yuan/demowebflux/VillageController.java @@ -0,0 +1,24 @@ +package com.example.yuan.demowebflux; + +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Mono; + +/** + * @author: yuanyuan + * @date: 2023/11/6 5:31 下午 + */ +@RestController +public class VillageController { + + @GetMapping("/village") + public Mono village(){ + return Mono.just("Hello, village"); + } + + @GetMapping("/demo") + public String demo() { + return "Hello, demo"; + } + +} diff --git a/samples/springboot3-samples/web/webflux/base/src/main/resources/application-sim.properties b/samples/springboot3-samples/web/webflux/base/src/main/resources/application-sim.properties new file mode 100644 index 000000000..761e4d842 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/src/main/resources/application-sim.properties @@ -0,0 +1 @@ +spring.application.name=xxxxx \ No newline at end of file diff --git a/samples/springboot3-samples/web/webflux/base/src/main/resources/application.properties b/samples/springboot3-samples/web/webflux/base/src/main/resources/application.properties new file mode 100644 index 000000000..16e100925 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/src/main/resources/application.properties @@ -0,0 +1,2 @@ +spring.application.name=demowebflux +logging.level.org.springframework=TRACE diff --git a/samples/springboot3-samples/web/webflux/base/src/test/java/com/example/yuan/demowebflux/DemowebfluxApplicationTests.java b/samples/springboot3-samples/web/webflux/base/src/test/java/com/example/yuan/demowebflux/DemowebfluxApplicationTests.java new file mode 100644 index 000000000..13240dac4 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/base/src/test/java/com/example/yuan/demowebflux/DemowebfluxApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.yuan.demowebflux; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class DemowebfluxApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/samples/springboot3-samples/web/webflux/biz/META-INF/MANIFEST.MF b/samples/springboot3-samples/web/webflux/biz/META-INF/MANIFEST.MF new file mode 100644 index 000000000..24618843c --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/META-INF/MANIFEST.MF @@ -0,0 +1,56 @@ +Manifest-Version: 1.0 +Created-By: Maven JAR Plugin 3.3.0 +Build-Jdk-Spec: 17 +Implementation-Title: bizwebflux +Implementation-Version: 0.0.1-SNAPSHOT +Main-Class: com.example.yuan.bizwebflux.BizwebfluxApplication +Ark-Biz-Name: biz +Ark-Biz-Version: 0.0.1-SNAPSHOT +priority: 100 +web-context-path: /biz +deny-import-packages: +deny-import-classes: +deny-import-resources: +inject-plugin-dependencies: +inject-export-packages: +declared-libraries: listenablefuture,reactive-streams,hessian,jackson-an + notations,lz4-java,netty-handler-ssl-ocsp,jackson-databind,druid-spring + -boot-starter,mybatis-spring-boot-autoconfigure,HdrHistogram,netty-tran + sport-native-epoll,netty-handler,jsr305,plexus-utils,jackson-datatype-j + sr310,tomcat-embed-el,guice,reactor-netty-incubator-quic,netty-codec-me + mcache,lombok,netty-codec-stomp,netty-incubator-codec-classes-quic,java + x.inject,reactor-netty-core,spring-boot-loader,sofa-ark-springboot-star + ter,netty-transport-native-kqueue,arklet-core,spring-boot-autoconfigure + ,sofa-ark-exception,sofa-serverless-adapter-apollo,netty-codec-haproxy, + text-ui,spring-boot-starter-json,fastjson,netty-transport-native-unix-c + ommon,spring-boot-starter-actuator,spring-boot-starter-web,netty-resolv + er-dns-classes-macos,spring-context,spring-boot-actuator,reactor-netty, + netty-codec-dns,slf4j-api,spring-aop,jackson-module-parameter-names,spr + ing-boot-starter-jdbc,spring-kafka,tomcat-embed-websocket,netty-transpo + rt-sctp,j2objc-annotations,micrometer-core,netty-transport-classes-epol + l,maven-model,netty-codec,logback-core,log4j-api,sofa-ark-support-start + er,web-ark-plugin,spring-retry,byte-buddy-agent,HikariCP,netty-codec-ht + tp,spring-messaging,micrometer-observation,spring-boot-starter-tomcat,s + nakeyaml,snappy-java,spring-web,mybatis,sofa-ark-all,commons-io,reactor + -netty-http,netty-transport-rxtx,LatencyUtils,log4j-jul,spring-jcl,jul- + to-slf4j,spring-expression,netty-buffer,netty-codec-http2,log4j-core,ne + tty-handler-proxy,sofa-common-tools,netty-transport-udt,mysql-connector + -j,sofa-serverless-app-starter,sofa-serverless-base-starter,jna,log-sof + a-boot,netty-incubator-codec-native-quic,sofa-serverless-adapter-log4j2 + ,netty-resolver-dns-native-macos,javax.annotation-api,netty-codec-redis + ,jackson-datatype-jdk8,logback-classic,sofa-ark-archive,netty-all,sprin + g-boot-actuator-autoconfigure,zstd-jni,spring-boot,micrometer-jakarta9, + spring-webmvc,netty-codec-xml,sofa-serverless-base-plugin,jakarta.annot + ation-api,kafka-clients,oshi-core,aopalliance,sofa-ark-container,sofa-s + erverless-common,netty-transport,druid,netty-codec-smtp,sofa-ark-common + ,arklet-springboot-starter,mybatis-spring,netty-codec-mqtt,netty-common + ,micrometer-commons,netty-codec-socks,failureaccess,sofa-ark-common-spr + ingboot,error_prone_annotations,netty-transport-classes-kqueue,mybatis- + spring-boot-starter,spring-jdbc,guava,checker-qual,sofa-serverless-adap + ter-logback,spring-boot-starter,sofa-ark-spi,jakarta.inject-api,spring- + beans,log-sofa-boot-starter,spring-boot-starter-logging,jackson-core,so + fa-ark-api,disruptor,tomcat-embed-core,reactor-core,spring-tx,netty-res + olver,log4j-slf4j2-impl,jna-platform,spring-core,spring-boot-starter-lo + g4j2,netty-resolver-dns,log4j-to-slf4j +build-time: 2024-01-23T20:21:12+0800 + diff --git a/samples/springboot3-samples/web/webflux/biz/META-INF/maven/com.alipay.sofa/bizwebflux/pom.properties b/samples/springboot3-samples/web/webflux/biz/META-INF/maven/com.alipay.sofa/bizwebflux/pom.properties new file mode 100644 index 000000000..e78479c0a --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/META-INF/maven/com.alipay.sofa/bizwebflux/pom.properties @@ -0,0 +1,3 @@ +artifactId=bizwebflux +groupId=com.alipay.sofa +version=0.0.1-SNAPSHOT diff --git a/samples/springboot3-samples/web/webflux/biz/META-INF/maven/com.alipay.sofa/bizwebflux/pom.xml b/samples/springboot3-samples/web/webflux/biz/META-INF/maven/com.alipay.sofa/bizwebflux/pom.xml new file mode 100644 index 000000000..fdf7ac3ad --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/META-INF/maven/com.alipay.sofa/bizwebflux/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + com.alipay.sofa + springboot-samples + 0.0.1-SNAPSHOT + ../../../pom.xml + + com.alipay.sofa + bizwebflux + 0.0.1-SNAPSHOT + bizwebflux + Demo project for Spring Boot + + + + org.springframework.boot + spring-boot-starter-webflux + provided + + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + + + + + + + com.alipay.sofa + sofa-ark-maven-plugin + ${sofa.ark.version} + + + default-cli + + repackage + + + + + true + target + biz + + /biz + true + + + + + + diff --git a/samples/springboot3-samples/web/webflux/biz/application.properties b/samples/springboot3-samples/web/webflux/biz/application.properties new file mode 100644 index 000000000..d11057660 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/application.properties @@ -0,0 +1,2 @@ +spring.application.name=bizwebflux +#server.port=8888 diff --git a/samples/springboot3-samples/web/webflux/biz/com/alipay/sofa/ark/biz/mark b/samples/springboot3-samples/web/webflux/biz/com/alipay/sofa/ark/biz/mark new file mode 100644 index 000000000..ce55efbc9 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/com/alipay/sofa/ark/biz/mark @@ -0,0 +1 @@ +a mark file included in sofa-ark module. \ No newline at end of file diff --git a/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/BizHandler.class b/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/BizHandler.class new file mode 100644 index 000000000..df215d8c6 Binary files /dev/null and b/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/BizHandler.class differ diff --git a/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/BizwebfluxApplication.class b/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/BizwebfluxApplication.class new file mode 100644 index 000000000..071c3f05b Binary files /dev/null and b/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/BizwebfluxApplication.class differ diff --git a/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/RouterConfig.class b/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/RouterConfig.class new file mode 100644 index 000000000..6e2ebdb43 Binary files /dev/null and b/samples/springboot3-samples/web/webflux/biz/com/example/yuan/bizwebflux/RouterConfig.class differ diff --git a/samples/springboot3-samples/web/webflux/biz/pom.xml b/samples/springboot3-samples/web/webflux/biz/pom.xml new file mode 100644 index 000000000..fdf7ac3ad --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + com.alipay.sofa + springboot-samples + 0.0.1-SNAPSHOT + ../../../pom.xml + + com.alipay.sofa + bizwebflux + 0.0.1-SNAPSHOT + bizwebflux + Demo project for Spring Boot + + + + org.springframework.boot + spring-boot-starter-webflux + provided + + + + org.springframework.boot + spring-boot-starter-test + test + + + io.projectreactor + reactor-test + test + + + + + + + + + + + + com.alipay.sofa + sofa-ark-maven-plugin + ${sofa.ark.version} + + + default-cli + + repackage + + + + + true + target + biz + + /biz + true + + + + + + diff --git a/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/BizHandler.java b/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/BizHandler.java new file mode 100644 index 000000000..4820974e3 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/BizHandler.java @@ -0,0 +1,24 @@ +package com.example.yuan.bizwebflux; + +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.server.ServerRequest; +import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; + +/** + * @author: yuanyuan + * @date: 2023/11/6 7:53 下午 + */ +@Component +public class BizHandler { + + public Mono helloBiz(ServerRequest request) { + return ServerResponse + .ok() + .contentType(MediaType.TEXT_PLAIN) + .body(BodyInserters.fromValue("Hello, biz webflux!")); + } + +} diff --git a/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/BizwebfluxApplication.java b/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/BizwebfluxApplication.java new file mode 100644 index 000000000..9e4eb1ead --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/BizwebfluxApplication.java @@ -0,0 +1,13 @@ +package com.example.yuan.bizwebflux; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class BizwebfluxApplication { + + public static void main(String[] args) { + SpringApplication.run(BizwebfluxApplication.class, args); + } + +} diff --git a/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/RouterConfig.java b/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/RouterConfig.java new file mode 100644 index 000000000..9a7cd2db8 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/src/main/java/com/example/yuan/bizwebflux/RouterConfig.java @@ -0,0 +1,28 @@ +package com.example.yuan.bizwebflux; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.MediaType; +import org.springframework.web.reactive.function.server.RequestPredicates; +import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerResponse; + +/** + * @author: yuanyuan + * @date: 2023/11/6 5:23 下午 + */ +@Configuration +public class RouterConfig { + + @Autowired + private BizHandler bizHandler; + + @Bean + public RouterFunction routeRequest() { + return RouterFunctions + .route(RequestPredicates.GET("/biz").and(RequestPredicates.accept(MediaType.TEXT_PLAIN)), bizHandler::helloBiz); + } + +} diff --git a/samples/springboot3-samples/web/webflux/biz/src/main/resources/application.properties b/samples/springboot3-samples/web/webflux/biz/src/main/resources/application.properties new file mode 100644 index 000000000..d11057660 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/src/main/resources/application.properties @@ -0,0 +1,2 @@ +spring.application.name=bizwebflux +#server.port=8888 diff --git a/samples/springboot3-samples/web/webflux/biz/src/test/java/com/example/yuan/bizwebflux/BizwebfluxApplicationTests.java b/samples/springboot3-samples/web/webflux/biz/src/test/java/com/example/yuan/bizwebflux/BizwebfluxApplicationTests.java new file mode 100644 index 000000000..04eadd634 --- /dev/null +++ b/samples/springboot3-samples/web/webflux/biz/src/test/java/com/example/yuan/bizwebflux/BizwebfluxApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.yuan.bizwebflux; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class BizwebfluxApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/sofa-serverless-runtime/pom.xml b/sofa-serverless-runtime/pom.xml index 00a1fbce5..c20e91dc6 100644 --- a/sofa-serverless-runtime/pom.xml +++ b/sofa-serverless-runtime/pom.xml @@ -9,7 +9,7 @@ pom - 3.0.2-SNAPSHOT + 3.0.2 3.2.1 0.5.6-jdk17-SNAPSHOT UTF-8 diff --git a/sofa-serverless-runtime/sofa-serverless-adapter-ext/pom.xml b/sofa-serverless-runtime/sofa-serverless-adapter-ext/pom.xml index 9bdc21d57..c725f0730 100644 --- a/sofa-serverless-runtime/sofa-serverless-adapter-ext/pom.xml +++ b/sofa-serverless-runtime/sofa-serverless-adapter-ext/pom.xml @@ -13,6 +13,7 @@ pom + sofa-serverless-adapter-log4j2 sofa-serverless-adapter-logback sofa-serverless-adapter-apollo diff --git a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/pom.xml b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/pom.xml new file mode 100644 index 000000000..ddab63580 --- /dev/null +++ b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/pom.xml @@ -0,0 +1,75 @@ + + + 4.0.0 + + com.alipay.sofa.serverless + sofa-serverless-adapter-ext + ${revision} + ../pom.xml + + sofa-serverless-adapter-log4j2 + ${revision} + + + + org.springframework.boot + spring-boot-starter + ${spring.boot.version} + provided + + + org.springframework.boot + spring-boot-starter-logging + + + + + org.springframework.boot + spring-boot-starter-log4j2 + ${spring.boot.version} + provided + + + com.alipay.sofa + sofa-ark-spi + provided + + + + + + + com.alipay.sofa + sofa-ark-plugin-maven-plugin + ${sofa.ark.version} + + + default-cli + + ark-plugin + + + + + com.alipay.sofa.serverless.adapter.Log4j2AdapterActivator + + + + + + org.springframework.boot.logging.log4j2.Log4J2LoggingSystem + + + + + *:*:* + com.alipay.sofa.serverless:sofa-serverless-adapter-log4j2 + + + + + + + + diff --git a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/com/alipay/sofa/serverless/adapter/Log4j2AdapterActivator.java b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/com/alipay/sofa/serverless/adapter/Log4j2AdapterActivator.java new file mode 100644 index 000000000..6f7c44c75 --- /dev/null +++ b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/com/alipay/sofa/serverless/adapter/Log4j2AdapterActivator.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.alipay.sofa.serverless.adapter; + +import com.alipay.sofa.ark.spi.model.PluginContext; +import com.alipay.sofa.ark.spi.service.PluginActivator; + +/** + * @author lvjing2 + * @since 0.5.5 + */ +public class Log4j2AdapterActivator implements PluginActivator { + @Override + public void start(PluginContext context) { + } + + @Override + public void stop(PluginContext context) { + // no op + } +} diff --git a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java new file mode 100644 index 000000000..be6c496a3 --- /dev/null +++ b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/springframework/boot/context/logging/LoggingApplicationListener.java @@ -0,0 +1,522 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.boot.context.logging; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.apache.logging.log4j.ThreadContext; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent; +import org.springframework.boot.context.event.ApplicationFailedEvent; +import org.springframework.boot.context.event.ApplicationPreparedEvent; +import org.springframework.boot.context.event.ApplicationStartingEvent; +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.source.ConfigurationPropertyName; +import org.springframework.boot.logging.LogFile; +import org.springframework.boot.logging.LogLevel; +import org.springframework.boot.logging.LoggerGroup; +import org.springframework.boot.logging.LoggerGroups; +import org.springframework.boot.logging.LoggingInitializationContext; +import org.springframework.boot.logging.LoggingSystem; +import org.springframework.boot.logging.LoggingSystemProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.ApplicationEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.SmartLifecycle; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.context.event.GenericApplicationListener; +import org.springframework.core.Ordered; +import org.springframework.core.ResolvableType; +import org.springframework.core.env.ConfigurableEnvironment; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.core.env.Environment; +import org.springframework.core.log.LogMessage; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; + +import java.io.FileNotFoundException; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.function.BiConsumer; + +/** + * An {@link ApplicationListener} that configures the {@link LoggingSystem}. If the + * environment contains a {@code logging.config} property it will be used to bootstrap the + * logging system, otherwise a default configuration is used. Regardless, logging levels + * will be customized if the environment contains {@code logging.level.*} entries and + * logging groups can be defined with {@code logging.group}. + *

+ * Debug and trace logging for Spring, Tomcat, Jetty and Hibernate will be enabled when + * the environment contains {@code debug} or {@code trace} properties that aren't set to + * {@code "false"} (i.e. if you start your application using + * {@literal java -jar myapp.jar [--debug | --trace]}). If you prefer to ignore these + * properties you can set {@link #setParseArgs(boolean) parseArgs} to {@code false}. + *

+ * By default, log output is only written to the console. If a log file is required, the + * {@code logging.file.path} and {@code logging.file.name} properties can be used. + *

+ * Some system properties may be set as side effects, and these can be useful if the + * logging configuration supports placeholders (i.e. log4j or logback): + *

    + *
  • {@code LOG_FILE} is set to the value of path of the log file that should be written + * (if any).
  • + *
  • {@code PID} is set to the value of the current process ID if it can be determined. + *
  • + *
+ * + * @author Dave Syer + * @author Phillip Webb + * @author Andy Wilkinson + * @author Madhura Bhave + * @author HaiTao Zhang + * @since 2.0.0 + * @see LoggingSystem#get(ClassLoader) + */ +public class LoggingApplicationListener implements GenericApplicationListener { + + private static final ConfigurationPropertyName LOGGING_LEVEL = ConfigurationPropertyName + .of("logging.level"); + + private static final ConfigurationPropertyName LOGGING_GROUP = ConfigurationPropertyName + .of("logging.group"); + + private static final Bindable> STRING_LOGLEVEL_MAP = Bindable + .mapOf( + String.class, + LogLevel.class); + + private static final Bindable>> STRING_STRINGS_MAP = Bindable + .of(ResolvableType + .forClassWithGenerics( + MultiValueMap.class, + String.class, + String.class) + .asMap()); + + /** + * The default order for the LoggingApplicationListener. + */ + public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 20; + + /** + * The name of the Spring property that contains a reference to the logging + * configuration to load. + */ + public static final String CONFIG_PROPERTY = "logging.config"; + + /** + * The name of the Spring property that controls the registration of a shutdown hook + * to shut down the logging system when the JVM exits. + * @see LoggingSystem#getShutdownHandler + */ + public static final String REGISTER_SHUTDOWN_HOOK_PROPERTY = "logging.register-shutdown-hook"; + + /** + * The name of the {@link LoggingSystem} bean. + */ + public static final String LOGGING_SYSTEM_BEAN_NAME = "springBootLoggingSystem"; + + /** + * The name of the {@link LogFile} bean. + * @since 2.2.0 + */ + public static final String LOG_FILE_BEAN_NAME = "springBootLogFile"; + + /** + * The name of the {@link LoggerGroups} bean. + * @since 2.2.0 + */ + public static final String LOGGER_GROUPS_BEAN_NAME = "springBootLoggerGroups"; + + /** + * The name of the {@link Lifecycle} bean used to handle cleanup. + */ + private static final String LOGGING_LIFECYCLE_BEAN_NAME = "springBootLoggingLifecycle"; + + private static final Map> DEFAULT_GROUP_LOGGERS; + static { + MultiValueMap loggers = new LinkedMultiValueMap<>(); + loggers.add("web", "org.springframework.core.codec"); + loggers.add("web", "org.springframework.http"); + loggers.add("web", "org.springframework.web"); + loggers.add("web", "org.springframework.boot.actuate.endpoint.web"); + loggers.add("web", "org.springframework.boot.web.servlet.ServletContextInitializerBeans"); + loggers.add("sql", "org.springframework.jdbc.core"); + loggers.add("sql", "org.hibernate.SQL"); + loggers.add("sql", "org.jooq.tools.LoggerListener"); + DEFAULT_GROUP_LOGGERS = Collections.unmodifiableMap(loggers); + } + + private static final Map> SPRING_BOOT_LOGGING_LOGGERS; + static { + MultiValueMap loggers = new LinkedMultiValueMap<>(); + loggers.add(LogLevel.DEBUG, "sql"); + loggers.add(LogLevel.DEBUG, "web"); + loggers.add(LogLevel.DEBUG, "org.springframework.boot"); + loggers.add(LogLevel.TRACE, "org.springframework"); + loggers.add(LogLevel.TRACE, "org.apache.tomcat"); + loggers.add(LogLevel.TRACE, "org.apache.catalina"); + loggers.add(LogLevel.TRACE, "org.eclipse.jetty"); + loggers.add(LogLevel.TRACE, "org.hibernate.tool.hbm2ddl"); + SPRING_BOOT_LOGGING_LOGGERS = Collections.unmodifiableMap(loggers); + } + + private static final Class[] EVENT_TYPES = { + ApplicationStartingEvent.class, ApplicationEnvironmentPreparedEvent.class, + ApplicationPreparedEvent.class, ContextClosedEvent.class, ApplicationFailedEvent.class }; + + private static final Class[] SOURCE_TYPES = { + SpringApplication.class, ApplicationContext.class }; + + private static final AtomicBoolean shutdownHookRegistered = new AtomicBoolean(); + + private final Log logger = LogFactory + .getLog(getClass()); + + private LoggingSystem loggingSystem; + + private LogFile logFile; + + private LoggerGroups loggerGroups; + + private int order = DEFAULT_ORDER; + + private boolean parseArgs = true; + + private LogLevel springBootLogging = null; + + @Override + public boolean supportsEventType(ResolvableType resolvableType) { + return isAssignableFrom(resolvableType.getRawClass(), EVENT_TYPES); + } + + @Override + public boolean supportsSourceType(Class sourceType) { + return isAssignableFrom(sourceType, SOURCE_TYPES); + } + + private boolean isAssignableFrom(Class type, Class... supportedTypes) { + if (type != null) { + for (Class supportedType : supportedTypes) { + if (supportedType.isAssignableFrom(type)) { + return true; + } + } + } + return false; + } + + @Override + public void onApplicationEvent(ApplicationEvent event) { + if (event instanceof ApplicationStartingEvent) { + onApplicationStartingEvent((ApplicationStartingEvent) event); + } else if (event instanceof ApplicationEnvironmentPreparedEvent) { + onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent) event); + } else if (event instanceof ApplicationPreparedEvent) { + onApplicationPreparedEvent((ApplicationPreparedEvent) event); + } else if (event instanceof ContextClosedEvent) { + onContextClosedEvent((ContextClosedEvent) event); + } else if (event instanceof ApplicationFailedEvent) { + onApplicationFailedEvent(); + } + } + + private void onApplicationStartingEvent(ApplicationStartingEvent event) { + this.loggingSystem = LoggingSystem.get(event.getSpringApplication().getClassLoader()); + this.loggingSystem.beforeInitialize(); + } + + private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) { + SpringApplication springApplication = event.getSpringApplication(); + if (this.loggingSystem == null) { + this.loggingSystem = LoggingSystem.get(springApplication.getClassLoader()); + } + initialize(event.getEnvironment(), springApplication.getClassLoader()); + } + + private void onApplicationPreparedEvent(ApplicationPreparedEvent event) { + ConfigurableApplicationContext applicationContext = event.getApplicationContext(); + ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); + if (!beanFactory.containsBean(LOGGING_SYSTEM_BEAN_NAME)) { + beanFactory.registerSingleton(LOGGING_SYSTEM_BEAN_NAME, this.loggingSystem); + } + if (this.logFile != null && !beanFactory.containsBean(LOG_FILE_BEAN_NAME)) { + beanFactory.registerSingleton(LOG_FILE_BEAN_NAME, this.logFile); + } + if (this.loggerGroups != null && !beanFactory.containsBean(LOGGER_GROUPS_BEAN_NAME)) { + beanFactory.registerSingleton(LOGGER_GROUPS_BEAN_NAME, this.loggerGroups); + } + if (!beanFactory.containsBean(LOGGING_LIFECYCLE_BEAN_NAME) + && applicationContext.getParent() == null) { + beanFactory.registerSingleton(LOGGING_LIFECYCLE_BEAN_NAME, new Lifecycle()); + } + } + + private void onContextClosedEvent(ContextClosedEvent event) { + ApplicationContext applicationContext = event.getApplicationContext(); + if (applicationContext.getParent() != null + || applicationContext.containsBean(LOGGING_LIFECYCLE_BEAN_NAME)) { + return; + } + cleanupLoggingSystem(); + } + + void cleanupLoggingSystem() { + if (this.loggingSystem != null) { + this.loggingSystem.cleanUp(); + } + } + + private void onApplicationFailedEvent() { + cleanupLoggingSystem(); + } + + /** + * Initialize the logging system according to preferences expressed through the + * {@link Environment} and the classpath. + * @param environment the environment + * @param classLoader the classloader + */ + protected void initialize(ConfigurableEnvironment environment, ClassLoader classLoader) { + getLoggingSystemProperties(environment).apply(); + this.logFile = LogFile.get(environment); + if (this.logFile != null) { + this.logFile.applyToSystemProperties(); + } + this.loggerGroups = new LoggerGroups(DEFAULT_GROUP_LOGGERS); + initializeEarlyLoggingLevel(environment); + initalizeThreadContextConfig(environment); + initializeSystem(environment, this.loggingSystem, this.logFile); + initializeFinalLoggingLevels(environment, this.loggingSystem); + registerShutdownHookIfNecessary(environment, this.loggingSystem); + } + + private LoggingSystemProperties getLoggingSystemProperties(ConfigurableEnvironment environment) { + return (this.loggingSystem != null) ? this.loggingSystem.getSystemProperties(environment) + : new LoggingSystemProperties(environment); + } + + private void initializeEarlyLoggingLevel(ConfigurableEnvironment environment) { + if (this.parseArgs && this.springBootLogging == null) { + if (isSet(environment, "debug")) { + this.springBootLogging = LogLevel.DEBUG; + } + if (isSet(environment, "trace")) { + this.springBootLogging = LogLevel.TRACE; + } + } + } + + private boolean isSet(ConfigurableEnvironment environment, String property) { + String value = environment.getProperty(property); + return (value != null && !value.equals("false")); + } + + private void initializeSystem(ConfigurableEnvironment environment, LoggingSystem system, + LogFile logFile) { + String logConfig = StringUtils.trimWhitespace(environment.getProperty(CONFIG_PROPERTY)); + try { + LoggingInitializationContext initializationContext = new LoggingInitializationContext( + environment); + if (ignoreLogConfig(logConfig)) { + system.initialize(initializationContext, null, logFile); + } else { + system.initialize(initializationContext, logConfig, logFile); + } + } catch (Exception ex) { + Throwable exceptionToReport = ex; + while (exceptionToReport != null + && !(exceptionToReport instanceof FileNotFoundException)) { + exceptionToReport = exceptionToReport.getCause(); + } + exceptionToReport = (exceptionToReport != null) ? exceptionToReport : ex; + // NOTE: We can't use the logger here to report the problem + System.err.println("Logging system failed to initialize using configuration from '" + + logConfig + "'"); + exceptionToReport.printStackTrace(System.err); + throw new IllegalStateException(ex); + } + } + + private boolean ignoreLogConfig(String logConfig) { + return !StringUtils.hasLength(logConfig) || logConfig.startsWith("-D"); + } + + private void initializeFinalLoggingLevels(ConfigurableEnvironment environment, + LoggingSystem system) { + bindLoggerGroups(environment); + if (this.springBootLogging != null) { + initializeSpringBootLogging(system, this.springBootLogging); + } + setLogLevels(system, environment); + } + + private void initalizeThreadContextConfig(ConfigurableEnvironment environment) { + Map configMap = new ConcurrentHashMap<>(); + Set configKeys = new HashSet<>(); + environment.getPropertySources().stream().filter(propertySource -> propertySource instanceof EnumerablePropertySource) + .forEach(propertySource -> configKeys.addAll(Arrays.asList(((EnumerablePropertySource)propertySource).getPropertyNames()))); + + configKeys.forEach(key -> { + try { + configMap.put(key, environment.getProperty(key)); + } catch (Throwable t) { + // ignore, 异常在 AlipayPrintEnvironmentListener 中打印 + } + }); + + configMap.forEach(ThreadContext::put); + } + + private void bindLoggerGroups(ConfigurableEnvironment environment) { + if (this.loggerGroups != null) { + Binder binder = Binder.get(environment); + binder.bind(LOGGING_GROUP, STRING_STRINGS_MAP).ifBound(this.loggerGroups::putAll); + } + } + + /** + * Initialize loggers based on the {@link #setSpringBootLogging(LogLevel) + * springBootLogging} setting. By default this implementation will pick an appropriate + * set of loggers to configure based on the level. + * @param system the logging system + * @param springBootLogging the spring boot logging level requested + * @since 2.2.0 + */ + protected void initializeSpringBootLogging(LoggingSystem system, LogLevel springBootLogging) { + BiConsumer configurer = getLogLevelConfigurer(system); + SPRING_BOOT_LOGGING_LOGGERS.getOrDefault(springBootLogging, Collections.emptyList()) + .forEach((name) -> configureLogLevel(name, springBootLogging, configurer)); + } + + /** + * Set logging levels based on relevant {@link Environment} properties. + * @param system the logging system + * @param environment the environment + * @since 2.2.0 + */ + protected void setLogLevels(LoggingSystem system, ConfigurableEnvironment environment) { + BiConsumer customizer = getLogLevelConfigurer(system); + Binder binder = Binder.get(environment); + Map levels = binder.bind(LOGGING_LEVEL, STRING_LOGLEVEL_MAP).orElseGet(Collections::emptyMap); + levels.forEach((name, level) -> configureLogLevel(name, level, customizer)); + } + + private void configureLogLevel(String name, LogLevel level, + BiConsumer configurer) { + if (this.loggerGroups != null) { + LoggerGroup group = this.loggerGroups.get(name); + if (group != null && group.hasMembers()) { + group.configureLogLevel(level, configurer); + return; + } + } + configurer.accept(name, level); + } + + private BiConsumer getLogLevelConfigurer(LoggingSystem system) { + return (name, level) -> { + try { + name = name.equalsIgnoreCase(LoggingSystem.ROOT_LOGGER_NAME) ? null : name; + system.setLogLevel(name, level); + } + catch (RuntimeException ex) { + this.logger.error(LogMessage.format("Cannot set level '%s' for '%s'", level, name)); + } + }; + } + + private void registerShutdownHookIfNecessary(Environment environment, + LoggingSystem loggingSystem) { + if (environment.getProperty(REGISTER_SHUTDOWN_HOOK_PROPERTY, Boolean.class, true)) { + Runnable shutdownHandler = loggingSystem.getShutdownHandler(); + if (shutdownHandler != null && shutdownHookRegistered.compareAndSet(false, true)) { + registerShutdownHook(shutdownHandler); + } + } + } + + void registerShutdownHook(Runnable shutdownHandler) { + SpringApplication.getShutdownHandlers().add(shutdownHandler); + } + + public void setOrder(int order) { + this.order = order; + } + + @Override + public int getOrder() { + return this.order; + } + + /** + * Sets a custom logging level to be used for Spring Boot and related libraries. + * @param springBootLogging the logging level + */ + public void setSpringBootLogging(LogLevel springBootLogging) { + this.springBootLogging = springBootLogging; + } + + /** + * Sets if initialization arguments should be parsed for {@literal debug} and + * {@literal trace} properties (usually defined from {@literal --debug} or + * {@literal --trace} command line args). Defaults to {@code true}. + * @param parseArgs if arguments should be parsed + */ + public void setParseArgs(boolean parseArgs) { + this.parseArgs = parseArgs; + } + + private class Lifecycle implements SmartLifecycle { + + private volatile boolean running; + + @Override + public void start() { + this.running = true; + } + + @Override + public void stop() { + this.running = false; + cleanupLoggingSystem(); + } + + @Override + public boolean isRunning() { + return this.running; + } + + @Override + public int getPhase() { + // Shutdown late and always after WebServerStartStopLifecycle + return Integer.MIN_VALUE + 1; + } + + } + +} diff --git a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java new file mode 100644 index 000000000..873e064a5 --- /dev/null +++ b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/org/springframework/boot/logging/log4j2/Log4J2LoggingSystem.java @@ -0,0 +1,465 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.boot.logging.log4j2; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Marker; +import org.apache.logging.log4j.core.Filter; +import org.apache.logging.log4j.core.LogEvent; +import org.apache.logging.log4j.core.Logger; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.AbstractConfiguration; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.ConfigurationFactory; +import org.apache.logging.log4j.core.config.ConfigurationSource; +import org.apache.logging.log4j.core.config.LoggerConfig; +import org.apache.logging.log4j.core.config.composite.CompositeConfiguration; +import org.apache.logging.log4j.core.filter.AbstractFilter; +import org.apache.logging.log4j.core.util.NameUtil; +import org.apache.logging.log4j.message.Message; + +import org.springframework.boot.context.properties.bind.BindResult; +import org.springframework.boot.context.properties.bind.Bindable; +import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.logging.*; +import org.springframework.boot.logging.LoggerConfiguration.LevelConfiguration; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ResourceUtils; +import org.springframework.util.StringUtils; + +/** + * {@link LoggingSystem} for Log4j 2. + * + * @author Daniel Fullarton + * @author Andy Wilkinson + * @author Alexander Heusingfeld + * @author Ben Hale + * @since 1.2.0 + */ +public class Log4J2LoggingSystem extends AbstractLoggingSystem { + + private static final String FILE_PROTOCOL = "file"; + + private static final LogLevels LEVELS = new LogLevels<>(); + + static { + LEVELS.map(LogLevel.TRACE, Level.TRACE); + LEVELS.map(LogLevel.DEBUG, Level.DEBUG); + LEVELS.map(LogLevel.INFO, Level.INFO); + LEVELS.map(LogLevel.WARN, Level.WARN); + LEVELS.map(LogLevel.ERROR, Level.ERROR); + LEVELS.map(LogLevel.FATAL, Level.FATAL); + LEVELS.map(LogLevel.OFF, Level.OFF); + } + + private static final Filter FILTER = new AbstractFilter() { + + @Override + public Result filter(LogEvent event) { + return Result.DENY; + } + + @Override + public Result filter(Logger logger, + Level level, + Marker marker, + Message msg, + Throwable t) { + return Result.DENY; + } + + @Override + public Result filter(Logger logger, + Level level, + Marker marker, + Object msg, + Throwable t) { + return Result.DENY; + } + + @Override + public Result filter(Logger logger, + Level level, + Marker marker, + String msg, + Object... params) { + return Result.DENY; + } + + }; + + public Log4J2LoggingSystem(ClassLoader classLoader) { + super(classLoader); + } + + @Override + protected String[] getStandardConfigLocations() { + return getCurrentlySupportedConfigLocations(); + } + + private String[] getCurrentlySupportedConfigLocations() { + List supportedConfigLocations = new ArrayList<>(); + addTestFiles(supportedConfigLocations); + supportedConfigLocations.add("log4j2.properties"); + if (isClassAvailable("com.fasterxml.jackson.dataformat.yaml.YAMLParser")) { + Collections.addAll(supportedConfigLocations, "log4j2.yaml", "log4j2.yml"); + } + if (isClassAvailable("com.fasterxml.jackson.databind.ObjectMapper")) { + Collections.addAll(supportedConfigLocations, "log4j2.json", "log4j2.jsn"); + } + supportedConfigLocations.add("log4j2.xml"); + return StringUtils.toStringArray(supportedConfigLocations); + } + + private void addTestFiles(List supportedConfigLocations) { + supportedConfigLocations.add("log4j2-test.properties"); + if (isClassAvailable("com.fasterxml.jackson.dataformat.yaml.YAMLParser")) { + Collections.addAll(supportedConfigLocations, "log4j2-test.yaml", "log4j2-test.yml"); + } + if (isClassAvailable("com.fasterxml.jackson.databind.ObjectMapper")) { + Collections.addAll(supportedConfigLocations, "log4j2-test.json", "log4j2-test.jsn"); + } + supportedConfigLocations.add("log4j2-test.xml"); + } + + protected boolean isClassAvailable(String className) { + return ClassUtils.isPresent(className, getClassLoader()); + } + + @Override + public void beforeInitialize() { + LoggerContext loggerContext = getLoggerContext(); + if (isAlreadyInitialized(loggerContext)) { + return; + } + super.beforeInitialize(); + loggerContext.getConfiguration().addFilter(FILTER); + } + + @Override + public void initialize(LoggingInitializationContext initializationContext, + String configLocation, LogFile logFile) { + LoggerContext loggerContext = getLoggerContext(); + if (isAlreadyInitialized(loggerContext)) { + return; + } + loggerContext.getConfiguration().removeFilter(FILTER); + super.initialize(initializationContext, configLocation, logFile); + markAsInitialized(loggerContext); + } + + @Override + protected void loadDefaults(LoggingInitializationContext initializationContext, LogFile logFile) { + if (logFile != null) { + loadConfiguration(getPackagedConfigFile("log4j2-file.xml"), logFile, + getOverrides(initializationContext)); + } else { + loadConfiguration(getPackagedConfigFile("log4j2.xml"), logFile, + getOverrides(initializationContext)); + } + } + + private List getOverrides(LoggingInitializationContext initializationContext) { + BindResult> overrides = Binder.get(initializationContext.getEnvironment()) + .bind("logging.log4j2.config.override", Bindable.listOf(String.class)); + return overrides.orElse(Collections.emptyList()); + } + + @Override + protected void loadConfiguration(LoggingInitializationContext initializationContext, + String location, LogFile logFile) { + if (initializationContext != null) { + applySystemProperties(initializationContext.getEnvironment(), logFile); + } + loadConfiguration(location, logFile, getOverrides(initializationContext)); + } + + /** + * Load the configuration from the given {@code location}. + * @param location the location + * @param logFile log file configuration + * @deprecated since 2.6.0 for removal in 3.0.0 in favor of + * {@link #loadConfiguration(String, LogFile, List)} + */ + @Deprecated + protected void loadConfiguration(String location, LogFile logFile) { + this.loadConfiguration(location, logFile, Collections.emptyList()); + } + + /** + * Load the configuration from the given {@code location}, creating a composite using + * the configuration from the given {@code overrides}. + * @param location the location + * @param logFile log file configuration + * @param overrides the overriding locations + * @since 2.6.0 + */ + protected void loadConfiguration(String location, LogFile logFile, List overrides) { + Assert.notNull(location, "Location must not be null"); + try { + List configurations = new ArrayList<>(); + LoggerContext context = getLoggerContext(); + configurations.add(load(location, context)); + for (String override : overrides) { + configurations.add(load(override, context)); + } + Configuration configuration = (configurations.size() > 1) ? createComposite(configurations) + : configurations.iterator().next(); + context.start(configuration); + } catch (Exception ex) { + throw new IllegalStateException("Could not initialize Log4J2 logging from " + location, + ex); + } + } + + private Configuration load(String location, LoggerContext context) throws IOException { + URL url = ResourceUtils.getURL(location); + ConfigurationSource source = getConfigurationSource(url); + return ConfigurationFactory.getInstance().getConfiguration(context, source); + } + + private ConfigurationSource getConfigurationSource(URL url) throws IOException { + InputStream stream = url.openStream(); + if (FILE_PROTOCOL.equals(url.getProtocol())) { + return new ConfigurationSource(stream, ResourceUtils.getFile(url)); + } + return new ConfigurationSource(stream, url); + } + + private CompositeConfiguration createComposite(List configurations) { + return new CompositeConfiguration( + configurations.stream().map(AbstractConfiguration.class::cast).collect(Collectors.toList())); + } + + @Override + protected void reinitialize(LoggingInitializationContext initializationContext) { + List overrides = getOverrides(initializationContext); + if (!CollectionUtils.isEmpty(overrides)) { + reinitializeWithOverrides(overrides); + } else { + LoggerContext context = getLoggerContext(); + context.reconfigure(); + } + } + + private void reinitializeWithOverrides(List overrides) { + LoggerContext context = getLoggerContext(); + Configuration base = context.getConfiguration(); + List configurations = new ArrayList<>(); + configurations.add((AbstractConfiguration) base); + for (String override : overrides) { + try { + configurations.add((AbstractConfiguration) load(override, context)); + } catch (IOException ex) { + throw new RuntimeException("Failed to load overriding configuration from '" + + override + "'", ex); + } + } + CompositeConfiguration composite = new CompositeConfiguration(configurations); + context.reconfigure(composite); + } + + @Override + public Set getSupportedLogLevels() { + return LEVELS.getSupported(); + } + + @Override + public void setLogLevel(String loggerName, LogLevel logLevel) { + setLogLevel(loggerName, LEVELS.convertSystemToNative(logLevel)); + } + + private void setLogLevel(String loggerName, Level level) { + LoggerConfig logger = getLogger(loggerName); + if (level == null) { + clearLogLevel(loggerName, logger); + } else { + setLogLevel(loggerName, logger, level); + } + getLoggerContext().updateLoggers(); + } + + private void clearLogLevel(String loggerName, LoggerConfig logger) { + if (logger instanceof LevelSetLoggerConfig) { + getLoggerContext().getConfiguration().removeLogger(loggerName); + } else { + logger.setLevel(null); + } + } + + private void setLogLevel(String loggerName, LoggerConfig logger, Level level) { + if (logger == null) { + getLoggerContext().getConfiguration().addLogger(loggerName, + new LevelSetLoggerConfig(loggerName, level, true)); + } else { + logger.setLevel(level); + } + } + + @Override + public List getLoggerConfigurations() { + List result = new ArrayList<>(); + getAllLoggers().forEach((name, loggerConfig) -> result.add(convertLoggerConfig(name, loggerConfig))); + result.sort(CONFIGURATION_COMPARATOR); + return result; + } + + @Override + public LoggerConfiguration getLoggerConfiguration(String loggerName) { + LoggerConfig loggerConfig = getAllLoggers().get(loggerName); + return (loggerConfig != null) ? convertLoggerConfig(loggerName, loggerConfig) : null; + } + + private Map getAllLoggers() { + Map loggers = new LinkedHashMap<>(); + for (Logger logger : getLoggerContext().getLoggers()) { + addLogger(loggers, logger.getName()); + } + getLoggerContext().getConfiguration().getLoggers().keySet().forEach((name) -> addLogger(loggers, name)); + return loggers; + } + + private void addLogger(Map loggers, String name) { + Configuration configuration = getLoggerContext().getConfiguration(); + while (name != null) { + loggers.computeIfAbsent(name, configuration::getLoggerConfig); + name = getSubName(name); + } + } + + private String getSubName(String name) { + if (!StringUtils.hasLength(name)) { + return null; + } + int nested = name.lastIndexOf('$'); + return (nested != -1) ? name.substring(0, nested) : NameUtil.getSubName(name); + } + + private LoggerConfiguration convertLoggerConfig(String name, LoggerConfig loggerConfig) { + if (loggerConfig == null) { + return null; + } + LevelConfiguration effectiveLevelConfiguration = getLevelConfiguration(loggerConfig + .getLevel()); + if (!StringUtils.hasLength(name) || LogManager.ROOT_LOGGER_NAME.equals(name)) { + name = ROOT_LOGGER_NAME; + } + boolean isAssigned = loggerConfig.getName().equals(name); + LevelConfiguration assignedLevelConfiguration = (!isAssigned) ? null + : effectiveLevelConfiguration; + return new LoggerConfiguration(name, assignedLevelConfiguration, + effectiveLevelConfiguration); + } + + private LevelConfiguration getLevelConfiguration(Level level) { + LogLevel logLevel = LEVELS.convertNativeToSystem(level); + return (logLevel != null) ? LevelConfiguration.of(logLevel) : LevelConfiguration + .ofCustom(level.name()); + } + + @Override + public Runnable getShutdownHandler() { + return () -> getLoggerContext().stop(); + } + + @Override + public void cleanUp() { + super.cleanUp(); + LoggerContext loggerContext = getLoggerContext(); + markAsUninitialized(loggerContext); + loggerContext.getConfiguration().removeFilter(FILTER); + } + + private LoggerConfig getLogger(String name) { + boolean isRootLogger = !StringUtils.hasLength(name) || ROOT_LOGGER_NAME.equals(name); + return findLogger(isRootLogger ? LogManager.ROOT_LOGGER_NAME : name); + } + + private LoggerConfig findLogger(String name) { + Configuration configuration = getLoggerContext().getConfiguration(); + if (configuration instanceof AbstractConfiguration) { + return ((AbstractConfiguration) configuration).getLogger(name); + } + return configuration.getLoggers().get(name); + } + + private LoggerContext getLoggerContext() { + return (LoggerContext) LogManager.getContext( + Thread.currentThread().getContextClassLoader(), false); + } + + private boolean isAlreadyInitialized(LoggerContext loggerContext) { + return LoggingSystem.class.getName().equals(loggerContext.getExternalContext()); + } + + private void markAsInitialized(LoggerContext loggerContext) { + loggerContext.setExternalContext(LoggingSystem.class.getName()); + } + + private void markAsUninitialized(LoggerContext loggerContext) { + loggerContext.setExternalContext(null); + } + + /** + * {@link LoggingSystemFactory} that returns {@link Log4J2LoggingSystem} if possible. + */ + @Order(Ordered.LOWEST_PRECEDENCE) + public static class Factory implements LoggingSystemFactory { + + private static final boolean PRESENT = ClassUtils + .isPresent( + "org.apache.logging.log4j.core.impl.Log4jContextFactory", + Factory.class.getClassLoader()); + + @Override + public LoggingSystem getLoggingSystem(ClassLoader classLoader) { + if (PRESENT) { + return new Log4J2LoggingSystem(classLoader); + } + return null; + } + + } + + /** + * {@link LoggerConfig} used when the user has set a specific {@link Level}. + */ + private static class LevelSetLoggerConfig extends LoggerConfig { + + LevelSetLoggerConfig(String name, Level level, boolean additive) { + super(name, level, additive); + } + + } + +} diff --git a/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/util/OSUtilsTest.java b/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/util/OSUtilsTest.java index 470226abf..a0e60a24e 100644 --- a/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/util/OSUtilsTest.java +++ b/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/util/OSUtilsTest.java @@ -18,7 +18,6 @@ import org.junit.Assert; import org.junit.Test; - /** * @author CodeNoobKing * @data 2024/1/22 @@ -40,6 +39,5 @@ public void testGetLocalFileProtocolPrefix() { } finally { OSUtils.OS_NAME_KEY = "os.name"; } - } }