This is an automated email from the ASF dual-hosted git repository.
jimin pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push:
new 65610d0e8e optimize: compatible with integration-tx-api module and
spring module (#6342)
65610d0e8e is described below
commit 65610d0e8ea6f5bf713745f43719382c2d8e8402
Author: xingfudeshi <[email protected]>
AuthorDate: Fri Feb 16 22:58:38 2024 +0800
optimize: compatible with integration-tx-api module and spring module
(#6342)
---
changes/en-us/2.0.0.md | 1 +
changes/zh-cn/2.0.0.md | 2 +
compatible/pom.xml | 6 +
.../java/io/seata/common/LockStrategyMode.java | 28 ++++
.../tx/api/interceptor/ActionContextUtil.java | 170 +++++++++++++++++++++
.../api/interceptor/ActionInterceptorHandler.java | 67 ++++++++
.../GlobalTransactionalInterceptorHandler.java | 95 ++++++++++++
.../GlobalTransactionalInterceptorParser.java | 62 ++++++++
.../io/seata/rm/tcc/api/BusinessActionContext.java | 20 +++
.../rm/tcc/api/BusinessActionContextParameter.java | 70 +++++++++
.../io/seata/spring/annotation/GlobalLock.java | 47 ++++++
.../spring/annotation/GlobalTransactional.java | 121 +++++++++++++++
.../main/java/io/seata/tm/api/FailureHandler.java | 20 +++
.../io/seata/tm/api/transaction/Propagation.java | 168 ++++++++++++++++++++
.../tx/api/interceptor/ActionContextUtil.java | 18 +--
.../GlobalTransactionalInterceptorHandler.java | 36 ++---
.../GlobalTransactionalInterceptorParser.java | 4 +-
17 files changed, 906 insertions(+), 29 deletions(-)
diff --git a/changes/en-us/2.0.0.md b/changes/en-us/2.0.0.md
index 7b8757be94..015ecfac60 100644
--- a/changes/en-us/2.0.0.md
+++ b/changes/en-us/2.0.0.md
@@ -155,6 +155,7 @@ The version is updated as follows:
- [[#5959](https://github.com/seata/seata/pull/5959)] modify code style and
remove unused import
- [[#6002](https://github.com/seata/seata/pull/6002)] remove fst serialization
- [[#6045](https://github.com/seata/seata/pull/6045)] optimize derivative
product check base on mysql
+- [[#6342](https://github.com/seata/seata/pull/6342)] compatible with
integration-tx-api module
### security:
- [[#5642](https://github.com/seata/seata/pull/5642)] add Hessian Serializer
WhiteDenyList
diff --git a/changes/zh-cn/2.0.0.md b/changes/zh-cn/2.0.0.md
index 0855991544..0982e53a3b 100644
--- a/changes/zh-cn/2.0.0.md
+++ b/changes/zh-cn/2.0.0.md
@@ -156,6 +156,8 @@ Seata 是一款开源的分布式事务解决方案,提供高性能和简单
- [[#5959](https://github.com/seata/seata/pull/5959)] 修正代码风格问题及去除无用的类引用
- [[#6002](https://github.com/seata/seata/pull/6002)] 移除fst序列化模块
- [[#6045](https://github.com/seata/seata/pull/6045)] 优化MySQL衍生数据库判断逻辑
+- [[#6342](https://github.com/seata/seata/pull/6342)] 兼容integration-tx-api模块
+
### security:
diff --git a/compatible/pom.xml b/compatible/pom.xml
index 865aa264f8..bf2d301b00 100644
--- a/compatible/pom.xml
+++ b/compatible/pom.xml
@@ -86,6 +86,12 @@
<artifactId>seata-rm-datasource</artifactId>
<version>2.1.0-SNAPSHOT</version>
<scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.seata</groupId>
+ <artifactId>seata-integration-tx-api</artifactId>
+ <version>2.1.0-SNAPSHOT</version>
+ <scope>compile</scope>
</dependency>
</dependencies>
</project>
diff --git a/compatible/src/main/java/io/seata/common/LockStrategyMode.java
b/compatible/src/main/java/io/seata/common/LockStrategyMode.java
new file mode 100644
index 0000000000..530c95dded
--- /dev/null
+++ b/compatible/src/main/java/io/seata/common/LockStrategyMode.java
@@ -0,0 +1,28 @@
+/*
+ * 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 io.seata.common;
+
+public enum LockStrategyMode {
+ /**
+ * Optimistic lock mode is recommended when resources are not reused in
the current global transaction.
+ */
+ OPTIMISTIC,
+ /**
+ * Pessimistic lock mode is recommended when there may be repeated use of
the same resource in a global transaction.
+ */
+ PESSIMISTIC
+}
diff --git
a/compatible/src/main/java/io/seata/integration/tx/api/interceptor/ActionContextUtil.java
b/compatible/src/main/java/io/seata/integration/tx/api/interceptor/ActionContextUtil.java
new file mode 100644
index 0000000000..ac90af80be
--- /dev/null
+++
b/compatible/src/main/java/io/seata/integration/tx/api/interceptor/ActionContextUtil.java
@@ -0,0 +1,170 @@
+/*
+ * 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 io.seata.integration.tx.api.interceptor;
+
+import io.seata.rm.tcc.api.BusinessActionContext;
+import io.seata.rm.tcc.api.BusinessActionContextParameter;
+import org.apache.seata.common.util.CollectionUtils;
+import org.apache.seata.common.util.StringUtils;
+import org.apache.seata.rm.tcc.api.ParamType;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.util.Map;
+
+import static
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.getByIndex;
+
+/**
+ * Extracting TCC Context from Method
+ */
+public final class ActionContextUtil {
+
+ private ActionContextUtil() {
+ }
+
+ /**
+ * Extracting context data from parameters
+ *
+ * @param targetParam the target param
+ * @return map the context
+ */
+ public static Map<String, Object> fetchContextFromObject(@Nonnull Object
targetParam) {
+ return
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.fetchContextFromObject(targetParam);
+ }
+
+ /**
+ * load param by the config of annotation, and then put into the action
context
+ *
+ * @param paramType the param type, 'param' or 'field'
+ * @param paramName the param name
+ * @param paramValue the param value
+ * @param annotation the annotation on the param or field
+ * @param actionContext the action context
+ */
+ public static void loadParamByAnnotationAndPutToContext(@Nonnull final
ParamType paramType, @Nonnull String paramName, Object paramValue,
+ @Nonnull final
BusinessActionContextParameter annotation, @Nonnull final Map<String, Object>
actionContext) {
+ if (paramValue == null) {
+ return;
+ }
+
+ // If {@code index >= 0}, get by index from the list param or field
+ int index = annotation.index();
+ if (index >= 0) {
+ paramValue = getByIndex(paramType, paramName, paramValue, index);
+ if (paramValue == null) {
+ return;
+ }
+ }
+
+ // if {@code isParamInProperty == true}, fetch context from paramValue
+ if (annotation.isParamInProperty()) {
+ Map<String, Object> paramContext =
fetchContextFromObject(paramValue);
+ if (CollectionUtils.isNotEmpty(paramContext)) {
+ actionContext.putAll(paramContext);
+ }
+ } else {
+ // get param name from the annotation
+ String paramNameFromAnnotation =
getParamNameFromAnnotation(annotation);
+ if (StringUtils.isNotBlank(paramNameFromAnnotation)) {
+ paramName = paramNameFromAnnotation;
+ }
+ putActionContextWithoutHandle(actionContext, paramName,
paramValue);
+ }
+ }
+
+
+ public static String getParamNameFromAnnotation(@Nonnull
BusinessActionContextParameter annotation) {
+ String paramName = annotation.paramName();
+ if (StringUtils.isBlank(paramName)) {
+ paramName = annotation.value();
+ }
+ return paramName;
+ }
+
+ /**
+ * put the action context after handle
+ *
+ * @param actionContext the action context
+ * @param key the actionContext's key
+ * @param value the actionContext's value
+ * @return the action context is changed
+ */
+ public static boolean putActionContext(Map<String, Object> actionContext,
String key, Object value) {
+ return
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.putActionContext(actionContext,
key, value);
+ }
+
+ /**
+ * put the action context after handle
+ *
+ * @param actionContext the action context
+ * @param actionContextMap the actionContextMap
+ * @return the action context is changed
+ */
+ public static boolean putActionContext(Map<String, Object> actionContext,
@Nonnull Map<String, Object> actionContextMap) {
+ return
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.putActionContext(actionContext,
actionContextMap);
+ }
+
+ /**
+ * put the action context without handle
+ *
+ * @param actionContext the action context
+ * @param key the actionContext's key
+ * @param value the actionContext's value
+ * @return the action context is changed
+ */
+ public static boolean putActionContextWithoutHandle(@Nonnull final
Map<String, Object> actionContext, String key, Object value) {
+ return
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.putActionContextWithoutHandle(actionContext,
key, value);
+ }
+
+ /**
+ * put the action context without handle
+ *
+ * @param actionContext the action context
+ * @param actionContextMap the actionContextMap
+ * @return the action context is changed
+ */
+ public static boolean putActionContextWithoutHandle(Map<String, Object>
actionContext, @Nonnull Map<String, Object> actionContextMap) {
+ return
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.putActionContextWithoutHandle(actionContext,
actionContextMap);
+ }
+
+ /**
+ * Handle the action context.
+ * It is convenient to convert type in phase 2.
+ *
+ * @param actionContext the action context
+ * @return the action context or JSON string
+ * @see #convertActionContext(String, Object, Class)
+ * @see BusinessActionContext#getActionContext(String, Class)
+ */
+ public static Object handleActionContext(@Nonnull Object actionContext) {
+ return
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.handleActionContext(actionContext);
+ }
+
+ /**
+ * Convert action context
+ *
+ * @param key the actionContext's key
+ * @param value the actionContext's value
+ * @param targetClazz the target class
+ * @param <T> the target type
+ * @return the action context of the target type
+ */
+ @SuppressWarnings("unchecked")
+ public static <T> T convertActionContext(String key, @Nullable Object
value, @Nonnull Class<T> targetClazz) {
+ return
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.convertActionContext(key,
value, targetClazz);
+ }
+}
diff --git
a/compatible/src/main/java/io/seata/integration/tx/api/interceptor/ActionInterceptorHandler.java
b/compatible/src/main/java/io/seata/integration/tx/api/interceptor/ActionInterceptorHandler.java
new file mode 100644
index 0000000000..161188cd03
--- /dev/null
+++
b/compatible/src/main/java/io/seata/integration/tx/api/interceptor/ActionInterceptorHandler.java
@@ -0,0 +1,67 @@
+/*
+ * 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 io.seata.integration.tx.api.interceptor;
+
+import io.seata.rm.tcc.api.BusinessActionContextParameter;
+import org.apache.seata.rm.tcc.api.ParamType;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Handler the Tx Participant Aspect : Setting Context, Creating Branch Record
+ */
+public class ActionInterceptorHandler extends
org.apache.seata.integration.tx.api.interceptor.ActionInterceptorHandler {
+
+
+ /**
+ * Extracting context data from parameters, add them to the context
+ *
+ * @param method the method
+ * @param arguments the arguments
+ * @return the context
+ */
+ @Override
+ protected Map<String, Object> fetchActionRequestContext(Method method,
Object[] arguments) {
+ Map<String, Object> context = new HashMap<>(8);
+
+ Annotation[][] parameterAnnotations = method.getParameterAnnotations();
+ for (int i = 0; i < parameterAnnotations.length; i++) {
+ for (int j = 0; j < parameterAnnotations[i].length; j++) {
+ if (parameterAnnotations[i][j] instanceof
org.apache.seata.rm.tcc.api.BusinessActionContextParameter) {
+ // get annotation
+ BusinessActionContextParameter annotation =
(BusinessActionContextParameter) parameterAnnotations[i][j];
+ if (arguments[i] == null) {
+ throw new
IllegalArgumentException("@BusinessActionContextParameter 's params can not
null");
+ }
+
+ // get param
+ Object paramObject = arguments[i];
+ if (paramObject == null) {
+ continue;
+ }
+
+ // load param by the config of annotation, and then put
into the context
+
ActionContextUtil.loadParamByAnnotationAndPutToContext(ParamType.PARAM, "",
paramObject, annotation, context);
+ }
+ }
+ }
+ return context;
+ }
+}
diff --git
a/compatible/src/main/java/io/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java
b/compatible/src/main/java/io/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java
new file mode 100644
index 0000000000..2882ec1fa9
--- /dev/null
+++
b/compatible/src/main/java/io/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java
@@ -0,0 +1,95 @@
+/*
+ * 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 io.seata.integration.tx.api.interceptor.handler;
+
+import io.seata.spring.annotation.GlobalLock;
+import io.seata.spring.annotation.GlobalTransactional;
+import io.seata.tm.api.FailureHandler;
+import org.apache.seata.core.model.GlobalLockConfig;
+import org.apache.seata.integration.tx.api.annotation.AspectTransactional;
+import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
+import org.apache.seata.integration.tx.api.util.ClassUtils;
+import org.apache.seata.rm.GlobalLockExecutor;
+
+import java.lang.reflect.Method;
+import java.util.Set;
+
+/**
+ * The type Global transactional interceptor handler.
+ */
+public class GlobalTransactionalInterceptorHandler extends
org.apache.seata.integration.tx.api.interceptor.handler.GlobalTransactionalInterceptorHandler
{
+
+
+ public GlobalTransactionalInterceptorHandler(FailureHandler
failureHandler, Set<String> methodsToProxy) {
+ super(failureHandler, methodsToProxy);
+ }
+
+ public GlobalTransactionalInterceptorHandler(FailureHandler
failureHandler, Set<String> methodsToProxy, AspectTransactional
aspectTransactional) {
+ super(failureHandler, methodsToProxy, aspectTransactional);
+ }
+
+ @Override
+ protected Object doInvoke(InvocationWrapper invocation) throws Throwable {
+ Class<?> targetClass = invocation.getTarget().getClass();
+ Method specificMethod =
ClassUtils.getMostSpecificMethod(invocation.getMethod(), targetClass);
+ if (specificMethod != null &&
!specificMethod.getDeclaringClass().equals(Object.class)) {
+ final GlobalTransactional globalTransactionalAnnotation =
getAnnotation(specificMethod, targetClass, GlobalTransactional.class);
+ final GlobalLock globalLockAnnotation =
getAnnotation(specificMethod, targetClass, GlobalLock.class);
+ boolean localDisable = disable || (ATOMIC_DEGRADE_CHECK.get() &&
degradeNum >= degradeCheckAllowTimes);
+ if (!localDisable) {
+ if (globalTransactionalAnnotation != null ||
this.aspectTransactional != null) {
+ AspectTransactional transactional;
+ if (globalTransactionalAnnotation != null) {
+ transactional = new
AspectTransactional(globalTransactionalAnnotation.timeoutMills(),
+ globalTransactionalAnnotation.name(),
globalTransactionalAnnotation.rollbackFor(),
+
globalTransactionalAnnotation.rollbackForClassName(),
+ globalTransactionalAnnotation.noRollbackFor(),
+
globalTransactionalAnnotation.noRollbackForClassName(),
+
org.apache.seata.tm.api.transaction.Propagation.valueOf(globalTransactionalAnnotation.propagation().name()),
+
globalTransactionalAnnotation.lockRetryInterval(),
+ globalTransactionalAnnotation.lockRetryTimes(),
+
org.apache.seata.common.LockStrategyMode.valueOf(globalTransactionalAnnotation.lockStrategyMode().name()));
+ } else {
+ transactional = this.aspectTransactional;
+ }
+ return handleGlobalTransaction(invocation, transactional);
+ } else if (globalLockAnnotation != null) {
+ return handleGlobalLock(invocation, globalLockAnnotation);
+ }
+ }
+ }
+ return invocation.proceed();
+ }
+
+
+ private Object handleGlobalLock(final InvocationWrapper methodInvocation,
final GlobalLock globalLockAnno) throws Throwable {
+ return globalLockTemplate.execute(new GlobalLockExecutor() {
+ @Override
+ public Object execute() throws Throwable {
+ return methodInvocation.proceed();
+ }
+
+ @Override
+ public GlobalLockConfig getGlobalLockConfig() {
+ GlobalLockConfig config = new GlobalLockConfig();
+
config.setLockRetryInterval(globalLockAnno.lockRetryInterval());
+ config.setLockRetryTimes(globalLockAnno.lockRetryTimes());
+ return config;
+ }
+ });
+ }
+}
diff --git
a/compatible/src/main/java/io/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java
b/compatible/src/main/java/io/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java
new file mode 100644
index 0000000000..485034e6e3
--- /dev/null
+++
b/compatible/src/main/java/io/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java
@@ -0,0 +1,62 @@
+/*
+ * 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 io.seata.integration.tx.api.interceptor.parser;
+
+import io.seata.spring.annotation.GlobalLock;
+import io.seata.spring.annotation.GlobalTransactional;
+import org.apache.seata.common.util.CollectionUtils;
+
+import java.lang.reflect.Method;
+
+public class GlobalTransactionalInterceptorParser extends
org.apache.seata.integration.tx.api.interceptor.parser.GlobalTransactionalInterceptorParser
{
+
+ @Override
+ protected boolean existsAnnotation(Class<?>... classes) {
+ boolean result = false;
+ if (CollectionUtils.isNotEmpty(classes)) {
+ for (Class<?> clazz : classes) {
+ if (clazz == null) {
+ continue;
+ }
+ GlobalTransactional trxAnnoOld =
clazz.getAnnotation(GlobalTransactional.class);
+ org.apache.seata.spring.annotation.GlobalTransactional
trxAnnoNew =
clazz.getAnnotation(org.apache.seata.spring.annotation.GlobalTransactional.class);
+
+ if (trxAnnoOld != null || trxAnnoNew != null) {
+ return true;
+ }
+ Method[] methods = clazz.getMethods();
+ for (Method method : methods) {
+ trxAnnoOld =
method.getAnnotation(GlobalTransactional.class);
+ trxAnnoNew =
method.getAnnotation(org.apache.seata.spring.annotation.GlobalTransactional.class);
+ if (trxAnnoOld != null || trxAnnoNew != null) {
+ methodsToProxy.add(method.getName());
+ result = true;
+ }
+
+ GlobalLock lockAnnoOld =
method.getAnnotation(GlobalLock.class);
+ org.apache.seata.spring.annotation.GlobalLock lockAnnoNew
= method.getAnnotation(org.apache.seata.spring.annotation.GlobalLock.class);
+
+ if (lockAnnoOld != null || lockAnnoNew != null) {
+ methodsToProxy.add(method.getName());
+ result = true;
+ }
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git
a/compatible/src/main/java/io/seata/rm/tcc/api/BusinessActionContext.java
b/compatible/src/main/java/io/seata/rm/tcc/api/BusinessActionContext.java
new file mode 100644
index 0000000000..d3ad5cd05b
--- /dev/null
+++ b/compatible/src/main/java/io/seata/rm/tcc/api/BusinessActionContext.java
@@ -0,0 +1,20 @@
+/*
+ * 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 io.seata.rm.tcc.api;
+
+public class BusinessActionContext extends
org.apache.seata.rm.tcc.api.BusinessActionContext {
+}
diff --git
a/compatible/src/main/java/io/seata/rm/tcc/api/BusinessActionContextParameter.java
b/compatible/src/main/java/io/seata/rm/tcc/api/BusinessActionContextParameter.java
new file mode 100644
index 0000000000..d9649587ef
--- /dev/null
+++
b/compatible/src/main/java/io/seata/rm/tcc/api/BusinessActionContextParameter.java
@@ -0,0 +1,70 @@
+/*
+ * 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 io.seata.rm.tcc.api;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.PARAMETER, ElementType.FIELD})
+public @interface BusinessActionContextParameter {
+
+ /**
+ * parameter's name. Synonym for {@link #paramName()}.
+ *
+ * @return the name of the param or field
+ * @see
org.apache.seata.spring.interceptor.ActionContextUtil#getParamNameFromAnnotation
+ */
+ String value() default "";
+
+ /**
+ * parameter's name. Synonym for {@link #value()}.
+ *
+ * @return the name of the param or field
+ * @see
org.apache.seata.spring.interceptor.ActionContextUtil#getParamNameFromAnnotation
+ */
+ String paramName() default "";
+
+ /**
+ * if it is a sharding param ?
+ *
+ * @return the boolean
+ * @deprecated This property is no longer in use.
+ */
+ @Deprecated
+ boolean isShardingParam() default false;
+
+ /**
+ * Specify the index of the parameter in the List
+ *
+ * @return the index of the List
+ * @see org.apache.seata.spring.interceptor.ActionContextUtil#getByIndex
+ */
+ int index() default -1;
+
+ /**
+ * whether get the parameter from the property of the object
+ * if {@code index >= 0}, the object get from the List and then do get the
parameter from the property of the object
+ *
+ * @return the boolean
+ * @see
org.apache.seata.spring.interceptor.ActionContextUtil#loadParamByAnnotationAndPutToContext
+ * @see
org.apache.seata.spring.interceptor.ActionContextUtil#fetchContextFromObject
+ */
+ boolean isParamInProperty() default false;
+}
diff --git
a/compatible/src/main/java/io/seata/spring/annotation/GlobalLock.java
b/compatible/src/main/java/io/seata/spring/annotation/GlobalLock.java
new file mode 100644
index 0000000000..f47e32976a
--- /dev/null
+++ b/compatible/src/main/java/io/seata/spring/annotation/GlobalLock.java
@@ -0,0 +1,47 @@
+/*
+ * 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 io.seata.spring.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Inherited
+public @interface GlobalLock {
+ /**
+ * customized global lock retry interval(unit: ms)
+ * you may use this to override global config of
"client.rm.lock.retryInterval"
+ * note: 0 or negative number will take no effect(which mean fall back to
global config)
+ *
+ * @return lock retry interval
+ */
+ int lockRetryInterval() default 0;
+
+ /**
+ * customized global lock retry times
+ * you may use this to override global config of
"client.rm.lock.retryTimes"
+ * note: negative number will take no effect(which mean fall back to
global config)
+ *
+ * @return lock retry times
+ */
+ int lockRetryTimes() default -1;
+}
diff --git
a/compatible/src/main/java/io/seata/spring/annotation/GlobalTransactional.java
b/compatible/src/main/java/io/seata/spring/annotation/GlobalTransactional.java
new file mode 100644
index 0000000000..f4d4fe0818
--- /dev/null
+++
b/compatible/src/main/java/io/seata/spring/annotation/GlobalTransactional.java
@@ -0,0 +1,121 @@
+/*
+ * 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 io.seata.spring.annotation;
+
+import io.seata.common.LockStrategyMode;
+import io.seata.tm.api.transaction.Propagation;
+import org.apache.seata.common.DefaultValues;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Inherited
+public @interface GlobalTransactional {
+
+ /**
+ * Global transaction timeoutMills in MILLISECONDS.
+ * If client.tm.default-global-transaction-timeout is configured, It will
replace the DefaultValues
+ * .DEFAULT_GLOBAL_TRANSACTION_TIMEOUT.
+ *
+ * @return timeoutMills in MILLISECONDS.
+ */
+ int timeoutMills() default
DefaultValues.DEFAULT_GLOBAL_TRANSACTION_TIMEOUT;
+
+ /**
+ * Given name of the global transaction instance.
+ *
+ * @return Given name.
+ */
+ String name() default "";
+
+ /**
+ * roll back for the Class
+ *
+ * @return the class array of the rollback for
+ */
+ Class<? extends Throwable>[] rollbackFor() default {};
+
+ /**
+ * roll back for the class name
+ *
+ * @return the class name of rollback for
+ */
+ String[] rollbackForClassName() default {};
+
+ /**
+ * not roll back for the Class
+ *
+ * @return the class array of no rollback for
+ */
+ Class<? extends Throwable>[] noRollbackFor() default {};
+
+ /**
+ * not roll back for the class name
+ *
+ * @return string [ ]
+ */
+ String[] noRollbackForClassName() default {};
+
+ /**
+ * the propagation of the global transaction
+ *
+ * @return propagation
+ */
+ Propagation propagation() default Propagation.REQUIRED;
+
+ /**
+ * customized global lock retry interval(unit: ms)
+ * you may use this to override global config of
"client.rm.lock.retryInterval"
+ * note: 0 or negative number will take no effect(which mean fall back to
global config)
+ *
+ * @return int
+ */
+ int lockRetryInterval() default 0;
+
+ /**
+ * customized global lock retry interval(unit: ms)
+ * you may use this to override global config of
"client.rm.lock.retryInterval"
+ * note: 0 or negative number will take no effect(which mean fall back to
global config)
+ *
+ * @return int
+ */
+ @Deprecated
+ int lockRetryInternal() default 0;
+
+ /**
+ * customized global lock retry times
+ * you may use this to override global config of
"client.rm.lock.retryTimes"
+ * note: negative number will take no effect(which mean fall back to
global config)
+ *
+ * @return int
+ */
+ int lockRetryTimes() default -1;
+
+ /**
+ * pick the Acquire lock policy
+ *
+ * @return lock strategy mode
+ */
+ LockStrategyMode lockStrategyMode() default LockStrategyMode.PESSIMISTIC;
+
+}
diff --git a/compatible/src/main/java/io/seata/tm/api/FailureHandler.java
b/compatible/src/main/java/io/seata/tm/api/FailureHandler.java
new file mode 100644
index 0000000000..5ff6615201
--- /dev/null
+++ b/compatible/src/main/java/io/seata/tm/api/FailureHandler.java
@@ -0,0 +1,20 @@
+/*
+ * 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 io.seata.tm.api;
+
+public interface FailureHandler extends org.apache.seata.tm.api.FailureHandler
{
+}
diff --git
a/compatible/src/main/java/io/seata/tm/api/transaction/Propagation.java
b/compatible/src/main/java/io/seata/tm/api/transaction/Propagation.java
new file mode 100644
index 0000000000..feae3a3cd8
--- /dev/null
+++ b/compatible/src/main/java/io/seata/tm/api/transaction/Propagation.java
@@ -0,0 +1,168 @@
+/*
+ * 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 io.seata.tm.api.transaction;
+
+public enum Propagation {
+ /**
+ * The REQUIRED.
+ * The default propagation.
+ *
+ * <p>
+ * If transaction is existing, execute with current transaction,
+ * else execute with new transaction.
+ * </p>
+ *
+ * <p>
+ * The logic is similar to the following code:
+ * <code><pre>
+ * if (tx == null) {
+ * try {
+ * tx = beginNewTransaction(); // begin new transaction, is
not existing
+ * Object rs = business.execute(); // execute with new
transaction
+ * commitTransaction(tx);
+ * return rs;
+ * } catch (Exception ex) {
+ * rollbackTransaction(tx);
+ * throw ex;
+ * }
+ * } else {
+ * return business.execute(); // execute with current transaction
+ * }
+ * </pre></code>
+ * </p>
+ */
+ REQUIRED,
+
+ /**
+ * The REQUIRES_NEW.
+ *
+ * <p>
+ * If transaction is existing, suspend it, and then execute business with
new transaction.
+ * </p>
+ *
+ * <p>
+ * The logic is similar to the following code:
+ * <code><pre>
+ * try {
+ * if (tx != null) {
+ * suspendedResource = suspendTransaction(tx); // suspend
current transaction
+ * }
+ * try {
+ * tx = beginNewTransaction(); // begin new transaction
+ * Object rs = business.execute(); // execute with new
transaction
+ * commitTransaction(tx);
+ * return rs;
+ * } catch (Exception ex) {
+ * rollbackTransaction(tx);
+ * throw ex;
+ * }
+ * } finally {
+ * if (suspendedResource != null) {
+ * resumeTransaction(suspendedResource); // resume transaction
+ * }
+ * }
+ * </pre></code>
+ * </p>
+ */
+ REQUIRES_NEW,
+
+ /**
+ * The NOT_SUPPORTED.
+ *
+ * <p>
+ * If transaction is existing, suspend it, and then execute business
without transaction.
+ * </p>
+ *
+ * <p>
+ * The logic is similar to the following code:
+ * <code><pre>
+ * try {
+ * if (tx != null) {
+ * suspendedResource = suspendTransaction(tx); // suspend
current transaction
+ * }
+ * return business.execute(); // execute without transaction
+ * } finally {
+ * if (suspendedResource != null) {
+ * resumeTransaction(suspendedResource); // resume transaction
+ * }
+ * }
+ * </pre></code>
+ * </p>
+ */
+ NOT_SUPPORTED,
+
+ /**
+ * The SUPPORTS.
+ *
+ * <p>
+ * If transaction is not existing, execute without global transaction,
+ * else execute business with current transaction.
+ * </p>
+ *
+ * <p>
+ * The logic is similar to the following code:
+ * <code><pre>
+ * if (tx != null) {
+ * return business.execute(); // execute with current transaction
+ * } else {
+ * return business.execute(); // execute without transaction
+ * }
+ * </pre></code>
+ * </p>
+ */
+ SUPPORTS,
+
+ /**
+ * The NEVER.
+ *
+ * <p>
+ * If transaction is existing, throw exception,
+ * else execute business without transaction.
+ * </p>
+ *
+ * <p>
+ * The logic is similar to the following code:
+ * <code><pre>
+ * if (tx != null) {
+ * throw new TransactionException("existing transaction");
+ * }
+ * return business.execute(); // execute without transaction
+ * </pre></code>
+ * </p>
+ */
+ NEVER,
+
+ /**
+ * The MANDATORY.
+ *
+ * <p>
+ * If transaction is not existing, throw exception,
+ * else execute business with current transaction.
+ * </p>
+ *
+ * <p>
+ * The logic is similar to the following code:
+ * <code><pre>
+ * if (tx == null) {
+ * throw new TransactionException("not existing transaction");
+ * }
+ * return business.execute(); // execute with current transaction
+ * </pre></code>
+ * </p>
+ */
+ MANDATORY
+}
diff --git
a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/ActionContextUtil.java
b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/ActionContextUtil.java
index 08e2459fec..ad6b7be469 100644
---
a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/ActionContextUtil.java
+++
b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/ActionContextUtil.java
@@ -16,14 +16,6 @@
*/
package org.apache.seata.integration.tx.api.interceptor;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import java.lang.reflect.Field;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
import org.apache.seata.common.exception.FrameworkException;
import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.common.util.ReflectionUtil;
@@ -35,6 +27,14 @@ import org.apache.seata.rm.tcc.api.ParamType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
/**
* Extracting TCC Context from Method
*
@@ -128,7 +128,7 @@ public final class ActionContextUtil {
}
@Nullable
- private static Object getByIndex(@Nonnull ParamType paramType, @Nonnull
String paramName, @Nonnull Object paramValue, int index) {
+ public static Object getByIndex(@Nonnull ParamType paramType, @Nonnull
String paramName, @Nonnull Object paramValue, int index) {
if (paramValue instanceof List) {
@SuppressWarnings("unchecked")
List<Object> list = (List<Object>)paramValue;
diff --git
a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java
b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java
index 7f9750a646..bc3a401402 100644
---
a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java
+++
b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/handler/GlobalTransactionalInterceptorHandler.java
@@ -16,16 +16,6 @@
*/
package org.apache.seata.integration.tx.api.interceptor.handler;
-import org.apache.seata.tm.api.GlobalTransaction;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Method;
-import java.util.LinkedHashSet;
-import java.util.Optional;
-import java.util.Set;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
import org.apache.seata.common.exception.ShouldNeverHappenException;
import org.apache.seata.common.thread.NamedThreadFactory;
import org.apache.seata.common.util.StringUtils;
@@ -51,6 +41,7 @@ import org.apache.seata.spring.annotation.GlobalTransactional;
import org.apache.seata.tm.TransactionManagerHolder;
import org.apache.seata.tm.api.FailureHandler;
import org.apache.seata.tm.api.FailureHandlerHolder;
+import org.apache.seata.tm.api.GlobalTransaction;
import org.apache.seata.tm.api.TransactionalExecutor;
import org.apache.seata.tm.api.TransactionalTemplate;
import org.apache.seata.tm.api.transaction.NoRollbackRule;
@@ -59,6 +50,15 @@ import org.apache.seata.tm.api.transaction.TransactionInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.LinkedHashSet;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
import static
org.apache.seata.common.DefaultValues.DEFAULT_DISABLE_GLOBAL_TRANSACTION;
import static
org.apache.seata.common.DefaultValues.DEFAULT_GLOBAL_TRANSACTION_TIMEOUT;
import static org.apache.seata.common.DefaultValues.DEFAULT_TM_DEGRADE_CHECK;
@@ -75,15 +75,15 @@ public class GlobalTransactionalInterceptorHandler extends
AbstractProxyInvocati
private static final Logger LOGGER =
LoggerFactory.getLogger(GlobalTransactionalInterceptorHandler.class);
private final TransactionalTemplate transactionalTemplate = new
TransactionalTemplate();
- private final GlobalLockTemplate globalLockTemplate = new
GlobalLockTemplate();
+ protected final GlobalLockTemplate globalLockTemplate = new
GlobalLockTemplate();
private Set<String> methodsToProxy;
- private volatile boolean disable;
- private static final AtomicBoolean ATOMIC_DEGRADE_CHECK = new
AtomicBoolean(false);
- private static volatile Integer degradeNum = 0;
+ protected volatile boolean disable;
+ protected static final AtomicBoolean ATOMIC_DEGRADE_CHECK = new
AtomicBoolean(false);
+ protected static volatile Integer degradeNum = 0;
private static volatile Integer reachNum = 0;
- private static int degradeCheckAllowTimes;
+ protected static int degradeCheckAllowTimes;
protected AspectTransactional aspectTransactional;
private static int degradeCheckPeriod;
@@ -172,7 +172,7 @@ public class GlobalTransactionalInterceptorHandler extends
AbstractProxyInvocati
}
- private Object handleGlobalLock(final InvocationWrapper methodInvocation,
final GlobalLock globalLockAnno) throws Throwable {
+ protected Object handleGlobalLock(final InvocationWrapper
methodInvocation, final GlobalLock globalLockAnno) throws Throwable {
return globalLockTemplate.execute(new GlobalLockExecutor() {
@Override
public Object execute() throws Throwable {
@@ -189,8 +189,8 @@ public class GlobalTransactionalInterceptorHandler extends
AbstractProxyInvocati
});
}
- Object handleGlobalTransaction(final InvocationWrapper methodInvocation,
- final AspectTransactional
aspectTransactional) throws Throwable {
+ protected Object handleGlobalTransaction(final InvocationWrapper
methodInvocation,
+ final AspectTransactional
aspectTransactional) throws Throwable {
boolean succeed = true;
try {
return transactionalTemplate.execute(new TransactionalExecutor() {
diff --git
a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java
b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java
index 3026615db9..beacda7de1 100644
---
a/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java
+++
b/integration-tx-api/src/main/java/org/apache/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java
@@ -34,7 +34,7 @@ import org.apache.seata.tm.api.FailureHandlerHolder;
public class GlobalTransactionalInterceptorParser implements InterfaceParser {
- private final Set<String> methodsToProxy = new HashSet<>();
+ protected final Set<String> methodsToProxy = new HashSet<>();
/**
* @param target
@@ -72,7 +72,7 @@ public class GlobalTransactionalInterceptorParser implements
InterfaceParser {
return ifNeedEnhanceBean;
}
- private boolean existsAnnotation(Class<?>... classes) {
+ protected boolean existsAnnotation(Class<?>... classes) {
boolean result = false;
if (CollectionUtils.isNotEmpty(classes)) {
for (Class<?> clazz : classes) {
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]