大家好,又见面了,我是你们的朋友全栈君。
1. Hmily是个高性能异步分布式事务TCC框架,具体包含Spring AOP,Disruptor,Dubbo等框架,当然还有其他的RPC框架。源码在https://github.com/yu199195/hmily,本文以duubo调用,mysql存储事务日志,kryo序列化为主,主要以下单支付减库存减余额为例,注解为Hmily,确认方法,取消方法和本次的tyr操作方法参数应该保持一致。前两个方法名配置在注解上。
@Hmily(confirmMethod = "confirmOrderStatus", cancelMethod = "cancelOrderStatus")
public void makePayment(Order order) {
order.setStatus(OrderStatusEnum.PAYING.getCode());
orderMapper.update(order);
//做库存和资金账户的检验工作 这里只是demo 。。。
/* final AccountDO accountDO = accountService.findByUserId(order.getUserId());
if (accountDO.getBalance().compareTo(order.getTotalAmount()) <= 0) {
throw new HmilyRuntimeException("余额不足!");
}
final InventoryDO inventory = inventoryService.findByProductId(order.getProductId());
if (inventory.getTotalInventory() < order.getCount()) {
throw new HmilyRuntimeException("库存不足!");
}*/
//扣除用户余额
AccountDTO accountDTO = new AccountDTO();
accountDTO.setAmount(order.getTotalAmount());
accountDTO.setUserId(order.getUserId());
accountService.payment(accountDTO);
//进入扣减库存操作
InventoryDTO inventoryDTO = new InventoryDTO();
inventoryDTO.setCount(order.getCount());
inventoryDTO.setProductId(order.getProductId());
inventoryService.decrease(inventoryDTO);
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Hmily {
/**
* Confirm method string.
*
* @return the string
*/
String confirmMethod() default "";
/**
* Cancel method string.
*
* @return the string
*/
String cancelMethod() default "";
/**
* Pattern pattern enum.
*
* @return the pattern enum
*/
PatternEnum pattern() default PatternEnum.TCC;
}
应用配置文件如下applicationContext.xml:spring-dubbo.xml:
<context:component-scan base-package="org.dromara.hmily.*"/>
<aop:aspectj-autoproxy expose-proxy="true"/>
<bean id="hmilyTransactionBootstrap" class="org.dromara.hmily.core.bootstrap.HmilyTransactionBootstrap">
<property name="serializer" value="kryo"/>
<property name="recoverDelayTime" value="120"/>
<property name="retryMax" value="3"/>
<property name="scheduledDelay" value="120"/>
<property name="scheduledThreadMax" value="4"/>
<property name="repositorySupport" value="db"/>
<property name="started" value="false"/>
<property name="hmilyDbConfig">
<bean class="org.dromara.hmily.common.config.HmilyDbConfig">
<property name="url"
value="jdbc:mysql://192.168.1.98:3306/tcc?useUnicode=true&characterEncoding=utf8"/>
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
</property>
</bean>
<import resource="spring-dubbo.xml"/>
<dubbo:application name="order_service"/>
<dubbo:registry protocol="zookeeper" address="192.168.1.84:2181"/>
<dubbo:protocol name="dubbo" port="20886"
server="netty" client="netty"
charset="UTF-8" threadpool="fixed" threads="500"
queues="0" buffer="8192" accepts="0" payload="8388608"/>
<dubbo:reference timeout="50000"
interface="org.dromara.hmily.demo.dubbo.inventory.api.service.InventoryService"
id="inventoryService"
retries="0" check="false" actives="20"/>
<dubbo:reference timeout="50000"
interface="org.dromara.hmily.demo.dubbo.account.api.service.AccountService"
id="accountService"
retries="0" check="false" actives="20"/>
2. 初始化启动类HmilyTransactionBootstrap,实现一些类的初始化,保存spring上下文容器。
public class HmilyTransactionBootstrap extends HmilyConfig implements ApplicationContextAware {
private final HmilyInitService hmilyInitService;
@Autowired
public HmilyTransactionBootstrap(final HmilyInitService hmilyInitService) {
this.hmilyInitService = hmilyInitService;
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
SpringBeanUtils.getInstance().setCfgContext((ConfigurableApplicationContext) applicationContext);
start(this);
}
private void start(final HmilyConfig hmilyConfig) {
hmilyInitService.initialization(hmilyConfig);
}
}
开始初始化类的处理化HmilyInitServiceImpl,注入数据存储协调了HmilyCoordinatorServiceImpl,加载spi支持类。也就是实例化序列化类KryoSerializer,事务日志存储类JdbcCoordinatorRepository,并注册到容器中。
public void initialization(final HmilyConfig hmilyConfig) {
Runtime.getRuntime().addShutdownHook(new Thread(() -> LOGGER.info("hmily shutdown now")));
try {
loadSpiSupport(hmilyConfig);
hmilyCoordinatorService.start(hmilyConfig);
} catch (Exception ex) {
LogUtil.error(LOGGER, " hmily init exception:{}", ex::getMessage);
System.exit(1);
}
new HmilyLogo().logo();
}
private void loadSpiSupport(final HmilyConfig hmilyConfig) {
//spi serialize
final SerializeEnum serializeEnum = SerializeEnum.acquire(hmilyConfig.getSerializer());
final ServiceLoader<ObjectSerializer> objectSerializers = ServiceBootstrap.loadAll(ObjectSerializer.class);
final ObjectSerializer serializer = StreamSupport.stream(objectSerializers.spliterator(), false)
.filter(objectSerializer -> Objects.equals(objectSerializer.getScheme(), serializeEnum.getSerialize()))
.findFirst().orElse(new KryoSerializer());
//spi repository
final RepositorySupportEnum repositorySupportEnum = RepositorySupportEnum.acquire(hmilyConfig.getRepositorySupport());
final ServiceLoader<HmilyCoordinatorRepository> recoverRepositories = ServiceBootstrap.loadAll(HmilyCoordinatorRepository.class);
final HmilyCoordinatorRepository repository = StreamSupport.stream(recoverRepositories.spliterator(), false)
.filter(recoverRepository -> Objects.equals(recoverRepository.getScheme(), repositorySupportEnum.getSupport()))
.findFirst().orElse(new JdbcCoordinatorRepository());
repository.setSerializer(serializer);
SpringBeanUtils.getInstance().registerBean(HmilyCoordinatorRepository.class.getName(), repository);
}
启动HmilyCoordinatorServiceImpl#start,也就是创建数据库表。
public void start(final HmilyConfig hmilyConfig) {
final String repositorySuffix = buildRepositorySuffix(hmilyConfig.getRepositorySuffix());
coordinatorRepository = SpringBeanUtils.getInstance().getBean(HmilyCoordinatorRepository.class);
coordinatorRepository.init(repositorySuffix, hmilyConfig);
}
3. 开始执行请求,这里会先执行切面方法,切面类是DubboHmilyTransactionAspect,这里会设置他的排序值,因为在构建增强器时会根据这个排序值进行从小到大排序AbstractAdvisorAutoProxyCreator#sortAdvisors(eligibleAdvisors);该类会被首先执行,他的切点在注解Hmily上,
@Pointcut("@annotation(org.dromara.hmily.annotation.Hmily)")
public void hmilyInterceptor() {
}
@Around("hmilyInterceptor()")
public Object interceptTccMethod(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return hmilyTransactionInterceptor.interceptor(proceedingJoinPoint);
}
DubboHmilyTransactionInterceptor#interceptor,因为这个时候还没有经过dubbo的过滤器调用,所以这个context会为空。这个ThreadLocal也为空,主要是用来存储事务上下文的。
public Object interceptor(final ProceedingJoinPoint pjp) throws Throwable {
final String context = RpcContext.getContext().getAttachment(CommonConstant.HMILY_TRANSACTION_CONTEXT);
HmilyTransactionContext hmilyTransactionContext;
if (StringUtils.isNoneBlank(context)) {
hmilyTransactionContext = GsonUtils.getInstance().fromJson(context, HmilyTransactionContext.class);
RpcContext.getContext().getAttachments().remove(CommonConstant.HMILY_TRANSACTION_CONTEXT);
} else {
hmilyTransactionContext = HmilyTransactionContextLocal.getInstance().get();
}
return hmilyTransactionAspectService.invoke(hmilyTransactionContext, pjp);
}
HmilyTransactionAspectServiceImpl#invoke获取对应的处理器然后进行下一步调用。
public Object invoke(final HmilyTransactionContext hmilyTransactionContext, final ProceedingJoinPoint point) throws Throwable {
final Class clazz = hmilyTransactionFactoryService.factoryOf(hmilyTransactionContext);
final HmilyTransactionHandler txTransactionHandler = (HmilyTransactionHandler) SpringBeanUtils.getInstance().getBean(clazz);
return txTransactionHandler.handler(point, hmilyTransactionContext);
}
HmilyTransactionFactoryServiceImpl根据上下文的内容获取对应的处理器,第一次获取StarterHmilyTransactionHandler
public Class factoryOf(final HmilyTransactionContext context) {
if (Objects.isNull(context)) {
return StarterHmilyTransactionHandler.class;
} else {
//why this code? because spring cloud invoke has proxy.
if (context.getRole() == HmilyRoleEnum.SPRING_CLOUD.getCode()) {
context.setRole(HmilyRoleEnum.START.getCode());
return ConsumeHmilyTransactionHandler.class;
}
// if context not null and role is inline is ParticipantHmilyTransactionHandler.
if (context.getRole() == HmilyRoleEnum.LOCAL.getCode()) {
return LocalHmilyTransactionHandler.class;
} else if (context.getRole() == HmilyRoleEnum.START.getCode()
|| context.getRole() == HmilyRoleEnum.INLINE.getCode()) {
return ParticipantHmilyTransactionHandler.class;
}
return ConsumeHmilyTransactionHandler.class;
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/143247.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...