From 675144b0d5535ff6940ec62a880147921eb09964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?WangLiang/=E7=8E=8B=E8=89=AF?= <841369634@qq.com> Date: Thu, 30 Jul 2020 17:35:57 +0800 Subject: [PATCH] feature: The data source proxy mode can be selected as AT or XA (#2913) --- .../core/constants/ConfigurationKeys.java | 5 ++++ .../seata/core/constants/DefaultValues.java | 2 ++ .../io/seata/core/context/RootContext.java | 10 ++++++-- script/client/spring/application.properties | 1 + script/client/spring/application.yml | 1 + .../autoconfigure/SeataAutoConfiguration.java | 3 ++- .../properties/SeataProperties.java | 13 ++++++++++ ...itional-spring-configuration-metadata.json | 25 +++++++++++++++++++ .../boot/autoconfigure/PropertiesTest.java | 1 + .../AutoDataSourceProxyRegistrar.java | 12 +++++++-- .../datasource/DataSourceProxyHolder.java | 14 +++++++---- .../datasource/EnableAutoDataSourceProxy.java | 9 ++++++- .../SeataAutoDataSourceProxyAdvice.java | 15 +++++++++-- .../SeataAutoDataSourceProxyCreator.java | 5 ++-- 14 files changed, 101 insertions(+), 15 deletions(-) create mode 100644 seata-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json diff --git a/core/src/main/java/io/seata/core/constants/ConfigurationKeys.java b/core/src/main/java/io/seata/core/constants/ConfigurationKeys.java index 6f70f573061..aa3b259bcaa 100644 --- a/core/src/main/java/io/seata/core/constants/ConfigurationKeys.java +++ b/core/src/main/java/io/seata/core/constants/ConfigurationKeys.java @@ -508,4 +508,9 @@ public class ConfigurationKeys { * The constant TX_SERVICE_GROUP. */ public static final String TX_SERVICE_GROUP = "txServiceGroup"; + + /** + * The constant DATA_SOURCE_PROXY_MODE. + */ + public static final String DATA_SOURCE_PROXY_MODE = "dataSourceProxyMode"; } diff --git a/core/src/main/java/io/seata/core/constants/DefaultValues.java b/core/src/main/java/io/seata/core/constants/DefaultValues.java index d7225934bbb..0a04638f90a 100644 --- a/core/src/main/java/io/seata/core/constants/DefaultValues.java +++ b/core/src/main/java/io/seata/core/constants/DefaultValues.java @@ -80,6 +80,8 @@ public class DefaultValues { public static final String DEFAULT_TC_CLUSTER = "default"; public static final String DEFAULT_GROUPLIST = "127.0.0.1:8091"; + public static final String DEFAULT_DATA_SOURCE_PROXY_MODE = "AT"; + public static final boolean DEFAULT_DISABLE_GLOBAL_TRANSACTION = false; public static final int SERVER_DEFAULT_PORT = 8091; diff --git a/core/src/main/java/io/seata/core/context/RootContext.java b/core/src/main/java/io/seata/core/context/RootContext.java index 3c597b32284..a1e0b9e1ef1 100644 --- a/core/src/main/java/io/seata/core/context/RootContext.java +++ b/core/src/main/java/io/seata/core/context/RootContext.java @@ -19,6 +19,9 @@ import io.seata.common.exception.ShouldNeverHappenException; import io.seata.common.util.StringUtils; +import io.seata.config.ConfigurationFactory; +import io.seata.core.constants.ConfigurationKeys; +import io.seata.core.constants.DefaultValues; import io.seata.core.model.BranchType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,6 +54,9 @@ private RootContext() { private static ContextCore CONTEXT_HOLDER = ContextCoreLoader.load(); + private static final String DATA_SOURCE_PROXY_MODE = ConfigurationFactory.getInstance() + .getConfig(ConfigurationKeys.DATA_SOURCE_PROXY_MODE, DefaultValues.DEFAULT_DATA_SOURCE_PROXY_MODE); + /** * Gets xid. * @@ -129,8 +135,8 @@ public static String getBranchType() { if (StringUtils.isNotBlank(branchType)) { return branchType; } - //default branchType is AT - return BranchType.AT.name(); + //default branchType is the dataSourceProxyMode + return BranchType.XA.name().equalsIgnoreCase(DATA_SOURCE_PROXY_MODE) ? BranchType.XA.name() : BranchType.AT.name(); } return null; } diff --git a/script/client/spring/application.properties b/script/client/spring/application.properties index ec51e58f046..fe0f1afe4db 100755 --- a/script/client/spring/application.properties +++ b/script/client/spring/application.properties @@ -19,6 +19,7 @@ seata.excludes-for-auto-proxying=firstClassNameForExclude,secondClassNameForExcl seata.application-id=applicationName seata.tx-service-group=my_test_tx_group seata.enable-auto-data-source-proxy=true +seata.data-source-proxy-mode=AT seata.use-jdk-proxy=false seata.client.rm.async-commit-buffer-limit=1000 seata.client.rm.report-retry-count=5 diff --git a/script/client/spring/application.yml b/script/client/spring/application.yml index a355698c6bf..dfff421b8a2 100755 --- a/script/client/spring/application.yml +++ b/script/client/spring/application.yml @@ -3,6 +3,7 @@ seata: application-id: applicationName tx-service-group: my_test_tx_group enable-auto-data-source-proxy: true + data-source-proxy-mode: AT use-jdk-proxy: false excludes-for-auto-proxying: firstClassNameForExclude,secondClassNameForExclude client: diff --git a/seata-spring-boot-starter/src/main/java/io/seata/spring/boot/autoconfigure/SeataAutoConfiguration.java b/seata-spring-boot-starter/src/main/java/io/seata/spring/boot/autoconfigure/SeataAutoConfiguration.java index 93104550b80..1e2f0f6da86 100644 --- a/seata-spring-boot-starter/src/main/java/io/seata/spring/boot/autoconfigure/SeataAutoConfiguration.java +++ b/seata-spring-boot-starter/src/main/java/io/seata/spring/boot/autoconfigure/SeataAutoConfiguration.java @@ -71,6 +71,7 @@ public GlobalTransactionScanner globalTransactionScanner(SeataProperties seataPr @ConditionalOnProperty(prefix = StarterConstants.SEATA_PREFIX, name = {"enableAutoDataSourceProxy", "enable-auto-data-source-proxy"}, havingValue = "true", matchIfMissing = true) @ConditionalOnMissingBean(SeataAutoDataSourceProxyCreator.class) public SeataAutoDataSourceProxyCreator seataAutoDataSourceProxyCreator(SeataProperties seataProperties) { - return new SeataAutoDataSourceProxyCreator(seataProperties.isUseJdkProxy(),seataProperties.getExcludesForAutoProxying()); + return new SeataAutoDataSourceProxyCreator(seataProperties.isUseJdkProxy(), + seataProperties.getExcludesForAutoProxying(), seataProperties.getDataSourceProxyMode()); } } diff --git a/seata-spring-boot-starter/src/main/java/io/seata/spring/boot/autoconfigure/properties/SeataProperties.java b/seata-spring-boot-starter/src/main/java/io/seata/spring/boot/autoconfigure/properties/SeataProperties.java index 31b56f13653..bd289947258 100644 --- a/seata-spring-boot-starter/src/main/java/io/seata/spring/boot/autoconfigure/properties/SeataProperties.java +++ b/seata-spring-boot-starter/src/main/java/io/seata/spring/boot/autoconfigure/properties/SeataProperties.java @@ -15,6 +15,7 @@ */ package io.seata.spring.boot.autoconfigure.properties; +import io.seata.core.constants.DefaultValues; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -43,6 +44,10 @@ public class SeataProperties { * Whether enable auto proxying of datasource bean */ private boolean enableAutoDataSourceProxy = true; + /** + * data source proxy mode + */ + private String dataSourceProxyMode = DefaultValues.DEFAULT_DATA_SOURCE_PROXY_MODE; /** * Whether use JDK proxy instead of CGLIB proxy */ @@ -97,6 +102,14 @@ public SeataProperties setEnableAutoDataSourceProxy(boolean enableAutoDataSource return this; } + public String getDataSourceProxyMode() { + return dataSourceProxyMode; + } + + public void setDataSourceProxyMode(String dataSourceProxyMode) { + this.dataSourceProxyMode = dataSourceProxyMode; + } + public boolean isUseJdkProxy() { return useJdkProxy; } diff --git a/seata-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/seata-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 00000000000..c00b1397c31 --- /dev/null +++ b/seata-spring-boot-starter/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,25 @@ +{ + "groups": [], + "properties": [ + { + "name": "seata.data-source-proxy-mode", + "type": "java.lang.String", + "description": "data source proxy mode.", + "sourceType": "io.seata.spring.boot.autoconfigure.properties.SeataProperties", + "defaultValue": "AT" + } + ], + "hints": [ + { + "name": "seata.data-source-proxy-mode", + "values": [ + { + "value": "AT" + }, + { + "value": "XA" + } + ] + } + ] +} \ No newline at end of file diff --git a/seata-spring-boot-starter/src/test/java/io/seata/spring/boot/autoconfigure/PropertiesTest.java b/seata-spring-boot-starter/src/test/java/io/seata/spring/boot/autoconfigure/PropertiesTest.java index 56ca556e826..010c40b29b8 100644 --- a/seata-spring-boot-starter/src/test/java/io/seata/spring/boot/autoconfigure/PropertiesTest.java +++ b/seata-spring-boot-starter/src/test/java/io/seata/spring/boot/autoconfigure/PropertiesTest.java @@ -249,6 +249,7 @@ public void testSeataProperties() { assertNull(context.getBean(SeataProperties.class).getApplicationId()); assertEquals("null-seata-service-group", context.getBean(SeataProperties.class).getTxServiceGroup()); assertTrue(context.getBean(SeataProperties.class).isEnableAutoDataSourceProxy()); + assertEquals("AT", context.getBean(SeataProperties.class).getDataSourceProxyMode()); assertFalse(context.getBean(SeataProperties.class).isUseJdkProxy()); } diff --git a/spring/src/main/java/io/seata/spring/annotation/datasource/AutoDataSourceProxyRegistrar.java b/spring/src/main/java/io/seata/spring/annotation/datasource/AutoDataSourceProxyRegistrar.java index e86b02097c4..668e5fc296c 100644 --- a/spring/src/main/java/io/seata/spring/annotation/datasource/AutoDataSourceProxyRegistrar.java +++ b/spring/src/main/java/io/seata/spring/annotation/datasource/AutoDataSourceProxyRegistrar.java @@ -21,6 +21,8 @@ import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.core.type.AnnotationMetadata; +import java.util.Map; + /** * @author xingfudeshi@gmail.com * The type auto data source proxy registrar @@ -28,17 +30,23 @@ public class AutoDataSourceProxyRegistrar implements ImportBeanDefinitionRegistrar { private static final String ATTRIBUTE_KEY_USE_JDK_PROXY = "useJdkProxy"; private static final String ATTRIBUTE_KEY_EXCLUDES = "excludes"; + private static final String ATTRIBUTE_KEY_DATA_SOURCE_PROXY_MODE = "dataSourceProxyMode"; public static final String BEAN_NAME_SEATA_AUTO_DATA_SOURCE_PROXY_CREATOR = "seataAutoDataSourceProxyCreator"; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { if (!registry.containsBeanDefinition(BEAN_NAME_SEATA_AUTO_DATA_SOURCE_PROXY_CREATOR)) { - boolean useJdkProxy = Boolean.parseBoolean(importingClassMetadata.getAnnotationAttributes(EnableAutoDataSourceProxy.class.getName()).get(ATTRIBUTE_KEY_USE_JDK_PROXY).toString()); - String[] excludes = (String[]) importingClassMetadata.getAnnotationAttributes(EnableAutoDataSourceProxy.class.getName()).get(ATTRIBUTE_KEY_EXCLUDES); + Map annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnableAutoDataSourceProxy.class.getName()); + + boolean useJdkProxy = Boolean.parseBoolean(annotationAttributes.get(ATTRIBUTE_KEY_USE_JDK_PROXY).toString()); + String[] excludes = (String[]) annotationAttributes.get(ATTRIBUTE_KEY_EXCLUDES); + String dataSourceProxyMode = (String) annotationAttributes.get(ATTRIBUTE_KEY_DATA_SOURCE_PROXY_MODE); + AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder .genericBeanDefinition(SeataAutoDataSourceProxyCreator.class) .addConstructorArgValue(useJdkProxy) .addConstructorArgValue(excludes) + .addConstructorArgValue(dataSourceProxyMode) .getBeanDefinition(); registry.registerBeanDefinition(BEAN_NAME_SEATA_AUTO_DATA_SOURCE_PROXY_CREATOR, beanDefinition); } diff --git a/spring/src/main/java/io/seata/spring/annotation/datasource/DataSourceProxyHolder.java b/spring/src/main/java/io/seata/spring/annotation/datasource/DataSourceProxyHolder.java index a59ff512e10..e76aeb756a8 100644 --- a/spring/src/main/java/io/seata/spring/annotation/datasource/DataSourceProxyHolder.java +++ b/spring/src/main/java/io/seata/spring/annotation/datasource/DataSourceProxyHolder.java @@ -18,7 +18,9 @@ import javax.sql.DataSource; import java.util.concurrent.ConcurrentHashMap; +import io.seata.core.model.BranchType; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.xa.DataSourceProxyXA; /** * the type data source proxy holder @@ -27,7 +29,7 @@ */ public class DataSourceProxyHolder { private static final int MAP_INITIAL_CAPACITY = 8; - private ConcurrentHashMap dataSourceProxyMap; + private ConcurrentHashMap dataSourceProxyMap; private DataSourceProxyHolder() { dataSourceProxyMap = new ConcurrentHashMap<>(MAP_INITIAL_CAPACITY); @@ -57,11 +59,13 @@ public static DataSourceProxyHolder get() { /** * Put dataSource * - * @param dataSource + * @param originalDataSource the original data source + * @param dataSourceProxyMode the data source proxy mode * @return dataSourceProxy */ - public DataSourceProxy putDataSource(DataSource dataSource) { - return this.dataSourceProxyMap.computeIfAbsent(dataSource, DataSourceProxy::new); + public DataSource putDataSource(DataSource originalDataSource, String dataSourceProxyMode) { + return this.dataSourceProxyMap.computeIfAbsent(originalDataSource, + BranchType.XA.name().equalsIgnoreCase(dataSourceProxyMode) ? DataSourceProxyXA::new : DataSourceProxy::new); } /** @@ -70,7 +74,7 @@ public DataSourceProxy putDataSource(DataSource dataSource) { * @param dataSource * @return dataSourceProxy */ - public DataSourceProxy getDataSourceProxy(DataSource dataSource) { + public DataSource getDataSourceProxy(DataSource dataSource) { return this.dataSourceProxyMap.get(dataSource); } diff --git a/spring/src/main/java/io/seata/spring/annotation/datasource/EnableAutoDataSourceProxy.java b/spring/src/main/java/io/seata/spring/annotation/datasource/EnableAutoDataSourceProxy.java index 280968fb38f..23b1a130bed 100644 --- a/spring/src/main/java/io/seata/spring/annotation/datasource/EnableAutoDataSourceProxy.java +++ b/spring/src/main/java/io/seata/spring/annotation/datasource/EnableAutoDataSourceProxy.java @@ -42,7 +42,14 @@ /** * Specifies which datasource bean are not eligible for auto-proxying * - * @return + * @return excludes */ String[] excludes() default {}; + + /** + * Data source proxy mode, AT or XA + * + * @return dataSourceProxyMode + */ + String dataSourceProxyMode() default "AT"; } diff --git a/spring/src/main/java/io/seata/spring/annotation/datasource/SeataAutoDataSourceProxyAdvice.java b/spring/src/main/java/io/seata/spring/annotation/datasource/SeataAutoDataSourceProxyAdvice.java index ed9ea41d36a..8169d3315fe 100644 --- a/spring/src/main/java/io/seata/spring/annotation/datasource/SeataAutoDataSourceProxyAdvice.java +++ b/spring/src/main/java/io/seata/spring/annotation/datasource/SeataAutoDataSourceProxyAdvice.java @@ -18,7 +18,9 @@ import javax.sql.DataSource; import java.lang.reflect.Method; +import io.seata.core.model.BranchType; import io.seata.rm.datasource.DataSourceProxy; +import io.seata.rm.datasource.xa.DataSourceProxyXA; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; import org.springframework.aop.IntroductionInfo; @@ -29,12 +31,21 @@ */ public class SeataAutoDataSourceProxyAdvice implements MethodInterceptor, IntroductionInfo { + private final String dataSourceProxyMode; + private final Class dataSourceProxyClazz; + + public SeataAutoDataSourceProxyAdvice(String dataSourceProxyMode) { + this.dataSourceProxyMode = dataSourceProxyMode; + this.dataSourceProxyClazz = BranchType.XA.name().equalsIgnoreCase(dataSourceProxyMode) ? + DataSourceProxyXA.class : DataSourceProxy.class; + } + @Override public Object invoke(MethodInvocation invocation) throws Throwable { - DataSourceProxy dataSourceProxy = DataSourceProxyHolder.get().putDataSource((DataSource) invocation.getThis()); + DataSource dataSourceProxy = DataSourceProxyHolder.get().putDataSource((DataSource) invocation.getThis(), dataSourceProxyMode); Method method = invocation.getMethod(); Object[] args = invocation.getArguments(); - Method m = BeanUtils.findDeclaredMethod(DataSourceProxy.class, method.getName(), method.getParameterTypes()); + Method m = BeanUtils.findDeclaredMethod(dataSourceProxyClazz, method.getName(), method.getParameterTypes()); if (m != null) { return m.invoke(dataSourceProxy, args); } else { diff --git a/spring/src/main/java/io/seata/spring/annotation/datasource/SeataAutoDataSourceProxyCreator.java b/spring/src/main/java/io/seata/spring/annotation/datasource/SeataAutoDataSourceProxyCreator.java index d30874dbbce..87c401cdc20 100644 --- a/spring/src/main/java/io/seata/spring/annotation/datasource/SeataAutoDataSourceProxyCreator.java +++ b/spring/src/main/java/io/seata/spring/annotation/datasource/SeataAutoDataSourceProxyCreator.java @@ -32,10 +32,11 @@ public class SeataAutoDataSourceProxyCreator extends AbstractAutoProxyCreator { private static final Logger LOGGER = LoggerFactory.getLogger(SeataAutoDataSourceProxyCreator.class); private final String[] excludes; - private final Advisor advisor = new DefaultIntroductionAdvisor(new SeataAutoDataSourceProxyAdvice()); + private final Advisor advisor; - public SeataAutoDataSourceProxyCreator(boolean useJdkProxy, String[] excludes) { + public SeataAutoDataSourceProxyCreator(boolean useJdkProxy, String[] excludes, String dataSourceProxyMode) { this.excludes = excludes; + this.advisor = new DefaultIntroductionAdvisor(new SeataAutoDataSourceProxyAdvice(dataSourceProxyMode)); setProxyTargetClass(!useJdkProxy); }