From ad0782b41868fbc70807c165e6666b6b32c8f42c Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Tue, 28 Nov 2023 16:34:13 +0800 Subject: [PATCH 01/11] ServiceProxyFactory check biz state --- .../common/service/ServiceProxyFactory.java | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java index 2ff7375ec..417707c70 100644 --- a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java +++ b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java @@ -48,38 +48,26 @@ public class ServiceProxyFactory { public static T createServiceProxy(Biz biz, String name, Class serviceType, ClassLoader clientClassLoader) { T service = getService(biz, name); - return (T) doCreateServiceProxy(biz, service, serviceType, clientClassLoader); + return doCreateServiceProxy(biz, service, serviceType, clientClassLoader); } public static T createServiceProxy(Biz biz, Class serviceType, ClassLoader clientClassLoader) { - Class serviceClass; - try { - serviceClass = biz.getBizClassLoader().loadClass(serviceType.getName()); - } catch (ClassNotFoundException e) { - throw new BizRuntimeException(E100005, "Cannot find class " + serviceType.getName() - + " from the biz " + biz.getIdentity()); - } + Class serviceClass = checkBizStateAndGetTargetClass(biz, serviceType); T service = (T) getService(biz, serviceClass); - return (T) doCreateServiceProxy(biz, service, serviceType, clientClassLoader); + return doCreateServiceProxy(biz, service, serviceType, clientClassLoader); } public static Map batchCreateServiceProxy(Biz biz, Class serviceType, ClassLoader clientClassLoader) { - Class serviceClass; - try { - serviceClass = biz.getBizClassLoader().loadClass(serviceType.getName()); - } catch (ClassNotFoundException e) { - throw new BizRuntimeException(E100005, "Cannot find class " + serviceType.getName() - + " from the biz " + biz.getIdentity()); - } + Class serviceClass = checkBizStateAndGetTargetClass(biz, serviceType); Map serviceMap = listService(biz, serviceClass); Map proxyMap = new HashMap<>(); for (String beanName : serviceMap.keySet()) { proxyMap.put( beanName, - (T) doCreateServiceProxy(biz, serviceMap.get(beanName), serviceType, - clientClassLoader)); + doCreateServiceProxy(biz, serviceMap.get(beanName), serviceType, + clientClassLoader)); } return proxyMap; } @@ -105,23 +93,6 @@ private static Map listService(Biz biz, Class serviceType) { return new HashMap<>(); } - private static BizRuntimeContext checkBizStateAndGetBizRuntimeContext(Biz biz) { - if (biz == null) { - throw new BizRuntimeException(E100003, "biz is null"); - } - if (biz.getBizState() != BizState.ACTIVATED && biz.getBizState() != BizState.DEACTIVATED) { - throw new BizRuntimeException(E100004, "biz state is not valid"); - } - BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry.getBizRuntimeContext(biz); - if (bizRuntimeContext == null) { - throw new BizRuntimeException(E100002, "biz runtime context is null"); - } - if (bizRuntimeContext.getRootApplicationContext() == null) { - throw new BizRuntimeException(E100002, "biz spring context is null"); - } - return bizRuntimeContext; - } - /** * @param biz 目标biz * @param service 目标biz中符合条件的bean @@ -173,4 +144,35 @@ public static Biz determineMostSuitableBiz(String moduleName, String moduleVersi } return biz; } + + private static Class checkBizStateAndGetTargetClass(Biz biz, Class sourceClass) { + checkBizState(biz); + try { + return biz.getBizClassLoader().loadClass(sourceClass.getName()); + } catch (ClassNotFoundException e) { + throw new BizRuntimeException(E100005, "Cannot find class " + sourceClass.getName() + + " from the biz " + biz.getIdentity()); + } + } + + private static BizRuntimeContext checkBizStateAndGetBizRuntimeContext(Biz biz) { + checkBizState(biz); + BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry.getBizRuntimeContext(biz); + if (bizRuntimeContext == null) { + throw new BizRuntimeException(E100002, "biz runtime context is null"); + } + if (bizRuntimeContext.getRootApplicationContext() == null) { + throw new BizRuntimeException(E100002, "biz spring context is null"); + } + return bizRuntimeContext; + } + + private static void checkBizState(Biz biz) { + if (biz == null) { + throw new BizRuntimeException(E100003, "biz does not exist"); + } + if (biz.getBizState() != BizState.ACTIVATED && biz.getBizState() != BizState.DEACTIVATED) { + throw new BizRuntimeException(E100004, "biz state is not valid"); + } + } } From 29ec7b1ef1aa81cdb446068665f2a3c4eaa2a75e Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Tue, 28 Nov 2023 16:37:02 +0800 Subject: [PATCH 02/11] Temporarily adjust getCallerClass depth --- .../sofa/serverless/common/service/ServiceProxyFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java index 417707c70..09113c27d 100644 --- a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java +++ b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java @@ -102,7 +102,7 @@ private static Map listService(Biz biz, Class serviceType) { */ private static T doCreateServiceProxy(Biz biz, Object service, Class serviceType, ClassLoader clientClassLoader) { if (clientClassLoader == null) { - Class callerClass = ReflectionUtils.getCallerClass(5); + Class callerClass = ReflectionUtils.getCallerClass(6); clientClassLoader = callerClass.getClassLoader(); } From 52a6fda75c90c4bf0ba351da708f8472b253ddc4 Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Thu, 30 Nov 2023 16:37:06 +0800 Subject: [PATCH 03/11] add docs runtime-service-route.md --- .../docs/tutorials/module-development/runtime-service-route.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/content/zh-cn/docs/tutorials/module-development/runtime-service-route.md diff --git a/docs/content/zh-cn/docs/tutorials/module-development/runtime-service-route.md b/docs/content/zh-cn/docs/tutorials/module-development/runtime-service-route.md new file mode 100644 index 000000000..e69de29bb From fd4edd9a649f7de8c7e90e8db50a5681f991aff2 Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Tue, 5 Dec 2023 15:18:52 +0800 Subject: [PATCH 04/11] add docs for SOFAServerlessLog4j2SpringContextListener --- .../log4j2/SOFAServerlessLog4j2SpringContextListener.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/com/alipay/sofa/serverless/log4j2/SOFAServerlessLog4j2SpringContextListener.java b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/com/alipay/sofa/serverless/log4j2/SOFAServerlessLog4j2SpringContextListener.java index 0308b6850..231b32cf7 100644 --- a/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/com/alipay/sofa/serverless/log4j2/SOFAServerlessLog4j2SpringContextListener.java +++ b/sofa-serverless-runtime/sofa-serverless-adapter-ext/sofa-serverless-adapter-log4j2/src/main/java/com/alipay/sofa/serverless/log4j2/SOFAServerlessLog4j2SpringContextListener.java @@ -37,6 +37,8 @@ /** * 支持将配置转换为 log4j2 context. + * 1. 设置LoggingSystem=SOFAServerlessLog4j2LoggingSystem + * 2. 添加属性到log4j2 ThreadContext * * @author ruoshan * @version $Id: AlipayLog4j2SpringContextListener.java, v 0.1 2018年08月23日 10:32 PM ruoshan Exp $ From 13739aaa4f714f4898420405740cdb1546eb2604 Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Tue, 5 Dec 2023 16:31:23 +0800 Subject: [PATCH 05/11] Module reuse base data source --- .../springboot-samples/db/mybatis/README.md | 73 ++++++++++++++++++- .../db/mybatis/biz1/pom.xml | 18 +++-- .../com/alipay/sofa/biz1/Biz1Application.java | 2 +- .../com/alipay/sofa/biz1/MybatisConfig.java | 58 +++++++++++++++ .../src/main/resources/application.properties | 38 +++++----- 5 files changed, 162 insertions(+), 27 deletions(-) create mode 100644 samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java diff --git a/samples/springboot-samples/db/mybatis/README.md b/samples/springboot-samples/db/mybatis/README.md index 24c888007..6b7b6c575 100644 --- a/samples/springboot-samples/db/mybatis/README.md +++ b/samples/springboot-samples/db/mybatis/README.md @@ -116,7 +116,7 @@ biz 包含两个模块,分别为 biz1 和 biz2, 都是普通 springboot,修 注意这里将不同 biz 的web context path 修改成不同的值,以此才能成功在一个 tomcat host 里安装多个 web 应用。 -## 实验步骤 +## 基座、模块各自定义数据源 ### 本地部署 mysql 并启动 @@ -191,6 +191,77 @@ curl http://localhost:8080/biz1mybatis/testmybatis ``` 返回 student 表中的内容,且可以发现使用的数据源已经变为 DruidDataSource +## 模块复用基座数据源 + +### 修改模块配置 + +在上一节「基座、模块各自定义数据源」的基础上 + +1. 移除模块数据源配置,在biz的application.properties文件中注释掉数据源datasource相关配置项 +```properties +#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +#spring.datasource.username=root +#spring.datasource.password=Zfj1995! +#spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false +# +#mybatis.mapper-locations=classpath:mappers/*.xml +# +#spring.datasource.type=com.alibaba.druid.pool.DruidDataSource +#spring.datasource.druid.initial-size=5 +#spring.datasource.druid.min-idle=5 +#spring.datasource.druid.max-active=200 +#spring.datasource.druid.max-wait=60000 +#spring.datasource.druid.time-between-eviction-runs-millis=60000 +#spring.datasource.druid.min-evictable-idle-time-millis=300000 +#spring.datasource.druid.test-while-idle=true +#spring.datasource.druid.test-on-borrow=false +#spring.datasource.druid.test-on-return=false +#spring.datasource.druid.pool-prepared-statements=false +#spring.datasource.druid.filters=stat,wall,slf4j +``` + +2. 添加模块MybatisConfig +```java +@Configuration +@MapperScan(basePackages = "com.alipay.sofa.biz1.mapper", sqlSessionFactoryRef = "mysqlSqlFactory") +@EnableTransactionManagement +public class MybatisConfig { + + //tips:不要初始化一个基座的DataSource,当模块被卸载的是,基座数据源会被销毁,transactionManager,transactionTemplate,mysqlSqlFactory被销毁没有问题 + + @Bean(name = "transactionManager") + public PlatformTransactionManager platformTransactionManager() { + return (PlatformTransactionManager) getBaseBean("transactionManager"); + } + + @Bean(name = "transactionTemplate") + public TransactionTemplate transactionTemplate() { + return (TransactionTemplate) getBaseBean("transactionTemplate"); + } + + @Bean(name = "mysqlSqlFactory") + public SqlSessionFactoryBean mysqlSqlFactory() throws IOException { + //数据源不能申明成模块spring上下文中的bean,因为模块卸载时会触发close方法 + + DataSource dataSource = (DataSource) getBaseBean("dataSource"); + SqlSessionFactoryBean mysqlSqlFactory = new SqlSessionFactoryBean(); + mysqlSqlFactory.setDataSource(dataSource); + mysqlSqlFactory.setMapperLocations(new PathMatchingResourcePatternResolver() + .getResources("classpath:mappers/*.xml")); + return mysqlSqlFactory; + } + + private Object getBaseBean(String name) { + Biz masterBiz = ArkClient.getMasterBiz(); + BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry.getBizRuntimeContext(masterBiz); + return bizRuntimeContext.getRootApplicationContext().getBean(name); + } +} +``` + +同上一节「基座、模块各自定义数据源」启动基座、部署模块、发起验证即可。 + + ## 注意事项 这里主要使用简单应用做验证,如果复杂应用,需要注意模块做好瘦身,基座有的依赖,模块尽可能设置成 provided,尽可能使用基座的依赖。 diff --git a/samples/springboot-samples/db/mybatis/biz1/pom.xml b/samples/springboot-samples/db/mybatis/biz1/pom.xml index 4d6181379..65c967eac 100644 --- a/samples/springboot-samples/db/mybatis/biz1/pom.xml +++ b/samples/springboot-samples/db/mybatis/biz1/pom.xml @@ -54,12 +54,12 @@ test - - - - - - + + com.alipay.sofa.serverless + sofa-serverless-app-starter + ${sofa.serverless.runtime.version} + provided + @@ -71,6 +71,12 @@ ${sofa.serverless.runtime.version} provided + + com.alipay.sofa + sofa-ark-api + ${sofa.ark.version} + provided + diff --git a/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/Biz1Application.java b/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/Biz1Application.java index 2963847b4..91b1cdbc5 100644 --- a/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/Biz1Application.java +++ b/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/Biz1Application.java @@ -9,7 +9,7 @@ import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication -@MapperScan(basePackages = "com.alipay.sofa.biz1.mapper") +//@MapperScan(basePackages = "com.alipay.sofa.biz1.mapper") public class Biz1Application { private static Logger LOGGER = LoggerFactory.getLogger(Biz1Application.class); diff --git a/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java b/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java new file mode 100644 index 000000000..6e3f2f974 --- /dev/null +++ b/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java @@ -0,0 +1,58 @@ +package com.alipay.sofa.biz1; + +import com.alipay.sofa.ark.api.ArkClient; +import com.alipay.sofa.ark.spi.model.Biz; +import com.alipay.sofa.serverless.common.BizRuntimeContext; +import com.alipay.sofa.serverless.common.BizRuntimeContextRegistry; +import org.mybatis.spring.SqlSessionFactoryBean; +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.transaction.support.TransactionTemplate; + +import javax.sql.DataSource; +import java.io.IOException; + +/** + * @author: yuanyuan + * @date: 2023/12/5 3:37 下午 + * 模块复用基座 transactionManager、transactionTemplate、以及 dataSource + */ +@Configuration +@MapperScan(basePackages = "com.alipay.sofa.biz1.mapper", sqlSessionFactoryRef = "mysqlSqlFactory") +@EnableTransactionManagement +public class MybatisConfig { + + //tips:不要初始化一个基座的DataSource,当模块被卸载的是,基座数据源会被销毁,transactionManager,transactionTemplate,mysqlSqlFactory被销毁没有问题 + + @Bean(name = "transactionManager") + public PlatformTransactionManager platformTransactionManager() { + return (PlatformTransactionManager) getBaseBean("transactionManager"); + } + + @Bean(name = "transactionTemplate") + public TransactionTemplate transactionTemplate() { + return (TransactionTemplate) getBaseBean("transactionTemplate"); + } + + @Bean(name = "mysqlSqlFactory") + public SqlSessionFactoryBean mysqlSqlFactory() throws IOException { + //数据源不能申明成模块spring上下文中的bean,因为模块卸载时会触发close方法 + + DataSource dataSource = (DataSource) getBaseBean("dataSource"); + SqlSessionFactoryBean mysqlSqlFactory = new SqlSessionFactoryBean(); + mysqlSqlFactory.setDataSource(dataSource); + mysqlSqlFactory.setMapperLocations(new PathMatchingResourcePatternResolver() + .getResources("classpath:mappers/*.xml")); + return mysqlSqlFactory; + } + + private Object getBaseBean(String name) { + Biz masterBiz = ArkClient.getMasterBiz(); + BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry.getBizRuntimeContext(masterBiz); + return bizRuntimeContext.getRootApplicationContext().getBean(name); + } +} diff --git a/samples/springboot-samples/db/mybatis/biz1/src/main/resources/application.properties b/samples/springboot-samples/db/mybatis/biz1/src/main/resources/application.properties index bb2f1e25a..65b610b4e 100644 --- a/samples/springboot-samples/db/mybatis/biz1/src/main/resources/application.properties +++ b/samples/springboot-samples/db/mybatis/biz1/src/main/resources/application.properties @@ -6,22 +6,22 @@ logging.level.root=INFO logging.level.com.alipay.sofa.arklet=INFO 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.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false - -mybatis.mapper-locations=classpath:mappers/*.xml - -spring.datasource.type=com.alibaba.druid.pool.DruidDataSource -spring.datasource.druid.initial-size=5 -spring.datasource.druid.min-idle=5 -spring.datasource.druid.max-active=200 -spring.datasource.druid.max-wait=60000 -spring.datasource.druid.time-between-eviction-runs-millis=60000 -spring.datasource.druid.min-evictable-idle-time-millis=300000 -spring.datasource.druid.test-while-idle=true -spring.datasource.druid.test-on-borrow=false -spring.datasource.druid.test-on-return=false -spring.datasource.druid.pool-prepared-statements=false -spring.datasource.druid.filters=stat,wall,slf4j \ No newline at end of file +#spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver +#spring.datasource.username=root +#spring.datasource.password=Zfj1995! +#spring.datasource.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false +# +#mybatis.mapper-locations=classpath:mappers/*.xml +# +#spring.datasource.type=com.alibaba.druid.pool.DruidDataSource +#spring.datasource.druid.initial-size=5 +#spring.datasource.druid.min-idle=5 +#spring.datasource.druid.max-active=200 +#spring.datasource.druid.max-wait=60000 +#spring.datasource.druid.time-between-eviction-runs-millis=60000 +#spring.datasource.druid.min-evictable-idle-time-millis=300000 +#spring.datasource.druid.test-while-idle=true +#spring.datasource.druid.test-on-borrow=false +#spring.datasource.druid.test-on-return=false +#spring.datasource.druid.pool-prepared-statements=false +#spring.datasource.druid.filters=stat,wall,slf4j \ No newline at end of file From 73dd076b857274fea2d9efe452ebe1b504cb9b4e Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Wed, 6 Dec 2023 11:02:10 +0800 Subject: [PATCH 06/11] format --- .../serverless/common/service/ServiceProxyFactory.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java index 09113c27d..f317390d1 100644 --- a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java +++ b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/service/ServiceProxyFactory.java @@ -64,8 +64,9 @@ public static Map batchCreateServiceProxy(Biz biz, Class servi Map serviceMap = listService(biz, serviceClass); Map proxyMap = new HashMap<>(); for (String beanName : serviceMap.keySet()) { - proxyMap.put( - beanName, + proxyMap + .put( + beanName, doCreateServiceProxy(biz, serviceMap.get(beanName), serviceType, clientClassLoader)); } @@ -151,7 +152,7 @@ private static Class checkBizStateAndGetTargetClass(Biz biz, Class sourceC return biz.getBizClassLoader().loadClass(sourceClass.getName()); } catch (ClassNotFoundException e) { throw new BizRuntimeException(E100005, "Cannot find class " + sourceClass.getName() - + " from the biz " + biz.getIdentity()); + + " from the biz " + biz.getIdentity()); } } From e8ffc2eeeb6b2878446a3c39d33ee4ee31ef8a6b Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Fri, 8 Dec 2023 17:32:15 +0800 Subject: [PATCH 07/11] add SpringBeanFinder --- .../db/mybatis/biz1/pom.xml | 11 ----- .../com/alipay/sofa/biz1/MybatisConfig.java | 11 +---- .../common/api/SpringBeanFinder.java | 43 +++++++++++++++++++ 3 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/api/SpringBeanFinder.java diff --git a/samples/springboot-samples/db/mybatis/biz1/pom.xml b/samples/springboot-samples/db/mybatis/biz1/pom.xml index 65c967eac..ce833c432 100644 --- a/samples/springboot-samples/db/mybatis/biz1/pom.xml +++ b/samples/springboot-samples/db/mybatis/biz1/pom.xml @@ -60,11 +60,6 @@ ${sofa.serverless.runtime.version} provided - - - - - com.alipay.sofa.serverless sofa-serverless-adapter-log4j2 @@ -77,12 +72,6 @@ ${sofa.ark.version} provided - - - - - - diff --git a/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java b/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java index 6e3f2f974..ce45dbe8a 100644 --- a/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java +++ b/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java @@ -1,9 +1,5 @@ package com.alipay.sofa.biz1; -import com.alipay.sofa.ark.api.ArkClient; -import com.alipay.sofa.ark.spi.model.Biz; -import com.alipay.sofa.serverless.common.BizRuntimeContext; -import com.alipay.sofa.serverless.common.BizRuntimeContextRegistry; import org.mybatis.spring.SqlSessionFactoryBean; import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Bean; @@ -16,6 +12,8 @@ import javax.sql.DataSource; import java.io.IOException; +import static com.alipay.sofa.serverless.common.api.SpringBeanFinder.getBaseBean; + /** * @author: yuanyuan * @date: 2023/12/5 3:37 下午 @@ -50,9 +48,4 @@ public SqlSessionFactoryBean mysqlSqlFactory() throws IOException { return mysqlSqlFactory; } - private Object getBaseBean(String name) { - Biz masterBiz = ArkClient.getMasterBiz(); - BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry.getBizRuntimeContext(masterBiz); - return bizRuntimeContext.getRootApplicationContext().getBean(name); - } } diff --git a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/api/SpringBeanFinder.java b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/api/SpringBeanFinder.java new file mode 100644 index 000000000..e72694d62 --- /dev/null +++ b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/api/SpringBeanFinder.java @@ -0,0 +1,43 @@ +/* + * 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.common.api; + +import com.alipay.sofa.ark.api.ArkClient; +import com.alipay.sofa.ark.spi.model.Biz; +import com.alipay.sofa.serverless.common.BizRuntimeContext; +import com.alipay.sofa.serverless.common.BizRuntimeContextRegistry; + +/** + * @author: yuanyuan + * @date: 2023/12/8 5:26 下午 + */ +public class SpringBeanFinder { + + public static Object getBaseBean(String name) { + Biz masterBiz = ArkClient.getMasterBiz(); + BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry + .getBizRuntimeContext(masterBiz); + return bizRuntimeContext.getRootApplicationContext().getBean(name); + } + + public static T getBaseBean(Class type) { + Biz masterBiz = ArkClient.getMasterBiz(); + BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry + .getBizRuntimeContext(masterBiz); + return bizRuntimeContext.getRootApplicationContext().getBean(type); + } +} From 6059267eb3632e66490946a4cc9c5a5996d58a25 Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Fri, 8 Dec 2023 18:12:07 +0800 Subject: [PATCH 08/11] add SpringBeanFinder --- .../com/alipay/sofa/serverless/common/api/SpringBeanFinder.java | 2 ++ .../alipay/sofa/serverless/common/SpringServiceFinderTest.java | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/api/SpringBeanFinder.java b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/api/SpringBeanFinder.java index e72694d62..0b34ff151 100644 --- a/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/api/SpringBeanFinder.java +++ b/sofa-serverless-runtime/sofa-serverless-common/src/main/java/com/alipay/sofa/serverless/common/api/SpringBeanFinder.java @@ -24,6 +24,8 @@ /** * @author: yuanyuan * @date: 2023/12/8 5:26 下午 + * + * SpringBeanFinder 查找基座bean工具类,无跨classloader支持 */ public class SpringBeanFinder { diff --git a/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceFinderTest.java b/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceFinderTest.java index 77f619448..9a2791847 100644 --- a/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceFinderTest.java +++ b/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceFinderTest.java @@ -37,7 +37,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.util.ReflectionUtils; -import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.List; From 3dd5fe60429c8620779c3d9f1f7c739c15980283 Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Fri, 8 Dec 2023 18:15:51 +0800 Subject: [PATCH 09/11] fix readme --- samples/springboot-samples/db/mybatis/README.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/samples/springboot-samples/db/mybatis/README.md b/samples/springboot-samples/db/mybatis/README.md index 93d907e79..7b8e40c98 100644 --- a/samples/springboot-samples/db/mybatis/README.md +++ b/samples/springboot-samples/db/mybatis/README.md @@ -259,12 +259,6 @@ public class MybatisConfig { .getResources("classpath:mappers/*.xml")); return mysqlSqlFactory; } - - private Object getBaseBean(String name) { - Biz masterBiz = ArkClient.getMasterBiz(); - BizRuntimeContext bizRuntimeContext = BizRuntimeContextRegistry.getBizRuntimeContext(masterBiz); - return bizRuntimeContext.getRootApplicationContext().getBean(name); - } } ``` From 6c47670a9256539e2c97ee82fa271fbe64e7c9d6 Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Fri, 8 Dec 2023 18:21:46 +0800 Subject: [PATCH 10/11] adjust reuse-base-datasource.md --- .../reuse-base-datasource.md | 19 +++++++++++-------- .../com/alipay/sofa/biz1/MybatisConfig.java | 1 - 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/docs/content/zh-cn/docs/tutorials/module-development/reuse-base-datasource.md b/docs/content/zh-cn/docs/tutorials/module-development/reuse-base-datasource.md index 581248d66..f6d5acabb 100644 --- a/docs/content/zh-cn/docs/tutorials/module-development/reuse-base-datasource.md +++ b/docs/content/zh-cn/docs/tutorials/module-development/reuse-base-datasource.md @@ -7,35 +7,38 @@ weight: 600 强烈建议使用本文档方式,在模块中尽可能**复用基座数据源**,否则模块反复部署就会反复创建、消耗数据源连接,导致模块发布运维会变慢,同时也会额外消耗内存。
## SpringBoot 解法 -在模块的代码中写个 MybatisConfig 类即可,这样事务模板都是复用基座的,只有 Mybatis 的 SqlSessionFactoryBean 需要新创建。
通过`BaseAppUtils.getBean`获取到基座的 Bean 对象,然后注册成模块的 Bean: +在模块的代码中写个 MybatisConfig 类即可,这样事务模板都是复用基座的,只有 Mybatis 的 SqlSessionFactoryBean 需要新创建。
参考 demo:/sofa-serverless/samples/springboot-samples/db/mybatis/biz1 + +通过`SpringBeanFinder.getBaseBean`获取到基座的 Bean 对象,然后注册成模块的 Bean: + ```java @Configuration -@MapperScan(basePackages = "com.alipay.serverless.dal.dao", sqlSessionFactoryRef = "mysqlSqlFactory") +@MapperScan(basePackages = "com.alipay.sofa.biz1.mapper", sqlSessionFactoryRef = "mysqlSqlFactory") @EnableTransactionManagement public class MybatisConfig { - // 注意:不要初始化一个基座的 DataSource,会导致模块被热卸载的时候,基座的数据源被销毁,不符合预期。 - // 但是 transactionManager,transactionTemplate,mysqlSqlFactory 这些资源被销毁没有问题 + //tips:不要初始化一个基座的DataSource,当模块被卸载的是,基座数据源会被销毁,transactionManager,transactionTemplate,mysqlSqlFactory被销毁没有问题 @Bean(name = "transactionManager") public PlatformTransactionManager platformTransactionManager() { - return (PlatformTransactionManager) BaseAppUtils.getBean("transactionManager"); + return (PlatformTransactionManager) getBaseBean("transactionManager"); } @Bean(name = "transactionTemplate") public TransactionTemplate transactionTemplate() { - return (TransactionTemplate) BaseAppUtils.getBean("transactionTemplate"); + return (TransactionTemplate) getBaseBean("transactionTemplate"); } @Bean(name = "mysqlSqlFactory") public SqlSessionFactoryBean mysqlSqlFactory() throws IOException { //数据源不能申明成模块spring上下文中的bean,因为模块卸载时会触发close方法 - ZdalDataSource dataSource = (ZdalDataSource) BaseAppUtils.getBean("dataSource"); + + DataSource dataSource = (DataSource) getBaseBean("dataSource"); SqlSessionFactoryBean mysqlSqlFactory = new SqlSessionFactoryBean(); mysqlSqlFactory.setDataSource(dataSource); mysqlSqlFactory.setMapperLocations(new PathMatchingResourcePatternResolver() - .getResources("classpath:mapper/*.xml")); + .getResources("classpath:mappers/*.xml")); return mysqlSqlFactory; } } diff --git a/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java b/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java index ce45dbe8a..368ebdf80 100644 --- a/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java +++ b/samples/springboot-samples/db/mybatis/biz1/src/main/java/com/alipay/sofa/biz1/MybatisConfig.java @@ -47,5 +47,4 @@ public SqlSessionFactoryBean mysqlSqlFactory() throws IOException { .getResources("classpath:mappers/*.xml")); return mysqlSqlFactory; } - } From f660a686511d5e410d51a7d9f5241ec3249fe21d Mon Sep 17 00:00:00 2001 From: yuanyuan Date: Mon, 11 Dec 2023 12:17:38 +0800 Subject: [PATCH 11/11] add SpringBeanFinder ut --- ...t.java => SpringServiceAndBeanFinderTest.java} | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) rename sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/{SpringServiceFinderTest.java => SpringServiceAndBeanFinderTest.java} (94%) diff --git a/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceFinderTest.java b/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceAndBeanFinderTest.java similarity index 94% rename from sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceFinderTest.java rename to sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceAndBeanFinderTest.java index 9a2791847..353800694 100644 --- a/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceFinderTest.java +++ b/sofa-serverless-runtime/sofa-serverless-common/src/test/java/com/alipay/sofa/serverless/common/SpringServiceAndBeanFinderTest.java @@ -22,6 +22,7 @@ import com.alipay.sofa.ark.spi.service.biz.BizManagerService; import com.alipay.sofa.serverless.common.api.AutowiredFromBase; import com.alipay.sofa.serverless.common.api.AutowiredFromBiz; +import com.alipay.sofa.serverless.common.api.SpringBeanFinder; import com.alipay.sofa.serverless.common.api.SpringServiceFinder; import com.alipay.sofa.serverless.common.service.ArkAutowiredBeanPostProcessor; import org.junit.Assert; @@ -52,7 +53,7 @@ * @date: 2023/9/26 9:40 下午 */ @RunWith(MockitoJUnitRunner.class) -public class SpringServiceFinderTest { +public class SpringServiceAndBeanFinderTest { @Mock private Biz masterBiz; @@ -119,12 +120,12 @@ public void testSpringServiceFinder() { // test to invoke crossing classloader - URL url = SpringServiceFinderTest.class.getClassLoader().getResource(""); + URL url = SpringServiceAndBeanFinderTest.class.getClassLoader().getResource(""); URLClassLoader loader = new URLClassLoader(new URL[] { url }, null); Object newModuleBean = null; try { Class aClass = loader - .loadClass("com.alipay.sofa.serverless.common.SpringServiceFinderTest$ModuleBean"); + .loadClass("com.alipay.sofa.serverless.common.SpringServiceAndBeanFinderTest$ModuleBean"); newModuleBean = aClass.newInstance(); } catch (Exception e) { System.out.println(e); @@ -171,6 +172,14 @@ public void testArkAutowired() { testBean)); } + @Test + public void testGetBaseBean() { + Object baseBean = SpringBeanFinder.getBaseBean("baseBean"); + BaseBean baseBean1 = SpringBeanFinder.getBaseBean(BaseBean.class); + Assert.assertNotNull(baseBean); + Assert.assertNotNull(baseBean1); + } + public ConfigurableApplicationContext buildApplicationContext(String appName) { Properties properties = new Properties(); properties.setProperty("spring.application.name", appName);