Hmily(1)

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

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

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&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上下文容器。

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;
        }
    }

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • phpstrom2020激活码(破解版激活)

    phpstrom2020激活码(破解版激活),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月16日
    54
  • PHP+MySql例子

    对于熟悉做网站的人来说,要想网站做成动态的,肯定要有数据库的支持,利用特定的脚本连接到数据库,从数据库中提取资料、向数据库中添加资料、删除资料等。这里我通过一个实例来说明如何用php连接到数据库的。

    2021年12月23日
    39
  • 教你用JAVA写个小游戏[通俗易懂]

    教你用JAVA写个小游戏[通俗易懂]上周上课的时候老师让用Java写个小程序,我本想写一个经典的飞机大战游戏来着,可以后来突发奇想就写成了这个一、整体思路继承窗体类,复写窗体刷新 添加按键监听 游戏结束界面 王思聪类和热狗类移动轨迹计算 判断碰撞音乐播放 不断刷新窗体处理细节二、编码1.图片首先你要找到图片,可以百度一张,然后用ps切开,再找一张背景图片就搞定了你还需要一个加载图片的…

    2022年7月14日
    22
  • 怎样开挂的教程_销售常见的八个问题

    怎样开挂的教程_销售常见的八个问题概念篇1、什么是外挂它是怎样定义?外挂是指某些人利用自己的电脑技术专门针对一个或多个网络游戏,通过改变网络游戏软件的部分程序,制作而成的作弊程序。这是一个让游戏公司痛恨、玩家分派、作者成就、工作室必备的游戏辅助软件程序。2、一般外挂分几类?有模拟类、内存类、封包类、变态类、脱机类,一般来讲模拟类是最轻的,比如用按键精灵来代替鼠标和键盘的操作;内存挂、封包挂是比较正规和普遍的

    2022年10月31日
    0
  • python django 数据库_Apache+Mysql+PHP/Python简单项目

    python django 数据库_Apache+Mysql+PHP/Python简单项目基于Python+Django+mysql的实验室设备管理系统当今时代是飞速发展的信息时代,在各行各业中离不开信息处理,这正是计算机被广泛应用于信息管理系统环境原因。计算机的最大好处在于利用它能够进行信息管理。使用计算机进行信息控制,不仅提高了工作效率,而且大大的提高了其安全性。尤其对于复杂的信息管理,计算机能够充分发挥它的优越性。计算机进行信息管理与信息管理系统的开发密切相关,系统的开发是系统管理的前提。高校的实验室设备管理水平和实验室设备管理规模日益成为反映高校综合实…

    2022年10月9日
    0
  • c# taskscheduler使用场合_hbase shell put

    c# taskscheduler使用场合_hbase shell put这里记录下TaskScheduler的简单用法。使用场景:在使用Task的时候,大家都知道用TaskFactory.StartNew可以用来创建一个Task。这里如果创建10个,那么这10个Task就各自放飞直接运行了。一般情况下是没什么大问题,如果这10个中的每个Task非常耗CPU或者内存,而公司的产品又是非常考验配置成本(比如一体机,移动设备等),就需要让这10个Task按照一定要求执行,比如串行执行,从而节省资源、让机器还可以顺畅去干别的事情。Task…

    2022年10月11日
    0

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号