Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

optimize: compatible with integration-tx-api module and spring module #6342

Merged
merged 7 commits into from
Feb 16, 2024
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -49,5 +49,11 @@
<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>
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* 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.BusinessActionContext;
xingfudeshi marked this conversation as resolved.
Show resolved Hide resolved
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.util.Map;

/**
* Extracting TCC Context from Method
*/
public final class ActionContextUtil {

private ActionContextUtil() {
}

private static final Logger LOGGER = LoggerFactory.getLogger(ActionContextUtil.class);

/**
* 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) {
ActionContextUtil.loadParamByAnnotationAndPutToContext(paramType, paramName, paramValue, annotation, actionContext);
xingfudeshi marked this conversation as resolved.
Show resolved Hide resolved
}


public static String getParamNameFromAnnotation(@Nonnull BusinessActionContextParameter annotation) {
return ActionContextUtil.getParamNameFromAnnotation(annotation);
xingfudeshi marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* 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,82 @@
/*
* 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 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);
} else if (parameterAnnotations[i][j] instanceof org.apache.seata.rm.tcc.api.BusinessActionContextParameter) {
// get annotation
org.apache.seata.rm.tcc.api.BusinessActionContextParameter annotation = (org.apache.seata.rm.tcc.api.BusinessActionContextParameter) parameterAnnotations[i][j];
xingfudeshi marked this conversation as resolved.
Show resolved Hide resolved
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
org.apache.seata.integration.tx.api.interceptor.ActionContextUtil.loadParamByAnnotationAndPutToContext(ParamType.PARAM, "", paramObject, annotation, context);
}
}
}
return context;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* 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 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 org.apache.seata.spring.annotation.GlobalLock;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.apache.seata.tm.api.FailureHandler;

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) {
xingfudeshi marked this conversation as resolved.
Show resolved Hide resolved
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 globalTransactionalAnnotationOld = getAnnotation(specificMethod, targetClass, GlobalTransactional.class);
final org.apache.seata.spring.annotation.GlobalTransactional globalTransactionalAnnotationNew = getAnnotation(specificMethod, targetClass, org.apache.seata.spring.annotation.GlobalTransactional.class);
xingfudeshi marked this conversation as resolved.
Show resolved Hide resolved
final GlobalLock globalLockAnnotationOld = getAnnotation(specificMethod, targetClass, GlobalLock.class);
final org.apache.seata.spring.annotation.GlobalLock globalLockAnnotationNew = getAnnotation(specificMethod, targetClass, org.apache.seata.spring.annotation.GlobalLock.class);

boolean localDisable = disable || (ATOMIC_DEGRADE_CHECK.get() && degradeNum >= degradeCheckAllowTimes);
if (!localDisable) {
if (globalTransactionalAnnotationOld != null || globalTransactionalAnnotationNew != null || this.aspectTransactional != null) {
AspectTransactional transactional;
if (globalTransactionalAnnotationOld != null) {
transactional = new AspectTransactional(globalTransactionalAnnotationOld.timeoutMills(),
globalTransactionalAnnotationOld.name(), globalTransactionalAnnotationOld.rollbackFor(),
globalTransactionalAnnotationOld.rollbackForClassName(),
globalTransactionalAnnotationOld.noRollbackFor(),
globalTransactionalAnnotationOld.noRollbackForClassName(),
globalTransactionalAnnotationOld.propagation(),
globalTransactionalAnnotationOld.lockRetryInterval(),
globalTransactionalAnnotationOld.lockRetryTimes(),
globalTransactionalAnnotationOld.lockStrategyMode());
} else if (globalTransactionalAnnotationNew != null) {
transactional = new AspectTransactional(globalTransactionalAnnotationNew.timeoutMills(),
globalTransactionalAnnotationNew.name(), globalTransactionalAnnotationNew.rollbackFor(),
globalTransactionalAnnotationNew.rollbackForClassName(),
globalTransactionalAnnotationNew.noRollbackFor(),
globalTransactionalAnnotationNew.noRollbackForClassName(),
globalTransactionalAnnotationNew.propagation(),
globalTransactionalAnnotationNew.lockRetryInterval(),
globalTransactionalAnnotationNew.lockRetryTimes(),
globalTransactionalAnnotationNew.lockStrategyMode());
} else {
transactional = this.aspectTransactional;
}
return handleGlobalTransaction(invocation, transactional);
} else if (globalLockAnnotationOld != null || globalLockAnnotationNew != null) {
if (globalLockAnnotationOld != null) {
return handleGlobalLockOld(invocation, globalLockAnnotationOld);
} else {
return handleGlobalLock(invocation, globalLockAnnotationNew);
}
}
}

}
return invocation.proceed();
}


private Object handleGlobalLockOld(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
Loading