Hmily(1)

2022-08-31 15:23:27 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

1. Hmily是个高性能异步分布式事务TCC框架,具体包含Spring AOP,Disruptor,Dubbo等框架,当然还有其他的RPC框架。源码在https://github.com/yu199195/hmily,本文以duubo调用,mysql存储事务日志,kryo序列化为主,主要以下单支付减库存减余额为例,注解为Hmily,确认方法,取消方法和本次的tyr操作方法参数应该保持一致。前两个方法名配置在注解上。

代码语言:javascript复制
@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:

代码语言:javascript复制
 <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&amp;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上下文容器。

代码语言:javascript复制
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,并注册到容器中。

代码语言:javascript复制
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,也就是创建数据库表。

代码语言:javascript复制
 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上,

代码语言:javascript复制
   @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也为空,主要是用来存储事务上下文的。

代码语言:javascript复制
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获取对应的处理器然后进行下一步调用。

代码语言:javascript复制
 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

代码语言:javascript复制
 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;
        }
    }

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/143247.html原文链接:https://javaforall.cn

0 人点赞