This is an automated email from the ASF dual-hosted git repository. jianbin pushed a commit to branch 2.x in repository https://gitbox.apache.org/repos/asf/incubator-seata.git
The following commit(s) were added to refs/heads/2.x by this push: new 167984918d optimize: branch register resource only at RM server end (#5399) 167984918d is described below commit 167984918d4f0ea887ce0680bd69edfe51132ba0 Author: sunrui1225 <srs_1...@163.com> AuthorDate: Mon Jan 8 13:58:44 2024 +0800 optimize: branch register resource only at RM server end (#5399) --- changes/en-us/2.x.md | 3 + changes/zh-cn/2.x.md | 5 +- .../interceptor/parser/DefaultInterfaceParser.java | 12 +++ .../GlobalTransactionalInterceptorParser.java | 14 +++ ...InterfaceParser.java => IfNeedEnhanceBean.java} | 69 ++++++++------ .../tx/api/interceptor/parser/InterfaceParser.java | 2 + .../{InterfaceParser.java => NeedEnhanceEnum.java} | 58 ++++++------ .../tx/api/remoting/RemotingParser.java | 9 ++ .../api/remoting/parser/DefaultRemotingParser.java | 15 +++ .../api/remoting/parser/DubboRemotingParser.java | 6 ++ .../tx/api/remoting/parser/HSFRemotingParser.java | 6 ++ .../api/remoting/parser/SofaRpcRemotingParser.java | 6 ++ .../seata/integration/tx/api/util/ProxyUtil.java | 15 +++ .../java/io/seata/rm/fence/SpringFenceHandler.java | 12 ++- .../annotation/GlobalTransactionScanner.java | 74 +++++++++++++++ .../remoting/parser/RemotingFactoryBeanParser.java | 5 + .../interceptor/TccActionInterceptorHandler.java | 11 +-- .../parser/TccActionInterceptorParser.java | 64 ++++++------- .../remoting/parser/LocalTCCRemotingParser.java | 9 ++ .../resource/parser/TccRegisterResourceParser.java | 102 +++++++++------------ 20 files changed, 342 insertions(+), 155 deletions(-) diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md index 64b45f46e3..240fcf7dec 100644 --- a/changes/en-us/2.x.md +++ b/changes/en-us/2.x.md @@ -39,6 +39,7 @@ Add changes here for all PR submitted to the 2.x branch. - [[#6184](https://github.com/apache/incubator-seata/pull/6184)] update NOTICE file - [[#6192](https://github.com/apache/incubator-seata/pull/6192)] remove the useless file - [[#6194](https://github.com/apache/incubator-seata/pull/6194)] fix asf.yaml parse error +- [[#5399](https://github.com/apache/incubator-seata/pull/5399)] optimizing branch register resource only at RM server end - [[#6154](https://github.com/apache/incubator-seata/pull/6154)] console log optimize for "kubectl logs -f" - [[#6116](https://github.com/apache/incubator-seata/pull/6116)] rewrite NettyPoolKey's hashcode and equals to fix duplicate construction of channel object pools - [[#6195](https://github.com/apache/incubator-seata/pull/6195)] update the url in change log to apache/incubator-seata @@ -78,10 +79,12 @@ Thanks to these contributors for their code commits. Please report an unintended - [lightClouds917](https://github.com/lightClouds917) - [xingfudeshi](https://github.com/xingfudeshi) - [PleaseGiveMeTheCoke](https://github.com/PleaseGiveMeTheCoke) +- [sunrui1225](https://github.com/sunrui1225) - [PeppaO](https://github.com/PeppaO) - [AlbumenJ](https://github.com/AlbumenJ) - [dreamskyvision](https://github.com/dreamskyvision) - [jsbxyyx](https://github.com/jsbxyyx) - [liuqiufeng](https://github.com/liuqiufeng) + Also, we receive many valuable issues, questions and advices from our community. Thanks for you all. diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md index 84fe561a2f..55f930c8ff 100644 --- a/changes/zh-cn/2.x.md +++ b/changes/zh-cn/2.x.md @@ -38,7 +38,7 @@ - [[#6184](https://github.com/apache/incubator-seata/pull/6184)] 更新NOTICE文件 - [[#6192](https://github.com/apache/incubator-seata/pull/6192)] 移除无用文件 - [[#6194](https://github.com/apache/incubator-seata/pull/6194)] 修复 asf.yaml 解析错误问题 -- [[#6116](https://github.com/apache/incubator-seata/pull/6116)] 重写NettyPoolKey的hashcode和equals,修复了channel对象池重复构建问题 +- [[#5399](https://github.com/apache/incubator-seata/pull/5399)] 分支注册只在RM端 - [[#6154](https://github.com/apache/incubator-seata/pull/6154)] 控制台日志优化 "kubectl logs -f" - [[#6116](https://github.com/apache/incubator-seata/pull/6116)] 重写NettyPoolKey的hashcode和equals,修复了channel对象池重复构建问题 - [[#6195](https://github.com/apache/incubator-seata/pull/6195)] 更新 change log 中的 seata url 为 apache/incubator-seata @@ -49,6 +49,7 @@ - [[#6004](https://github.com/apache/incubator-seata/pull/6004)] 优化RM,TM连接server快速失败 - [[#6243](https://github.com/apache/incubator-seata/pull/6243)] 优化控制台页眉中的链接 + ### security: - [[#6069](https://github.com/apache/incubator-seata/pull/6069)] 升级Guava依赖版本,修复安全漏洞 - [[#6144](https://github.com/apache/incubator-seata/pull/6144)] 升级Nacos依赖版本至1.4.6 @@ -78,10 +79,12 @@ - [lightClouds917](https://github.com/lightClouds917) - [xingfudeshi](https://github.com/xingfudeshi) - [PleaseGiveMeTheCoke](https://github.com/PleaseGiveMeTheCoke) +- [sunrui1225](https://github.com/sunrui1225) - [PeppaO](https://github.com/PeppaO) - [AlbumenJ](https://github.com/AlbumenJ) - [dreamskyvision](https://github.com/dreamskyvision) - [jsbxyyx](https://github.com/jsbxyyx) - [liuqiufeng](https://github.com/liuqiufeng) + 同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。 diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java index 89f8499db8..7474ef4a6d 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/DefaultInterfaceParser.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.List; /** + * @author leezongjie */ public class DefaultInterfaceParser implements InterfaceParser { @@ -63,4 +64,15 @@ public class DefaultInterfaceParser implements InterfaceParser { return null; } + @Override + public IfNeedEnhanceBean parseIfNeedEnhancement(Class<?> beanClass) { + for (InterfaceParser interfaceParser : ALL_INTERFACE_PARSERS) { + IfNeedEnhanceBean ifNeedEnhanceBean = interfaceParser.parseIfNeedEnhancement(beanClass); + if (ifNeedEnhanceBean.isIfNeed()) { + return ifNeedEnhanceBean; + } + } + return new IfNeedEnhanceBean(); + } + } diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java index 5bb44043b8..9b01e92a2f 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/GlobalTransactionalInterceptorParser.java @@ -22,6 +22,7 @@ import java.util.Set; import io.seata.common.ConfigurationKeys; import io.seata.common.util.CollectionUtils; +import io.seata.common.util.ReflectionUtil; import io.seata.config.ConfigurationCache; import io.seata.config.ConfigurationChangeListener; import io.seata.integration.tx.api.interceptor.handler.GlobalTransactionalInterceptorHandler; @@ -59,6 +60,19 @@ public class GlobalTransactionalInterceptorParser implements InterfaceParser { return null; } + @Override + public IfNeedEnhanceBean parseIfNeedEnhancement(Class<?> beanClass) { + Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(beanClass); + Class<?>[] interfaceClasseArray = interfaceClasses.toArray(new Class<?>[0]); + + IfNeedEnhanceBean ifNeedEnhanceBean = new IfNeedEnhanceBean(); + if (existsAnnotation(beanClass) || existsAnnotation(interfaceClasseArray)) { + ifNeedEnhanceBean.setIfNeed(true); + ifNeedEnhanceBean.setNeedEnhanceEnum(NeedEnhanceEnum.GLOBAL_TRANSACTIONAL_BEAN); + } + return ifNeedEnhanceBean; + } + private boolean existsAnnotation(Class<?>... classes) { boolean result = false; if (CollectionUtils.isNotEmpty(classes)) { diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/IfNeedEnhanceBean.java similarity index 63% copy from integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java copy to integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/IfNeedEnhanceBean.java index 23db3c4a2e..c0d1e91737 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/IfNeedEnhanceBean.java @@ -1,28 +1,41 @@ -/* - * 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.parser; - -import io.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; - -/** - */ -public interface InterfaceParser { - - ProxyInvocationHandler parserInterfaceToProxy(Object target, String objectName) throws Exception; - - -} +/* + * 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.parser; + +public class IfNeedEnhanceBean { + + private boolean ifNeed; + + private NeedEnhanceEnum needEnhanceEnum; + + public boolean isIfNeed() { + return ifNeed; + } + + public void setIfNeed(boolean ifNeed) { + this.ifNeed = ifNeed; + } + + public NeedEnhanceEnum getNeedEnhanceEnum() { + return needEnhanceEnum; + } + + public void setNeedEnhanceEnum(NeedEnhanceEnum needEnhanceEnum) { + this.needEnhanceEnum = needEnhanceEnum; + } + +} diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java index 23db3c4a2e..2584c6459e 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java @@ -24,5 +24,7 @@ public interface InterfaceParser { ProxyInvocationHandler parserInterfaceToProxy(Object target, String objectName) throws Exception; + IfNeedEnhanceBean parseIfNeedEnhancement(Class<?> beanClass); + } diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/NeedEnhanceEnum.java similarity index 79% copy from integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java copy to integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/NeedEnhanceEnum.java index 23db3c4a2e..7ac30889c7 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/InterfaceParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/interceptor/parser/NeedEnhanceEnum.java @@ -1,28 +1,30 @@ -/* - * 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.parser; - -import io.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; - -/** - */ -public interface InterfaceParser { - - ProxyInvocationHandler parserInterfaceToProxy(Object target, String objectName) throws Exception; - - -} +/* + * 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.parser; + + +public enum NeedEnhanceEnum { + + /** + * global transactional bean type + */ + GLOBAL_TRANSACTIONAL_BEAN, + /** + * service bean type + */ + SERVICE_BEAN; +} diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/RemotingParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/RemotingParser.java index 569f5749ad..71664b0542 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/RemotingParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/RemotingParser.java @@ -54,6 +54,15 @@ public interface RemotingParser { */ boolean isService(Object bean, String beanName) throws FrameworkException; + /** + * if it is service bean ? + * + * @param beanClass the bean class + * @return boolean boolean + * @throws FrameworkException the framework exception + */ + boolean isService(Class<?> beanClass) throws FrameworkException; + /** * get the remoting bean info * diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/DefaultRemotingParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/DefaultRemotingParser.java index f3f8eafab4..e1ca71b622 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/DefaultRemotingParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/DefaultRemotingParser.java @@ -132,6 +132,21 @@ public class DefaultRemotingParser { return false; } + /** + * is service bean ? + * + * @param beanClass the bean class + * @return boolean boolean + */ + public boolean isService(Class<?> beanClass) { + for (RemotingParser remotingParser : allRemotingParsers) { + if (remotingParser.isService(beanClass)) { + return true; + } + } + return false; + } + /** * get the remoting Service desc * diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/DubboRemotingParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/DubboRemotingParser.java index 681e096ad9..4014cd5e8c 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/DubboRemotingParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/DubboRemotingParser.java @@ -41,6 +41,12 @@ public class DubboRemotingParser extends AbstractedRemotingParser { || "org.apache.dubbo.config.spring.ServiceBean".equals(c.getName()); } + @Override + public boolean isService(Class<?> beanClass) throws FrameworkException { + return "com.alibaba.dubbo.config.spring.ServiceBean".equals(beanClass.getName()) + || "org.apache.dubbo.config.spring.ServiceBean".equals(beanClass.getName()); + } + @Override public RemotingDesc getServiceDesc(Object bean, String beanName) throws FrameworkException { if (!this.isRemoting(bean, beanName)) { diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/HSFRemotingParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/HSFRemotingParser.java index aa76a40353..4818f127d4 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/HSFRemotingParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/HSFRemotingParser.java @@ -64,6 +64,12 @@ public class HSFRemotingParser extends AbstractedRemotingParser { return isHsf && "com.taobao.hsf.app.spring.util.HSFSpringProviderBean".equals(beanClassName); } + @Override + public boolean isService(Class<?> beanClass) throws FrameworkException { + String beanClassName = beanClass.getName(); + return isHsf && "com.taobao.hsf.app.spring.util.HSFSpringProviderBean".equals(beanClassName); + } + @Override public RemotingDesc getServiceDesc(Object bean, String beanName) throws FrameworkException { if (!this.isRemoting(bean, beanName)) { diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/SofaRpcRemotingParser.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/SofaRpcRemotingParser.java index a5872ba133..4cb03f709d 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/SofaRpcRemotingParser.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/remoting/parser/SofaRpcRemotingParser.java @@ -42,6 +42,12 @@ public class SofaRpcRemotingParser extends AbstractedRemotingParser { return "com.alipay.sofa.runtime.spring.factory.ServiceFactoryBean".equals(beanClassName); } + @Override + public boolean isService(Class<?> beanClass) throws FrameworkException { + String beanClassName = beanClass.getName(); + return "com.alipay.sofa.runtime.spring.factory.ServiceFactoryBean".equals(beanClassName); + } + @Override public RemotingDesc getServiceDesc(Object bean, String beanName) throws FrameworkException { if (!this.isRemoting(bean, beanName)) { diff --git a/integration-tx-api/src/main/java/io/seata/integration/tx/api/util/ProxyUtil.java b/integration-tx-api/src/main/java/io/seata/integration/tx/api/util/ProxyUtil.java index 8588803384..9efbf8b0f0 100644 --- a/integration-tx-api/src/main/java/io/seata/integration/tx/api/util/ProxyUtil.java +++ b/integration-tx-api/src/main/java/io/seata/integration/tx/api/util/ProxyUtil.java @@ -37,6 +37,21 @@ public class ProxyUtil { return createProxy(target, target.getClass().getName()); } + /** + * The API for generating proxy for target. It can be used by spring aop, or + * provide user to generate proxy manually. + * <p> + * At TM side, It can be used for the target bean with @GlobalTransactional or @GlobalLock to generate proxy which start global transaction. + * At RM side, if you use TCC mode, It can be for target bean with @TwoPhaseBusinessAction to generate proxy which register branch source + * and branch transaction. If you want to use this API to generate proxy manual like dubbo, you must make sure the target bean is the + * business bean with @GlobalTransactional annotation. If you pass the ServiceBean(com.alibaba.dubbo.config.spring.ServiceBean) or + * ReferenceBean(com.alibaba.dubbo.config.spring.ReferenceBean), it will don't work. + * + * @param target the business bean + * @param beanName the business bean name + * @return the proxy bean + * @param <T> the generics class + */ public static <T> T createProxy(T target, String beanName) { try { synchronized (PROXYED_SET) { diff --git a/spring/src/main/java/io/seata/rm/fence/SpringFenceHandler.java b/spring/src/main/java/io/seata/rm/fence/SpringFenceHandler.java index 1fd56e7992..e657605432 100644 --- a/spring/src/main/java/io/seata/rm/fence/SpringFenceHandler.java +++ b/spring/src/main/java/io/seata/rm/fence/SpringFenceHandler.java @@ -163,7 +163,9 @@ public class SpringFenceHandler implements FenceHandler { } return false; } - return updateStatusAndInvokeTargetMethod(conn, commitMethod, targetTCCBean, xid, branchId, CommonFenceConstant.STATUS_COMMITTED, status, args); + boolean result = updateStatusAndInvokeTargetMethod(conn, commitMethod, targetTCCBean, xid, branchId, CommonFenceConstant.STATUS_COMMITTED, status, args); + LOGGER.info("Common fence commit result: {}. xid: {}, branchId: {}", result, xid, branchId); + return result; } catch (Throwable t) { status.setRollbackOnly(); throw new SkipCallbackWrapperException(t); @@ -210,7 +212,9 @@ public class SpringFenceHandler implements FenceHandler { return false; } } - return updateStatusAndInvokeTargetMethod(conn, rollbackMethod, targetTCCBean, xid, branchId, CommonFenceConstant.STATUS_ROLLBACKED, status, args); + boolean result = updateStatusAndInvokeTargetMethod(conn, rollbackMethod, targetTCCBean, xid, branchId, CommonFenceConstant.STATUS_ROLLBACKED, status, args); + LOGGER.info("Common fence rollback result: {}. xid: {}, branchId: {}", result, xid, branchId); + return result; } catch (Throwable t) { status.setRollbackOnly(); throw new SkipCallbackWrapperException(t); @@ -237,13 +241,13 @@ public class SpringFenceHandler implements FenceHandler { } /** - * Update TCC Fence status and invoke target method + * Update Common Fence status and invoke target method * * @param method target method * @param targetTCCBean target bean * @param xid the global transaction id * @param branchId the branch transaction id - * @param status the tcc fence status + * @param status the common fence status * @return the boolean */ private static boolean updateStatusAndInvokeTargetMethod(Connection conn, Method method, Object targetTCCBean, diff --git a/spring/src/main/java/io/seata/spring/annotation/GlobalTransactionScanner.java b/spring/src/main/java/io/seata/spring/annotation/GlobalTransactionScanner.java index f37b6117be..916d3dd1aa 100644 --- a/spring/src/main/java/io/seata/spring/annotation/GlobalTransactionScanner.java +++ b/spring/src/main/java/io/seata/spring/annotation/GlobalTransactionScanner.java @@ -25,6 +25,7 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import javax.annotation.Nullable; +import com.google.common.collect.ImmutableSet; import io.seata.common.util.CollectionUtils; import io.seata.common.util.StringUtils; import io.seata.config.ConfigurationCache; @@ -42,6 +43,8 @@ import io.seata.integration.tx.api.interceptor.SeataInterceptorPosition; import io.seata.integration.tx.api.interceptor.handler.GlobalTransactionalInterceptorHandler; import io.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; import io.seata.integration.tx.api.interceptor.parser.DefaultInterfaceParser; +import io.seata.integration.tx.api.interceptor.parser.IfNeedEnhanceBean; +import io.seata.integration.tx.api.interceptor.parser.NeedEnhanceEnum; import io.seata.integration.tx.api.remoting.parser.DefaultRemotingParser; import io.seata.rm.RMClient; import io.seata.spring.annotation.scannercheckers.PackageScannerChecker; @@ -62,10 +65,13 @@ import org.springframework.aop.framework.AdvisedSupport; import org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator; import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; +import org.springframework.beans.PropertyValue; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.ConfigurableApplicationContext; @@ -114,6 +120,8 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator private ApplicationContext applicationContext; + private static final Set<String> NEED_ENHANCE_BEAN_NAME_SET = new HashSet<>(); + /** * Instantiates a new Global transaction scanner. @@ -280,6 +288,9 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator if (PROXYED_SET.contains(beanName)) { return bean; } + if (!NEED_ENHANCE_BEAN_NAME_SET.contains(beanName)) { + return bean; + } interceptor = null; ProxyInvocationHandler proxyInvocationHandler = DefaultInterfaceParser.get().parserInterfaceToProxy(bean, beanName); if (proxyInvocationHandler == null) { @@ -469,8 +480,71 @@ public class GlobalTransactionScanner extends AbstractAutoProxyCreator if (initialized.compareAndSet(false, true)) { initClient(); } + + this.findBusinessBeanNamesNeededEnhancement(); } + private void findBusinessBeanNamesNeededEnhancement() { + if (applicationContext instanceof ConfigurableApplicationContext) { + ConfigurableApplicationContext configurableApplicationContext = (ConfigurableApplicationContext) applicationContext; + ConfigurableListableBeanFactory configurableListableBeanFactory = configurableApplicationContext.getBeanFactory(); + + String[] beanNames = applicationContext.getBeanDefinitionNames(); + for (String contextBeanName : beanNames) { + BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition(contextBeanName); + if (StringUtils.isBlank(beanDefinition.getBeanClassName())) { + continue; + } + if (IGNORE_ENHANCE_CHECK_SET.contains(beanDefinition.getBeanClassName())) { + continue; + } + try { + // get the class by bean definition class name + Class<?> beanClass = Class.forName(beanDefinition.getBeanClassName()); + // check if it needs enhancement by the class + IfNeedEnhanceBean ifNeedEnhanceBean = DefaultInterfaceParser.get().parseIfNeedEnhancement(beanClass); + if (!ifNeedEnhanceBean.isIfNeed()) { + continue; + } + if (ifNeedEnhanceBean.getNeedEnhanceEnum().equals(NeedEnhanceEnum.SERVICE_BEAN)) { + // the native bean which dubbo, sofa bean service bean referenced + PropertyValue propertyValue = beanDefinition.getPropertyValues().getPropertyValue("ref"); + if (propertyValue == null) { + // the native bean which HSF service bean referenced + propertyValue = beanDefinition.getPropertyValues().getPropertyValue("target"); + } + if (propertyValue != null) { + RuntimeBeanReference r = (RuntimeBeanReference) propertyValue.getValue(); + if (r != null && StringUtils.isNotBlank(r.getBeanName())) { + NEED_ENHANCE_BEAN_NAME_SET.add(r.getBeanName()); + continue; + } + } + // the native bean which local tcc service bean referenced + NEED_ENHANCE_BEAN_NAME_SET.add(contextBeanName); + } else if (ifNeedEnhanceBean.getNeedEnhanceEnum().equals(NeedEnhanceEnum.GLOBAL_TRANSACTIONAL_BEAN)) { + // global transactional bean + NEED_ENHANCE_BEAN_NAME_SET.add(contextBeanName); + } + } catch (ClassNotFoundException e) { + LOGGER.warn("check if need enhance bean error, it can be ignore", e); + } + } + LOGGER.info("The needed enhancement business beans are : {}", NEED_ENHANCE_BEAN_NAME_SET); + } + } + + private static final Set<String> IGNORE_ENHANCE_CHECK_SET = ImmutableSet.of( + "io.seata.spring.annotation.GlobalTransactionScanner" + , "io.seata.rm.fence.SpringFenceConfig" + , "org.springframework.context.annotation.internalConfigurationAnnotationProcessor" + , "org.springframework.context.annotation.internalAutowiredAnnotationProcessor" + , "org.springframework.context.annotation.internalCommonAnnotationProcessor" + , "org.springframework.context.event.internalEventListenerProcessor" + , "org.springframework.context.event.internalEventListenerFactory" + ); + + @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; diff --git a/spring/src/main/java/io/seata/spring/remoting/parser/RemotingFactoryBeanParser.java b/spring/src/main/java/io/seata/spring/remoting/parser/RemotingFactoryBeanParser.java index a5635fbbbf..052061e1c3 100644 --- a/spring/src/main/java/io/seata/spring/remoting/parser/RemotingFactoryBeanParser.java +++ b/spring/src/main/java/io/seata/spring/remoting/parser/RemotingFactoryBeanParser.java @@ -73,6 +73,11 @@ public class RemotingFactoryBeanParser extends AbstractedRemotingParser { return DefaultRemotingParser.get().isService(factoryBean, getFactoryBeanName(beanName)); } + @Override + public boolean isService(Class<?> beanClass) throws FrameworkException { + return false; + } + @Override public RemotingDesc getServiceDesc(Object bean, String beanName) throws FrameworkException { Object factoryBean = getRemotingFactoryBean(bean, beanName); diff --git a/tcc/src/main/java/io/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java b/tcc/src/main/java/io/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java index bbdffe0c7e..db611a8052 100644 --- a/tcc/src/main/java/io/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java +++ b/tcc/src/main/java/io/seata/rm/tcc/interceptor/TccActionInterceptorHandler.java @@ -35,7 +35,6 @@ import io.seata.integration.tx.api.interceptor.InvocationWrapper; import io.seata.integration.tx.api.interceptor.SeataInterceptorPosition; import io.seata.integration.tx.api.interceptor.TwoPhaseBusinessActionParam; import io.seata.integration.tx.api.interceptor.handler.AbstractProxyInvocationHandler; -import io.seata.integration.tx.api.remoting.RemotingDesc; import io.seata.rm.tcc.api.TwoPhaseBusinessAction; import org.slf4j.MDC; @@ -52,12 +51,12 @@ public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler private ActionInterceptorHandler actionInterceptorHandler = new ActionInterceptorHandler(); private Set<String> methodsToProxy; - private RemotingDesc remotingDesc; + private Object targetBean; private Map<Method, TwoPhaseBusinessAction> parseAnnotationCache = new ConcurrentHashMap<>(); - public TccActionInterceptorHandler(RemotingDesc remotingDesc, Set<String> methodsToProxy) { - this.remotingDesc = remotingDesc; + public TccActionInterceptorHandler(Object targetBean, Set<String> methodsToProxy) { + this.targetBean = targetBean; this.methodsToProxy = methodsToProxy; } @@ -113,8 +112,8 @@ public class TccActionInterceptorHandler extends AbstractProxyInvocationHandler private TwoPhaseBusinessAction parseAnnotation(Method methodKey) throws NoSuchMethodException { TwoPhaseBusinessAction result = parseAnnotationCache.computeIfAbsent(methodKey, method -> { TwoPhaseBusinessAction businessAction = method.getAnnotation(TwoPhaseBusinessAction.class); - if (businessAction == null && remotingDesc.getServiceClass() != null) { - Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(remotingDesc.getServiceClass()); + if (businessAction == null && targetBean.getClass() != null) { + Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(targetBean.getClass()); if (interfaceClasses != null) { for (Class<?> interClass : interfaceClasses) { try { diff --git a/tcc/src/main/java/io/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java b/tcc/src/main/java/io/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java index 6496df4a87..d28b6d3e2d 100644 --- a/tcc/src/main/java/io/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java +++ b/tcc/src/main/java/io/seata/rm/tcc/interceptor/parser/TccActionInterceptorParser.java @@ -16,61 +16,63 @@ */ package io.seata.rm.tcc.interceptor.parser; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + import io.seata.common.util.ReflectionUtil; -import io.seata.integration.tx.api.interceptor.TxBeanParserUtils; import io.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler; import io.seata.integration.tx.api.interceptor.parser.DefaultResourceRegisterParser; +import io.seata.integration.tx.api.interceptor.parser.IfNeedEnhanceBean; import io.seata.integration.tx.api.interceptor.parser.InterfaceParser; -import io.seata.integration.tx.api.remoting.RemotingDesc; +import io.seata.integration.tx.api.interceptor.parser.NeedEnhanceEnum; import io.seata.integration.tx.api.remoting.parser.DefaultRemotingParser; import io.seata.rm.tcc.api.TwoPhaseBusinessAction; import io.seata.rm.tcc.interceptor.TccActionInterceptorHandler; - -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** */ public class TccActionInterceptorParser implements InterfaceParser { + private static final Logger LOGGER = LoggerFactory.getLogger(TccActionInterceptorParser.class); + @Override public ProxyInvocationHandler parserInterfaceToProxy(Object target, String objectName) { - boolean isTxRemotingBean = TxBeanParserUtils.isTxRemotingBean(target, objectName); - if (isTxRemotingBean) { - RemotingDesc remotingDesc = DefaultRemotingParser.get().getRemotingBeanDesc(target); - if (remotingDesc != null) { - if (remotingDesc.isService()) { - DefaultResourceRegisterParser.get().registerResource(target, objectName); - } - if (remotingDesc.isReference()) { - //if it is a tcc remote reference - Set<String> methodsToProxy = tccProxyTargetMethod(remotingDesc); - if (remotingDesc != null && !methodsToProxy.isEmpty()) { - ProxyInvocationHandler proxyInvocationHandler = new TccActionInterceptorHandler(remotingDesc, methodsToProxy); - return proxyInvocationHandler; - } - } - } + // eliminate the bean without two phase annotation. + Set<String> methodsToProxy = this.tccProxyTargetMethod(target); + if (methodsToProxy.isEmpty()) { + return null; } - return null; + // register resource and enhance with interceptor + DefaultResourceRegisterParser.get().registerResource(target, objectName); + return new TccActionInterceptorHandler(target, methodsToProxy); + } + + @Override + public IfNeedEnhanceBean parseIfNeedEnhancement(Class<?> beanClass) { + IfNeedEnhanceBean ifNeedEnhanceBean = new IfNeedEnhanceBean(); + if (DefaultRemotingParser.get().isService(beanClass)) { + ifNeedEnhanceBean.setIfNeed(true); + ifNeedEnhanceBean.setNeedEnhanceEnum(NeedEnhanceEnum.SERVICE_BEAN); + } + return ifNeedEnhanceBean; } /** * is TCC proxy-bean/target-bean: LocalTCC , the proxy bean of sofa:reference/dubbo:reference * - * @param remotingDesc the remoting desc + * @param target the remoting desc * @return boolean boolean */ - private Set<String> tccProxyTargetMethod(RemotingDesc remotingDesc) { - if (!remotingDesc.isReference() || remotingDesc == null) { - return Collections.emptySet(); - } + + private Set<String> tccProxyTargetMethod(Object target) { Set<String> methodsToProxy = new HashSet<>(); //check if it is TCC bean - Class<?> tccServiceClazz = remotingDesc.getServiceClass(); + Class<?> tccServiceClazz = target.getClass(); Set<Method> methods = new HashSet<>(Arrays.asList(tccServiceClazz.getMethods())); Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(tccServiceClazz); if (interfaceClasses != null) { diff --git a/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/LocalTCCRemotingParser.java b/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/LocalTCCRemotingParser.java index 07a8b9214f..f786924ffa 100644 --- a/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/LocalTCCRemotingParser.java +++ b/tcc/src/main/java/io/seata/rm/tcc/remoting/parser/LocalTCCRemotingParser.java @@ -42,6 +42,11 @@ public class LocalTCCRemotingParser extends AbstractedRemotingParser { return isLocalTCC(bean); } + @Override + public boolean isService(Class<?> beanClass) throws FrameworkException { + return isLocalTCC(beanClass); + } + @Override public RemotingDesc getServiceDesc(Object bean, String beanName) throws FrameworkException { if (!this.isRemoting(bean, beanName)) { @@ -84,6 +89,10 @@ public class LocalTCCRemotingParser extends AbstractedRemotingParser { */ private boolean isLocalTCC(Object bean) { Class<?> classType = bean.getClass(); + return isLocalTCC(classType); + } + + private boolean isLocalTCC(Class<?> classType) { Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(classType); for (Class<?> interClass : interfaceClasses) { if (interClass.isAnnotationPresent(LocalTCC.class)) { diff --git a/tcc/src/main/java/io/seata/rm/tcc/resource/parser/TccRegisterResourceParser.java b/tcc/src/main/java/io/seata/rm/tcc/resource/parser/TccRegisterResourceParser.java index 1918dd2419..c3a4035715 100644 --- a/tcc/src/main/java/io/seata/rm/tcc/resource/parser/TccRegisterResourceParser.java +++ b/tcc/src/main/java/io/seata/rm/tcc/resource/parser/TccRegisterResourceParser.java @@ -16,80 +16,68 @@ */ package io.seata.rm.tcc.resource.parser; +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; + import io.seata.common.exception.FrameworkException; import io.seata.common.util.ReflectionUtil; import io.seata.common.util.StringUtils; import io.seata.integration.tx.api.interceptor.ActionContextUtil; -import io.seata.integration.tx.api.interceptor.TxBeanParserUtils; import io.seata.integration.tx.api.interceptor.parser.RegisterResourceParser; -import io.seata.integration.tx.api.remoting.RemotingDesc; -import io.seata.integration.tx.api.remoting.parser.DefaultRemotingParser; import io.seata.rm.DefaultResourceManager; import io.seata.rm.tcc.TCCResource; import io.seata.rm.tcc.api.BusinessActionContext; import io.seata.rm.tcc.api.BusinessActionContextParameter; import io.seata.rm.tcc.api.TwoPhaseBusinessAction; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Method; -import java.util.Arrays; -import java.util.HashSet; -import java.util.Set; - /** */ public class TccRegisterResourceParser implements RegisterResourceParser { @Override public void registerResource(Object target, String beanName) { - boolean isTxRemotingBean = TxBeanParserUtils.isTxRemotingBean(target, beanName); - if (isTxRemotingBean) { - RemotingDesc remotingDesc = DefaultRemotingParser.get().getRemotingBeanDesc(target); - if (remotingDesc != null) { - if (remotingDesc.isService()) { - try { - //service bean, registry resource - Class<?> serviceClass = remotingDesc.getServiceClass(); - Set<Method> methods = new HashSet<>(Arrays.asList(serviceClass.getMethods())); - Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(serviceClass); - if (interfaceClasses != null) { - for (Class<?> interClass : interfaceClasses) { - methods.addAll(Arrays.asList(interClass.getMethods())); - } - } - Object targetBean = remotingDesc.getTargetBean(); - for (Method m : methods) { - TwoPhaseBusinessAction twoPhaseBusinessAction = m.getAnnotation(TwoPhaseBusinessAction.class); - if (twoPhaseBusinessAction != null) { - TCCResource tccResource = new TCCResource(); - if (StringUtils.isBlank(twoPhaseBusinessAction.name())) { - throw new FrameworkException("TCC bean name cannot be null or empty"); - } - tccResource.setActionName(twoPhaseBusinessAction.name()); - tccResource.setTargetBean(targetBean); - tccResource.setPrepareMethod(m); - tccResource.setCommitMethodName(twoPhaseBusinessAction.commitMethod()); - tccResource.setCommitMethod(serviceClass.getMethod(twoPhaseBusinessAction.commitMethod(), - twoPhaseBusinessAction.commitArgsClasses())); - tccResource.setRollbackMethodName(twoPhaseBusinessAction.rollbackMethod()); - tccResource.setRollbackMethod(serviceClass.getMethod(twoPhaseBusinessAction.rollbackMethod(), - twoPhaseBusinessAction.rollbackArgsClasses())); - // set argsClasses - tccResource.setCommitArgsClasses(twoPhaseBusinessAction.commitArgsClasses()); - tccResource.setRollbackArgsClasses(twoPhaseBusinessAction.rollbackArgsClasses()); - // set phase two method's keys - tccResource.setPhaseTwoCommitKeys(this.getTwoPhaseArgs(tccResource.getCommitMethod(), - twoPhaseBusinessAction.commitArgsClasses())); - tccResource.setPhaseTwoRollbackKeys(this.getTwoPhaseArgs(tccResource.getRollbackMethod(), - twoPhaseBusinessAction.rollbackArgsClasses())); - //registry tcc resource - DefaultResourceManager.get().registerResource(tccResource); - } - } - } catch (Throwable t) { - throw new FrameworkException(t, "parser remoting service error"); - } + try { + //service bean, registry resource + Class<?> serviceClass = target.getClass(); + this.executeRegisterResource(target, new HashSet<>(Arrays.asList(serviceClass.getMethods())), target.getClass()); + Set<Class<?>> interfaceClasses = ReflectionUtil.getInterfaces(serviceClass); + for (Class<?> interClass : interfaceClasses) { + this.executeRegisterResource(target, new HashSet<>(Arrays.asList(interClass.getMethods())), interClass); + } + } catch (Throwable t) { + throw new FrameworkException(t, "parser remoting service error"); + } + } + + private void executeRegisterResource(Object target, Set<Method> methods, Class<?> targetServiceClass) throws NoSuchMethodException { + for (Method m : methods) { + TwoPhaseBusinessAction twoPhaseBusinessAction = m.getAnnotation(TwoPhaseBusinessAction.class); + if (twoPhaseBusinessAction != null) { + TCCResource tccResource = new TCCResource(); + if (StringUtils.isBlank(twoPhaseBusinessAction.name())) { + throw new FrameworkException("TCC bean name cannot be null or empty"); } + tccResource.setActionName(twoPhaseBusinessAction.name()); + tccResource.setTargetBean(target); + tccResource.setPrepareMethod(m); + tccResource.setCommitMethodName(twoPhaseBusinessAction.commitMethod()); + tccResource.setCommitMethod(targetServiceClass.getMethod(twoPhaseBusinessAction.commitMethod(), + twoPhaseBusinessAction.commitArgsClasses())); + tccResource.setRollbackMethodName(twoPhaseBusinessAction.rollbackMethod()); + tccResource.setRollbackMethod(targetServiceClass.getMethod(twoPhaseBusinessAction.rollbackMethod(), + twoPhaseBusinessAction.rollbackArgsClasses())); + // set argsClasses + tccResource.setCommitArgsClasses(twoPhaseBusinessAction.commitArgsClasses()); + tccResource.setRollbackArgsClasses(twoPhaseBusinessAction.rollbackArgsClasses()); + // set phase two method's keys + tccResource.setPhaseTwoCommitKeys(this.getTwoPhaseArgs(tccResource.getCommitMethod(), + twoPhaseBusinessAction.commitArgsClasses())); + tccResource.setPhaseTwoRollbackKeys(this.getTwoPhaseArgs(tccResource.getRollbackMethod(), + twoPhaseBusinessAction.rollbackArgsClasses())); + //registry tcc resource + DefaultResourceManager.get().registerResource(tccResource); } } } --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@seata.apache.org For additional commands, e-mail: notifications-h...@seata.apache.org