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

框架调用从业务补偿方法时spring注入类丢失问题 #412

Open
BianChangcai opened this issue Aug 26, 2023 · 6 comments
Open

Comments

@BianChangcai
Copy link

public final class Terminator {
private Terminator() {
}

public static Object invoke(TransactionContext transactionContext, Invocation invocation, Class<? extends TransactionContextEditor> transactionContextEditorClass) {
    if (StringUtils.isNotEmpty(invocation.getMethodName())) {
        Object target = FactoryBuilder.factoryOf(invocation.getTargetClass()).getInstance();
        Method method = null;

        try {
            method = target.getClass().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
        } catch (NoSuchMethodException var12) {
            throw new SystemException(var12);
        }

        ((TransactionContextEditor)FactoryBuilder.factoryOf(transactionContextEditorClass).getInstance()).set(transactionContext, target, method, invocation.getArgs());

        Object var5;
        try {
            var5 = method.invoke(target, invocation.getArgs());
        } catch (InvocationTargetException | IllegalAccessException var10) {
            throw new SystemException(var10);
        } finally {
            ((TransactionContextEditor)FactoryBuilder.factoryOf(transactionContextEditorClass).getInstance()).clear(transactionContext, target, method, invocation.getArgs());
        }

        return var5;
    } else {
        return null;
    }
}

}

Springboot 版本:2.3.5.RELEASE
TCC 版本:2.0.1
框架通过 Terminator 调用以下反射方法执行补偿逻辑时,因为 target 类中spring注入的Bean都是null,所以执行业务方法时报空指针异常,这个问题如何解决?
var5 = method.invoke(target, invocation.getArgs());

再往上看,应该是框架创建代理类时注入依赖没有问题,框架的问题望高手指点?
Object target = FactoryBuilder.factoryOf(invocation.getTargetClass()).getInstance();

@BianChangcai
Copy link
Author

我从业务通过Feign调用的,从业务获取 TransactionContext 上下文都没问题的,就是Bean注入类都变成null了

@BianChangcai
Copy link
Author

问题指正:应该是框架创建代理类时注入依赖有问题,不是没问题
再往上看,应该是框架创建代理类时注入依赖没有问题,框架的问题望高手指点?
Object target = FactoryBuilder.factoryOf(invocation.getTargetClass()).getInstance();

@BianChangcai
Copy link
Author

临时解决方法:
针对框架获取 Spring Bean 时,对 Bean 本身的依赖没有注入进去问题,在框架补偿方法中,自己编写一个从 Spring 容器中获取Bean 的方法来对依赖进行赋值。
具体方法:
1、先定义获取 Spirng Bean 的工具类
2、在补偿方法中通过工具类获取依赖 Bean,然后对被依赖类行依赖注入

1、工具类:
@component
public class BeanUtils implements ApplicationContextAware {
protected static ApplicationContext applicationContext;

@Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
    if (applicationContext == null) {
        applicationContext = arg0;
    }

}

public static Object getBean(String name) {
    // name表示其他要注入的注解name名
    return applicationContext.getBean(name);
}

/**
 * 拿到ApplicationContext对象实例后就可以手动获取Bean的注入实例对象
 */
public static <T> T getBean(Class<T> clazz) {
    return applicationContext.getBean(clazz);
}

}

2、在补偿方法中使用方式:
public void cancelCreditToPointAccountTcc(String param1, String param2) {
### pointAccountService = BeanUtils.getBean(RpPointAccountService.class);
pointAccountService.cancelCreditToPointAccountTcc(param1, param2);
}

pointAccountService 原先是通过 @Autowired 注解来注入的,引入框架后在补偿方法中失效了,为 null。

@BianChangcai
Copy link
Author

tcc-transaction github 仓:"created_at": "2015-12-05T04:27:53Z", 2016年当时国内最好的 TCC 框架。

Seata github 仓:"created_at": "2018-12-28T08:37:22Z", 之后 Seata 等后来者追上。

1 similar comment
@BianChangcai
Copy link
Author

tcc-transaction github 仓:"created_at": "2015-12-05T04:27:53Z", 2016年当时国内最好的 TCC 框架。

Seata github 仓:"created_at": "2018-12-28T08:37:22Z", 之后 Seata 等后来者追上。

@nervose
Copy link
Contributor

nervose commented Aug 29, 2023

问题指正:应该是框架创建代理类时注入依赖有问题,不是没问题 再往上看,应该是框架创建代理类时注入依赖没有问题,框架的问题望高手指点? Object target = FactoryBuilder.factoryOf(invocation.getTargetClass()).getInstance();

TCC补偿时target对象的获取是通过类名,从spring容器中拿的。所以需要把使用了@Compensable注解的方法所在的类注册到spring容器中。如果是基于feign来传递上下文的话,可以参考tcc-transaction-http-sample中的实现。如果还有问题,建议提供下复现方式。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants