概述
Beast-tx是一个轻量级不侵入业务代码的TCC分布式事务框架。支持dubbo和spring cloud。
特性
- 支持主流的RPC框架:dubbo和spring cloud
- 配置简单。不侵入业务代码
- 提供一个事务信息收集器,可以自行扩展。
- 几乎没有性能损耗。
2. Beast-tx For Dubbo
2.1 如果你使用spring
在你的项目中加上依赖,maven的GAV为:
<code><dependency>
<groupid>com.thebeastshop/<groupid>
<artifactid>beast-tx-dubbo/<artifactid>
<version>${version}/<version>
/<dependency>/<code>
目前中央仓库没有上传,需要自己编译打包
然后在dubbo的消费者端的applicationContext.xml里配置如下:
<code><aspectj-autoproxy>
<bean>
<bean>/<code>
2.2 如果你使用springboot
在你的项目中加上依赖,maven的GAV为:
<code> <dependency>
<groupid>com.thebeastshop/<groupid>
<artifactid>beast-tx-dubbo-spring-boot-starter/<artifactid>
<version>${version}/<version>
/<dependency>/<code>
目前中央仓库没有上传,需要自己编译打包
由于对springboot作了自动装配,因此只需引入包即可。不用额外配置
2.3 使用方法
假设你的dubbo提供者端有一个service:DemoService,接口定义如下:
<code>String test1(String name);
String test2(String name, Integer age);
String test3(Long id);/<code>
假设test方法需要支持分布式TCC事务,则需要遵循以下约定:
- 定义并实现tryTest(String name)方法,主要用于校验一些前置条件,如参数合法性,业务的前置判断等。参数必须和主体方法参数一致,但这不是必须的,如果您的前置判断写在test方法主体里,那这个方法可以不定义。
- 定义并实现cancelTest(String str)方法,用于做业务的回滚操作。如果在回滚方法里需要用到方法主体返回的结果,也可以定义为cancelTest(String str, Object result)。BeastTx对这2种定义都支持。
然后在你的dubbo消费者端需要加入分布式事务的service中的method上加上@BeastTx标签即可
完整例子如下:
dubbo提供者端
<code>public interface DemoService {
boolean tryTest1(String name);
String test1(String name);
String test2(String name, Integer age);
String test3(Long id);
void cancelTest1(String str);
void cancelTest2(String str);
}/<code>
dubbo消费者端
<code>@Service("testService")
public class TestServiceImpl implements TestService {
private final static Logger log = LoggerFactory.getLogger(TestServiceImpl.class);
@Resource
private DemoService demoService;//这是另外一个服务的service
@Resource
private JdbcTemplate jdbcTemplate;
@Override
@BeastTx
public void consumerTest() {
jdbcTemplate.execute("insert into user (name, age) values ('beast-tx', '99131')");
String result = demoService.test1("jack");
log.info("result:" + result);
demoService.test3(8L);
}
}/<code>
以上示例为一个本地事务+dubbo远程事务test1+dubbo远程事务test3,假设dubboService.test3出错。那整个执行顺序如下:
- 先执行本地事务jdbcTemplate.execute("insert into user (name, age) values ('beast-tx', '99131')")
- 自动执行demoService.tryTest1(String name)进行业务前置判断检查
- 执行demoService.test1(String name)进行业务操作
- 执行demoService.test3(Long id)进行业务操作,抛出错误
- 自动执行demoService.cancelTest3(Long id)进行回滚操作
- 本地事务的回滚操作
3.Beast-tx For Spring Cloud
3.1 依赖和配置
在你的项目中加上依赖,maven的GAV为:
<code><dependency>
<groupid>com.thebeastshop/<groupid>
<artifactid>beast-tx-feign-spring-boot-starter/<artifactid>
<version>${version}/<version>
/<dependency>/<code>
目前中央仓库没有上传,需要自己编译打包
springboot会自动装配,如无其他配置
3.2 使用方法
对Spring Cloud的Feign提供支持。所需要用的方法约束,和2.3类似,不再重复
下面只贴出例子:
Feign的提供者端:
<code>@RestController
public class ProviderController {
private final Logger log = LoggerFactory.getLogger(this.getClass());
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private ProviderDomain providerDomain;
@RequestMapping("/hi")
public String sayHello(@RequestParam String name){
System.out.println("invoke method hi,name="+name);
String services = "Services:" + discoveryClient.getServices();
System.out.println(services);
return "hello," + name;
}
@RequestMapping("/tryTest1")
public boolean tryTest1(@RequestParam String name){
log.info("invoked tryTest1");
return providerDomain.tryTest1(name);
}
@RequestMapping("/test1")
public String test1(@RequestParam String name){
log.info("invoked test1");
return providerDomain.test1(name);
}
@RequestMapping("/cancelTest1")
public void cancelTest1(@RequestParam String name){
log.info("invoked cancelTest1");
providerDomain.cancelTest1(name);
}
public String test2(@RequestParam String name){
return providerDomain.test2(name);
}
}/<code>
Feign的消费者端
Feign接口定义:
<code>@FeignClient("test-provider")
public interface TxTestSayhiFeignClient {
@RequestMapping(value = "hi",method = RequestMethod.GET)
public String sayHello(@RequestParam(value = "name") String name);
@RequestMapping(value = "tryTest1",method = RequestMethod.GET)
public boolean tryTest1(@RequestParam(value = "name") String name);
@RequestMapping(value = "test1",method = RequestMethod.GET)
public String test1(@RequestParam(value = "name") String name);
@RequestMapping(value = "cancelTest1",method = RequestMethod.GET)
public void cancelTest1(@RequestParam(value ="name") String name);
@RequestMapping(value = "test2",method = RequestMethod.GET)
public String test2(@RequestParam(value = "name") String name);
}/<code>
消费者实现类:
<code>@Component
public class ConsumerDomain {
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private TxTestSayhiFeignClient txTestSayhiFeignClient;
@BeastTx
public String doTest(String name){
jdbcTemplate.execute("insert into user (name, age) values ('beast-tx', '99131')");
String result = txTestSayhiFeignClient.test1("jack");
System.out.println("result:" + result);
txTestSayhiFeignClient.test2("rose");
return "ok";
}
}/<code>
以上示例为一个本地事务+Feign远程事务test1+Feign远程事务test2,假设txTestSayhiFeignClient.test2出错。那整个执行顺序如下:
- 先执行本地事务jdbcTemplate.execute("insert into user (name, age) values ('beast-tx', '99131')")
- 自动执行txTestSayhiFeignClient.tryTest1(String name)进行业务前置判断检查
- 执行txTestSayhiFeignClient.test1(String name)进行业务操作
- 执行txTestSayhiFeignClient.test2(String name)进行业务操作,抛出错误
- 自动执行txTestSayhiFeignClient.cancelTest2(String name)进行回滚操作
- 本地事务的回滚操作
4.回滚之后的Hook接口
当分布式事务回滚之后,Beast-Tx提供了一个可供扩展的hook接口。
只要你的项目中实现了CancelInvokeHook这个接口并注册到spring容器中。在项目启动的时候就会被自动扫描到。
当你的分布式事务回滚之后,会自动执行这个hook实现。你可以用来持久化错误信息,打印回滚链路,或者进行一些其他的业务操作。
5.监控的扩展
Beast-Tx留了一系列的监控扩展点。
5.1 监控的server端(半成品)
其中监控的server端为beast-tx-monitor,如启动的话,这个项目目前只接受每一条的事务上下文并打印,并没有对事务上下文作进一步的监控业务,如有兴趣可以自行实现
5.2 client端
如果您在dubbo/Spring Cloud消费者端的application.yml配了如下配置
<code>tx:
monitor:
ip: 127.0.0.1
port: 6789/<code>
springboot启动时会自动装配,在每一个分布式事务结束后,会把这个事务中的详细内容发送到server端。
其中项目对socket提供了2个实现:
beast-tx-socket-netty
beast-tx-socket-tio
都是用SPI实现的,默认用netty,想换实现,只需换一个依赖包即可
閱讀更多 儒雅程序員 的文章