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

bugfix: fix the failure of @BusinessActionContextParamete annotation … #6475

Open
wants to merge 7 commits into
base: 2.x
Choose a base branch
from
4 changes: 4 additions & 0 deletions changes/en-us/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ Add changes here for all PR submitted to the 2.x branch.
- [[#6385](https://github.com/apache/incubator-seata/pull/6385)] fix the bug where Role.participant does not execute hooks but clears them.
- [[#6465](https://github.com/apache/incubator-seata/pull/6465)] fix(6257): fix saga mode replay context lost start in 2.x
- [[#6469](https://github.com/apache/incubator-seata/pull/6469)] fix Error in insert sql of [lock_table] data table to sqlserver database
- [[#6475](https://github.com/apache/incubator-seata/pull/6475)] fix the failure of @BusinessActionContextParamete annotation to set parameters into io.seata.rm.tcc.api.BusinessActionContext at TCC mode.
- [[#6492](https://github.com/apache/incubator-seata/pull/6492)] fix XA did not rollback but close when executing a long-running SQL(or deadlock SQL)
- [[#6497](https://github.com/apache/incubator-seata/pull/6497)] fix tcc properties class when autoconfigure



### optimize:
- [[#6031](https://github.com/apache/incubator-seata/pull/6031)] add a check for the existence of the undolog table
- [[#6089](https://github.com/apache/incubator-seata/pull/6089)] modify the semantics of RaftServerFactory and remove unnecessary singleton
Expand Down Expand Up @@ -191,8 +193,10 @@ Thanks to these contributors for their code commits. Please report an unintended
- [yixia](https://github.com/wt-better)
- [MikhailNavitski](https://github.com/MikhailNavitski)
- [deung](https://github.com/deung)
- [TakeActionNow2019](https://github.com/TakeActionNow2019)
- [tanyaofei](https://github.com/tanyaofei)
- [xjlgod](https://github.com/xjlgod)



Also, we receive many valuable issues, questions and advices from our community. Thanks for you all.
4 changes: 4 additions & 0 deletions changes/zh-cn/2.x.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@
- [[#6385](https://github.com/apache/incubator-seata/pull/6385)] 修复Role.Participant不执行hook但会清理的问题
- [[#6465](https://github.com/apache/incubator-seata/pull/6465)] 修复2.0下saga模式的context replay丢失start问题
- [[#6469](https://github.com/apache/incubator-seata/pull/6469)] 修复在sqlserver数据库下[lock_table]数据表的插入操作sql中存在的错误
- [[#6475](https://github.com/apache/incubator-seata/pull/6475)] 修复TCC模式@BusinessActionContextParamete注解无法将参数设置到BusinessActionContext的问题
- [[#6492](https://github.com/apache/incubator-seata/pull/6492)] 修复XA执行长时间SQL(或死锁SQL)没有完成回滚就释放连接
- [[#6497](https://github.com/apache/incubator-seata/pull/6497)] 修复自动装配时的seata tcc 配置类



### optimize:
- [[#6031](https://github.com/apache/incubator-seata/pull/6031)] 添加undo_log表的存在性校验
- [[#6089](https://github.com/apache/incubator-seata/pull/6089)] 修改RaftServerFactory语义并删除不必要的单例构建
Expand Down Expand Up @@ -188,8 +190,10 @@
- [yixia](https://github.com/wt-better)
- [MikhailNavitski](https://github.com/MikhailNavitski)
- [deung](https://github.com/deung)
- [TakeActionNow2019](https://github.com/TakeActionNow2019)
- [tanyaofei](https://github.com/tanyaofei)
- [xjlgod](https://github.com/xjlgod)



同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* 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.spring.tcc;
funky-eyes marked this conversation as resolved.
Show resolved Hide resolved

import org.aopalliance.intercept.MethodInvocation;
import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
import org.apache.seata.rm.tcc.api.BusinessActionContext;
import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction;
import org.apache.seata.rm.tcc.interceptor.TccActionInterceptorHandler;
import org.apache.seata.spring.annotation.AdapterInvocationWrapper;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.HashSet;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;


class TccActionInterceptorHandlerTest {

protected TccActionInterceptorHandler tccActionInterceptorHandler = new TccActionInterceptorHandler(
null,
new HashSet<String>() {{
add("prepare");
}}
);

/**
* Test method "parseAnnotation" of TccActionInterceptorHandler
*
* @throws Throwable
*/
@Test
void testParseAnnotation() throws Throwable {
// mock MethodInvocation
NormalTccActionImpl tccAction = new NormalTccActionImpl();
Method classMethod = NormalTccActionImpl.class.getMethod("prepare", BusinessActionContext.class);
MethodInvocation mockInvocation = mock(MethodInvocation.class);
when(mockInvocation.getMethod()).thenReturn(classMethod);
when(mockInvocation.getArguments()).thenReturn(new Object[]{new BusinessActionContext()});
when(mockInvocation.proceed()).thenAnswer(invocation -> classMethod.invoke(tccAction, mockInvocation.getArguments()));

// mock AdapterInvocationWrapper
AdapterInvocationWrapper invocationWrapper = new AdapterInvocationWrapper(mockInvocation);
when(invocationWrapper.getTarget()).thenReturn(tccAction);

// invoke private method "parseAnnotation" of TccActionInterceptorHandler
Method method = TccActionInterceptorHandler.class.getDeclaredMethod("parseAnnotation", InvocationWrapper.class);
method.setAccessible(true);
Object[] results = (Object[]) method.invoke(tccActionInterceptorHandler, invocationWrapper);
System.out.println(results);

// test results
Method interfaceMethod = NormalTccAction.class.getMethod("prepare", BusinessActionContext.class);
Assertions.assertEquals(interfaceMethod, results[0]);
Assertions.assertEquals(true, results[1] instanceof TwoPhaseBusinessAction);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
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.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;


Expand All @@ -46,6 +48,8 @@

public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler {

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

private static final int ORDER_NUM = ConfigurationFactory.getInstance().getInt(TCC_ACTION_INTERCEPTOR_ORDER,
DefaultValues.TCC_ACTION_INTERCEPTOR_ORDER);

Expand All @@ -54,7 +58,7 @@ public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler
private Set<String> methodsToProxy;
protected Object targetBean;

protected Map<Method, Annotation> parseAnnotationCache = new ConcurrentHashMap<>();
protected Map<Method, Object[]> parseAnnotationCache = new ConcurrentHashMap<>();

public TccActionInterceptorHandler(Object targetBean, Set<String> methodsToProxy) {
this.targetBean = targetBean;
Expand All @@ -67,8 +71,10 @@ protected Object doInvoke(InvocationWrapper invocation) throws Throwable {
//not in transaction, or this interceptor is disabled
return invocation.proceed();
}
Method method = invocation.getMethod();
Annotation businessAction = parseAnnotation(method);

Object[] methodAndAnnotation = parseAnnotation(invocation);
Method method = (Method) methodAndAnnotation[0];
Annotation businessAction = (Annotation) methodAndAnnotation[1];

//try method
if (businessAction != null) {
Expand Down Expand Up @@ -99,30 +105,41 @@ protected Object doInvoke(InvocationWrapper invocation) throws Throwable {
return invocation.proceed();
}

private Annotation parseAnnotation(Method methodKey) throws NoSuchMethodException {
Annotation result = parseAnnotationCache.computeIfAbsent(methodKey, method -> {
/**
* Get try method and the corresponding annotation of TCC mode.
*
* @param invocation
* @return
*/
private Object[] parseAnnotation(InvocationWrapper invocation) {
Object[] results = parseAnnotationCache.computeIfAbsent(invocation.getMethod(), method -> {
Annotation twoPhaseBusinessAction = method.getAnnotation(getAnnotationClass());
if (twoPhaseBusinessAction == null && targetBean.getClass() != null) {
Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(targetBean.getClass());
Method tryMethod = method;
if (twoPhaseBusinessAction == null && invocation.getTarget() != null) {
Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(invocation.getTarget().getClass());
if (interfaceClasses != null) {
for (Class<?> interClass : interfaceClasses) {
try {
Method m = interClass.getMethod(method.getName(), method.getParameterTypes());
twoPhaseBusinessAction = m.getAnnotation(getAnnotationClass());
if (twoPhaseBusinessAction != null) {
// init common fence clean task if enable useTccFence
initCommonFenceCleanTask(twoPhaseBusinessAction);
tryMethod = m;
break;
}
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
LOGGER.debug(method.getName() + ", no such method found", e);
}
}
}
}
return twoPhaseBusinessAction;
if (twoPhaseBusinessAction == null) {
throw new RuntimeException("No such method with annotation" + getAnnotationClass());
}
// init common fence clean task if enable useTccFence
initCommonFenceCleanTask(twoPhaseBusinessAction);
return new Object[] {tryMethod, twoPhaseBusinessAction};
});
return result;
return results;
}

protected TwoPhaseBusinessActionParam createTwoPhaseBusinessActionParam(Annotation annotation) {
Expand Down
Loading