Skip to content

Commit

Permalink
bugfix: TwoPhaseBusinessAction coexist with GlobalTransactional (#6331)
Browse files Browse the repository at this point in the history
  • Loading branch information
leezongjie committed Feb 28, 2024
1 parent 87b6e5f commit 1939a9f
Show file tree
Hide file tree
Showing 18 changed files with 742 additions and 51 deletions.
1 change: 1 addition & 0 deletions changes/en-us/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#6232](https://github.com/apache/incubator-seata/pull/6232)] convert to utf8mb4 if mysql column is json type
- [[#6278](https://github.com/apache/incubator-seata/pull/6278)] fix ProtocolV1SerializerTest failed
- [[#6324](https://github.com/apache/incubator-seata/pull/6324)] fix Parse protocol file failed
- [[#6331](https://github.com/apache/incubator-seata/pull/6331)] fixed the problem that TCC nested transactions cannot add TwoPhaseBusinessAction and GlobalTransactional annotations at the same time
- [[#6354](https://github.com/apache/incubator-seata/pull/6354)] fix dynamic degradation does not work properly
- [[#6363](https://github.com/apache/incubator-seata/pull/6363)] fix known problems of docker image
- [[#6372](https://github.com/apache/incubator-seata/pull/6372)] fix initializing the sql file postgresql.sql index name conflict
Expand Down
1 change: 1 addition & 0 deletions changes/zh-cn/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
- [[#6232](https://github.com/apache/incubator-seata/pull/6232)] 修复在mysql的json类型下出现Cannot create a JSON value from a string with CHARACTER SET 'binary'问题
- [[#6278](https://github.com/apache/incubator-seata/pull/6278)] 修复 ProtocolV1SerializerTest 失败问题
- [[#6324](https://github.com/apache/incubator-seata/pull/6324)] 修复 Parse protocol file failed
- [[#6331](https://github.com/apache/incubator-seata/pull/6331)] 修复TCC嵌套事务不能同时添加TwoPhaseBusinessAction和GlobalTransactional两个注解的问题
- [[#6354](https://github.com/apache/incubator-seata/pull/6354)] 修复动态升降级不能正常工作问题
- [[#6363](https://github.com/apache/incubator-seata/pull/6363)] 修复docker镜像中的已知问题
- [[#6372](https://github.com/apache/incubator-seata/pull/6372)] 修复初始化sql文件postgresql.sql 索引名称冲突问题
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* 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 org.apache.seata.integration.tx.api.interceptor;

/**
* The InvocationHandlerType enum
*/
public enum InvocationHandlerType {

GlobalTransactional, TwoPhaseAnnotation

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* 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 org.apache.seata.integration.tx.api.interceptor;

import java.lang.reflect.Method;
import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler;


public class NestInterceptorHandlerWrapper implements InvocationWrapper {

private ProxyInvocationHandler proxyInvocationHandler;

private InvocationWrapper invocation;

public NestInterceptorHandlerWrapper(ProxyInvocationHandler proxyInvocationHandler, InvocationWrapper invocation) {
this.proxyInvocationHandler = proxyInvocationHandler;
this.invocation = invocation;
}

@Override
public Method getMethod() {
return invocation.getMethod();
}

@Override
public Object getProxy() {
return invocation.getProxy();
}

@Override
public Object getTarget() {
return invocation.getTarget();
}

@Override
public Object[] getArguments() {
return invocation.getArguments();
}

@Override
public Object proceed() throws Throwable {
return proxyInvocationHandler.invoke(invocation);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
import org.apache.seata.integration.tx.api.interceptor.NestInterceptorHandlerWrapper;


public abstract class AbstractProxyInvocationHandler implements ProxyInvocationHandler {
Expand All @@ -26,11 +27,16 @@ public abstract class AbstractProxyInvocationHandler implements ProxyInvocationH

protected int order = Integer.MAX_VALUE;

protected ProxyInvocationHandler nextInvocationHandlerChain;

@Override
public Object invoke(InvocationWrapper invocation) throws Throwable {
if (CollectionUtils.isNotEmpty(getMethodsToProxy()) && !getMethodsToProxy().contains(invocation.getMethod().getName())) {
return invocation.proceed();
}
if (nextInvocationHandlerChain != null) {
invocation = new NestInterceptorHandlerWrapper(nextInvocationHandlerChain, invocation);
}
return doInvoke(invocation);
}

Expand All @@ -44,4 +50,8 @@ public int getOrder() {
return this.order;
}

@Override
public void setNextProxyInvocationHandler(ProxyInvocationHandler next) {
this.nextInvocationHandlerChain = next;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,15 @@
*/
package org.apache.seata.integration.tx.api.interceptor.handler;

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 com.google.common.eventbus.Subscribe;
import org.apache.seata.common.exception.ShouldNeverHappenException;
import org.apache.seata.common.thread.NamedThreadFactory;
Expand All @@ -32,6 +41,7 @@
import org.apache.seata.core.model.GlobalLockConfig;
import org.apache.seata.integration.tx.api.annotation.AspectTransactional;
import org.apache.seata.integration.tx.api.event.DegradeCheckEvent;
import org.apache.seata.integration.tx.api.interceptor.InvocationHandlerType;
import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
import org.apache.seata.integration.tx.api.interceptor.SeataInterceptorPosition;
import org.apache.seata.integration.tx.api.util.ClassUtils;
Expand All @@ -51,15 +61,6 @@
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;
Expand Down Expand Up @@ -410,4 +411,9 @@ public SeataInterceptorPosition getPosition() {
return SeataInterceptorPosition.BeforeTransaction;
}


@Override
public String type() {
return InvocationHandlerType.GlobalTransactional.name();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,11 @@ public interface ProxyInvocationHandler extends SeataInterceptor {

SeataInterceptorPosition getPosition();

String type();

default int order() {
return 0;
}

void setNextProxyInvocationHandler(ProxyInvocationHandler next);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@
*/
package org.apache.seata.integration.tx.api.interceptor.parser;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.seata.common.loader.EnhancedServiceLoader;
import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler;

import java.util.ArrayList;
import java.util.List;

/**
* @author leezongjie
*/
Expand Down Expand Up @@ -53,15 +57,46 @@ protected void initInterfaceParser() {
}
}

/**
* Create an interceptor chain that supports adding multiple interceptors.Create an interceptor chain that supports adding multiple interceptors.
* The entry order of the facets can be specified through {@link ProxyInvocationHandler # order()}.
* It is not allowed to load multiple interceptors of the same type, such as two-stage annotations for TCC and Saga that cannot exist simultaneously. The type can be specified through {@link ProxyInvocationHandler # type()}.It is not allowed to load multiple interceptors of the same type, such as two-stage annotations for TCC and Saga that cannot exist simultaneously. The type can be specified through {@link ProxyInvocationHandler # type()}.
*
* @param target
* @param objectName
* @return
* @throws Exception
*/
@Override
public ProxyInvocationHandler parserInterfaceToProxy(Object target, String objectName) throws Exception {
List<ProxyInvocationHandler> invocationHandlerList = new ArrayList<>();
Set<String> invocationHandlerRepeatCheck = new HashSet<>();

for (InterfaceParser interfaceParser : ALL_INTERFACE_PARSERS) {
ProxyInvocationHandler proxyInvocationHandler = interfaceParser.parserInterfaceToProxy(target, objectName);
if (proxyInvocationHandler != null) {
return proxyInvocationHandler;
if (!invocationHandlerRepeatCheck.add(proxyInvocationHandler.type())) {
throw new RuntimeException("there is already an annotation of type " + proxyInvocationHandler.type() + " for class: " + target.getClass().getName());
}
invocationHandlerList.add(proxyInvocationHandler);
}
}
return null;

Collections.sort(invocationHandlerList, Comparator.comparingInt(ProxyInvocationHandler::order));

ProxyInvocationHandler first = null;
ProxyInvocationHandler last = null;
for (ProxyInvocationHandler proxyInvocationHandler : invocationHandlerList) {
if (first == null) {
first = proxyInvocationHandler;
}
if (last != null) {
last.setNextProxyInvocationHandler(proxyInvocationHandler);
}
last = proxyInvocationHandler;
}

return first;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;

import org.apache.seata.common.ConfigurationKeys;
import org.apache.seata.common.util.CollectionUtils;
import org.apache.seata.common.util.ReflectionUtil;
Expand All @@ -31,7 +30,6 @@
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.apache.seata.tm.api.FailureHandlerHolder;


public class GlobalTransactionalInterceptorParser implements InterfaceParser {

protected final Set<String> methodsToProxy = new HashSet<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.seata.common.Constants;
import org.apache.seata.common.DefaultValues;
import org.apache.seata.common.holder.ObjectHolder;
Expand All @@ -31,17 +30,16 @@
import org.apache.seata.core.model.BranchType;
import org.apache.seata.integration.tx.api.fence.config.CommonFenceConfig;
import org.apache.seata.integration.tx.api.interceptor.ActionInterceptorHandler;
import org.apache.seata.integration.tx.api.interceptor.InvocationHandlerType;
import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
import org.apache.seata.integration.tx.api.interceptor.SeataInterceptorPosition;
import org.apache.seata.integration.tx.api.interceptor.TwoPhaseBusinessActionParam;
import org.apache.seata.integration.tx.api.interceptor.handler.AbstractProxyInvocationHandler;
import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.slf4j.MDC;

import static org.apache.seata.common.ConfigurationKeys.TCC_ACTION_INTERCEPTOR_ORDER;
import static org.apache.seata.common.Constants.BEAN_NAME_SPRING_FENCE_CONFIG;


public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler {

private static final int ORDER_NUM = ConfigurationFactory.getInstance().getInt(TCC_ACTION_INTERCEPTOR_ORDER,
Expand Down Expand Up @@ -167,4 +165,13 @@ public SeataInterceptorPosition getPosition() {
return SeataInterceptorPosition.Any;
}

@Override
public int order() {
return 1;
}

@Override
public String type() {
return InvocationHandlerType.TwoPhaseAnnotation.name();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

import org.apache.seata.common.util.ReflectionUtil;
import org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler;
import org.apache.seata.integration.tx.api.interceptor.parser.DefaultResourceRegisterParser;
Expand All @@ -34,7 +33,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class TccActionInterceptorParser implements InterfaceParser {

private static final Logger LOGGER = LoggerFactory.getLogger(TccActionInterceptorParser.class);
Expand Down
Loading

0 comments on commit 1939a9f

Please sign in to comment.