Skip to content

Commit

Permalink
optimize: compatible with integration-tx-api module and spring module (
Browse files Browse the repository at this point in the history
  • Loading branch information
xingfudeshi authored Feb 16, 2024
1 parent 4006df1 commit 65610d0
Show file tree
Hide file tree
Showing 17 changed files with 906 additions and 29 deletions.
1 change: 1 addition & 0 deletions changes/en-us/2.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 2 additions & 0 deletions changes/zh-cn/2.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
6 changes: 6 additions & 0 deletions compatible/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
28 changes: 28 additions & 0 deletions compatible/src/main/java/io/seata/common/LockStrategyMode.java
Original file line number Diff line number Diff line change
@@ -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
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
});
}
}
Loading

0 comments on commit 65610d0

Please sign in to comment.