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

feature: TCC mode supports tcc annotation marked on both interface and implementation class #4479

Merged
Merged
Expand Up @@ -120,25 +120,25 @@ public Object invoke(final MethodInvocation invocation) throws Throwable {
* @return the action interface method
*/
protected Method getActionInterfaceMethod(MethodInvocation invocation) {
Class<?> interfaceType = null;
Class<?> serviceType = null;
try {
if (remotingDesc == null) {
interfaceType = getProxyInterface(invocation.getThis());
serviceType = getProxyInterface(invocation.getThis());
} else {
interfaceType = remotingDesc.getInterfaceClass();
serviceType = remotingDesc.getServiceClass();
}
if (interfaceType == null && remotingDesc != null && remotingDesc.getInterfaceClassName() != null) {
interfaceType = Class.forName(remotingDesc.getInterfaceClassName(), true,
if (serviceType == null && remotingDesc != null && remotingDesc.getServiceClassName() != null) {
serviceType = Class.forName(remotingDesc.getServiceClassName(), true,
Thread.currentThread().getContextClassLoader());
}
if (interfaceType == null) {
if (serviceType == null) {
return invocation.getMethod();
}
return interfaceType.getMethod(invocation.getMethod().getName(),
return serviceType.getMethod(invocation.getMethod().getName(),
invocation.getMethod().getParameterTypes());
} catch (NoSuchMethodException e) {
if (interfaceType != null && !"toString".equals(invocation.getMethod().getName())) {
LOGGER.warn("no such method '{}' from interface {}", invocation.getMethod().getName(), interfaceType.getName());
if (serviceType != null && !"toString".equals(invocation.getMethod().getName())) {
LOGGER.warn("no such method '{}' from interface {}", invocation.getMethod().getName(), serviceType.getName());
}
return invocation.getMethod();
} catch (Exception e) {
Expand Down
Expand Up @@ -90,21 +90,21 @@ protected void process(Object bean, String beanName, Class<? extends Annotation>
* @param bean the bean
* @param beanName the bean name
* @param field the field
* @param interfaceClass the interface class
* @param serviceClass the serviceClass
* @throws IllegalAccessException the illegal access exception
*/
public void addTccAdvise(Object bean, String beanName, Field field, Class interfaceClass) throws IllegalAccessException {
public void addTccAdvise(Object bean, String beanName, Field field, Class serviceClass) throws IllegalAccessException {
Object fieldValue = field.get(bean);
if (fieldValue == null) {
return;
}
for (Method method : field.getType().getMethods()) {
if (!Modifier.isStatic(method.getModifiers()) && (method.isAnnotationPresent(TwoPhaseBusinessAction.class))) {
RemotingDesc remotingDesc = new RemotingDesc();
remotingDesc.setInterfaceClass(interfaceClass);
remotingDesc.setServiceClass(serviceClass);

TccActionInterceptor actionInterceptor = new TccActionInterceptor(remotingDesc);
Object proxyBean = TCCBeanParserUtils.createProxy(interfaceClass, fieldValue, actionInterceptor);
Object proxyBean = TCCBeanParserUtils.createProxy(serviceClass, fieldValue, actionInterceptor);
field.setAccessible(true);
field.set(bean, proxyBean);
LOGGER.info("Bean[" + bean.getClass().getName() + "] with name [" + field.getName() + "] would use proxy [" + actionInterceptor.getClass().getName() + "]");
Expand Down
Expand Up @@ -113,8 +113,8 @@ public static boolean isTccProxyTargetBean(RemotingDesc remotingDesc) {
}
//check if it is TCC bean
boolean isTccClazz = false;
Class<?> tccInterfaceClazz = remotingDesc.getInterfaceClass();
Method[] methods = tccInterfaceClazz.getMethods();
Class<?> tccServiceClazz = remotingDesc.getServiceClass();
Method[] methods = tccServiceClazz.getMethods();
TwoPhaseBusinessAction twoPhaseBusinessAction;
for (Method method : methods) {
twoPhaseBusinessAction = method.getAnnotation(TwoPhaseBusinessAction.class);
Expand Down Expand Up @@ -151,8 +151,8 @@ public static void initTccFenceCleanTask(RemotingDesc remotingDesc, ApplicationC
if (tccFenceConfig == null || tccFenceConfig.getInitialized().get()) {
return;
}
Class<?> tccInterfaceClazz = remotingDesc.getInterfaceClass();
Method[] methods = tccInterfaceClazz.getMethods();
Class<?> tccServiceClazz = remotingDesc.getServiceClass();
Method[] methods = tccServiceClazz.getMethods();
for (Method method : methods) {
TwoPhaseBusinessAction twoPhaseBusinessAction = method.getAnnotation(TwoPhaseBusinessAction.class);
if (twoPhaseBusinessAction != null && twoPhaseBusinessAction.useTCCFence()) {
Expand Down
6 changes: 4 additions & 2 deletions tcc/pom.xml
Expand Up @@ -39,6 +39,10 @@
<artifactId>seata-rm</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
Expand All @@ -48,6 +52,4 @@
<artifactId>fastjson</artifactId>
</dependency>
</dependencies>


</project>
41 changes: 21 additions & 20 deletions tcc/src/main/java/io/seata/rm/tcc/remoting/RemotingDesc.java
Expand Up @@ -33,14 +33,14 @@ public class RemotingDesc {
private Object targetBean;

/**
* the tcc interface tyep
* the tcc serviceClass type
*/
private Class<?> interfaceClass;
private Class<?> serviceClass;

/**
* interface class name
* serviceClass name
*/
private String interfaceClassName;
private String serviceClassName;

/**
* rpc uniqueId: hsf, dubbo's version, sofa-rpc's uniqueId
Expand Down Expand Up @@ -76,39 +76,39 @@ public void setTargetBean(Object targetBean) {
}

/**
* Gets interface class.
* Gets serviceClass.
*
* @return the interface class
* @return the serviceClass
*/
public Class<?> getInterfaceClass() {
return interfaceClass;
public Class<?> getServiceClass() {
return serviceClass;
}

/**
* Sets interface class.
* Sets serviceClass.
*
* @param interfaceClass the interface class
* @param serviceClass the serviceClass
*/
public void setInterfaceClass(Class<?> interfaceClass) {
this.interfaceClass = interfaceClass;
public void setServiceClass(Class<?> serviceClass) {
this.serviceClass = serviceClass;
}

/**
* Gets interface class name.
* Gets serviceClass name.
*
* @return the interface class name
* @return the serviceClass name
*/
public String getInterfaceClassName() {
return interfaceClassName;
public String getServiceClassName() {
return serviceClassName;
}

/**
* Sets interface class name.
* Sets serviceClass name.
*
* @param interfaceClassName the interface class name
* @param serviceClassName the serviceClass name
*/
public void setInterfaceClassName(String interfaceClassName) {
this.interfaceClassName = interfaceClassName;
public void setServiceClassName(String serviceClassName) {
this.serviceClassName = serviceClassName;
}

/**
Expand Down Expand Up @@ -182,4 +182,5 @@ public boolean isReference() {
public void setReference(boolean reference) {
isReference = reference;
}

}
Expand Up @@ -170,8 +170,8 @@ public RemotingDesc parserRemotingServiceInfo(Object bean, String beanName, Remo
}
remotingServiceMap.put(beanName, remotingBeanDesc);

Class<?> interfaceClass = remotingBeanDesc.getInterfaceClass();
Method[] methods = interfaceClass.getMethods();
Class<?> serviceClass = remotingBeanDesc.getServiceClass();
Method[] methods = serviceClass.getMethods();
if (remotingParser.isService(bean, beanName)) {
try {
//service bean, registry resource
Expand All @@ -184,10 +184,10 @@ public RemotingDesc parserRemotingServiceInfo(Object bean, String beanName, Remo
tccResource.setTargetBean(targetBean);
tccResource.setPrepareMethod(m);
tccResource.setCommitMethodName(twoPhaseBusinessAction.commitMethod());
tccResource.setCommitMethod(interfaceClass.getMethod(twoPhaseBusinessAction.commitMethod(),
tccResource.setCommitMethod(serviceClass.getMethod(twoPhaseBusinessAction.commitMethod(),
twoPhaseBusinessAction.commitArgsClasses()));
tccResource.setRollbackMethodName(twoPhaseBusinessAction.rollbackMethod());
tccResource.setRollbackMethod(interfaceClass.getMethod(twoPhaseBusinessAction.rollbackMethod(),
tccResource.setRollbackMethod(serviceClass.getMethod(twoPhaseBusinessAction.rollbackMethod(),
twoPhaseBusinessAction.rollbackArgsClasses()));
// set argsClasses
tccResource.setCommitArgsClasses(twoPhaseBusinessAction.commitArgsClasses());
Expand Down
Expand Up @@ -52,8 +52,8 @@ public RemotingDesc getServiceDesc(Object bean, String beanName) throws Framewor
String interfaceClassName = (String)ReflectionUtil.getFieldValue(bean, "interfaceName");
String version = (String)ReflectionUtil.invokeMethod(bean, "getVersion");
String group = (String)ReflectionUtil.invokeMethod(bean, "getGroup");
serviceBeanDesc.setInterfaceClass(interfaceClass);
serviceBeanDesc.setInterfaceClassName(interfaceClassName);
serviceBeanDesc.setServiceClass(interfaceClass);
serviceBeanDesc.setServiceClassName(interfaceClassName);
serviceBeanDesc.setUniqueId(version);
serviceBeanDesc.setGroup(group);
serviceBeanDesc.setProtocol(Protocols.DUBBO);
Expand Down
Expand Up @@ -80,8 +80,8 @@ public RemotingDesc getServiceDesc(Object bean, String beanName) throws Framewor
String group = (String) ReflectionUtil.invokeMethod(metadata, "getGroup");

RemotingDesc serviceBeanDesc = new RemotingDesc();
serviceBeanDesc.setInterfaceClass(interfaceClass);
serviceBeanDesc.setInterfaceClassName(interfaceClassName);
serviceBeanDesc.setServiceClass(interfaceClass);
serviceBeanDesc.setServiceClassName(interfaceClassName);
serviceBeanDesc.setUniqueId(uniqueId);
serviceBeanDesc.setGroup(group);
serviceBeanDesc.setProtocol(Protocols.HSF);
Expand All @@ -95,8 +95,8 @@ public RemotingDesc getServiceDesc(Object bean, String beanName) throws Framewor
String uniqueId = (String) ReflectionUtil.invokeMethod(metadata, "getVersion");
String group = (String) ReflectionUtil.invokeMethod(metadata, "getGroup");
RemotingDesc serviceBeanDesc = new RemotingDesc();
serviceBeanDesc.setInterfaceClass(interfaceClass);
serviceBeanDesc.setInterfaceClassName(interfaceClassName);
serviceBeanDesc.setServiceClass(interfaceClass);
serviceBeanDesc.setServiceClassName(interfaceClassName);
serviceBeanDesc.setUniqueId(uniqueId);
serviceBeanDesc.setGroup(group);

Expand Down
Expand Up @@ -22,6 +22,7 @@
import io.seata.rm.tcc.api.LocalTCC;
import io.seata.rm.tcc.remoting.Protocols;
import io.seata.rm.tcc.remoting.RemotingDesc;
import org.springframework.aop.framework.AopProxyUtils;

/**
* local tcc bean parsing
Expand Down Expand Up @@ -49,11 +50,19 @@ public RemotingDesc getServiceDesc(Object bean, String beanName) throws Framewor
remotingDesc.setReference(true);
remotingDesc.setProtocol(Protocols.IN_JVM);
Class<?> classType = bean.getClass();
// check if LocalTCC annotation is marked on the implementation class
if (classType.isAnnotationPresent(LocalTCC.class)) {
remotingDesc.setServiceClass(AopProxyUtils.ultimateTargetClass(bean));
remotingDesc.setServiceClassName(remotingDesc.getServiceClass().getName());
remotingDesc.setTargetBean(bean);
return remotingDesc;
}
wangliang181230 marked this conversation as resolved.
Show resolved Hide resolved
// check if LocalTCC annotation is marked on the interface
Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(classType);
for (Class<?> interClass : interfaceClasses) {
if (interClass.isAnnotationPresent(LocalTCC.class)) {
remotingDesc.setInterfaceClassName(interClass.getName());
remotingDesc.setInterfaceClass(interClass);
remotingDesc.setServiceClassName(interClass.getName());
remotingDesc.setServiceClass(interClass);
remotingDesc.setTargetBean(bean);
return remotingDesc;
}
Expand All @@ -67,7 +76,7 @@ public short getProtocol() {
}

/**
* Determine whether there is an annotation {@link LocalTCC}
* Determine whether there is an annotation on interface or impl {@link LocalTCC}
* @param bean the bean
* @return boolean
*/
Expand All @@ -79,6 +88,6 @@ private boolean isLocalTCC(Object bean) {
return true;
}
}
return false;
return classType.isAnnotationPresent(LocalTCC.class);
}
}
Expand Up @@ -52,8 +52,8 @@ public RemotingDesc getServiceDesc(Object bean, String beanName) throws Framewor
Class<?> interfaceClass = (Class<?>)ReflectionUtil.invokeMethod(bean, "getInterfaceClass");
String interfaceClassName = (String)ReflectionUtil.getFieldValue(bean, "interfaceType");
String uniqueId = (String)ReflectionUtil.getFieldValue(bean, "uniqueId");
serviceBeanDesc.setInterfaceClass(interfaceClass);
serviceBeanDesc.setInterfaceClassName(interfaceClassName);
serviceBeanDesc.setServiceClass(interfaceClass);
serviceBeanDesc.setServiceClassName(interfaceClassName);
serviceBeanDesc.setUniqueId(uniqueId);
serviceBeanDesc.setProtocol(Protocols.SOFA_RPC);
if (isService(bean, beanName)) {
Expand Down
Expand Up @@ -66,8 +66,8 @@ public void testServiceDesc(){
RemotingDesc remotingDesc = localTCCRemotingParser.getServiceDesc(tccAction, "c");
Assertions.assertNotNull(remotingDesc);

Assertions.assertEquals("io.seata.rm.tcc.TccAction", remotingDesc.getInterfaceClassName());
Assertions.assertEquals(remotingDesc.getInterfaceClass(), TccAction.class);
Assertions.assertEquals("io.seata.rm.tcc.TccAction", remotingDesc.getServiceClassName());
Assertions.assertEquals(remotingDesc.getServiceClass(), TccAction.class);
Assertions.assertEquals(remotingDesc.getTargetBean(), tccAction);
}

Expand Down