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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 推荐系统中传统模型——LightGBM + FFM融合

    推荐系统中传统模型——LightGBM + FFM融合之前比较相关的文章:推荐系统中传统模型——LightGBM+LR融合python-机器学习lightgbm相关实践1深入FFM原理与实践来自美团技术团队的,深入FFM原理与实践FM和FFM模型是最近几年提出的模型,凭借其在数据量比较大并且特征稀疏的情况下,仍然能够得到优秀的性能和效果的特性,屡次在各大公司举办的CTR预估比赛中获得不错的战绩。美团技术团队在搭建DSP的过程中,探索并使用了FM和FFM模型进行CTR和CVR预估,并且取得了不错的效果。经过One-Hot编码之后,大部分

    2022年5月27日
    34
  • 匹配电子邮箱的正则表达式_怎样设置电子邮箱

    匹配电子邮箱的正则表达式_怎样设置电子邮箱电子邮件格式  电子邮件地址的格式是域内部分@域,其中域内部分最长为64个字符,而域名最长可达255个字符。例如:name@domainname可以使用任意ASCII字符:大小写英文字母a-z,A-Z数字0-9name部分只允许输入‘-’、’_’、’.’。原则上字符  !#$%&’*±/=?^`{|}~  甚至空格都可以输入,但是有些邮件服务器会拒绝包含有特殊字符的邮件地址一般来说只允许输入‘-’、’_’、’.’这三个特殊符号字符‘.’不能

    2022年9月23日
    0
  • fastai教程_euleros安装教程

    fastai教程_euleros安装教程从fast.ai学到的十大技巧:如何在几周内上手顶级算法https://www.colabug.com/3887239.htmlfastai系列教程(二)-快速入门MNIST示例https://www.pytorchtutorial.com/fastai-tutorial-2-overview-mnist/…

    2022年9月8日
    0
  • Pycharm使用pyinstaller打包成64/32位通用exe

    Pycharm使用pyinstaller打包成64/32位通用exe网上大多数博客都是行不通的 在此记录一个可行的快捷方式 下载 32 位 python 安装包 点击安装 选择第二种自定义方式安装 默认 填写自己的安装路径 安装完成 PycharmSetti 设置 ShowAll 点击 选择 existingenvi 选择 Python32 位安装路径 设置好后需要安装 pyinstaller 库 点击右边 号 安装 pyinstaller 完成 回到项目 对报红缺失的依

    2025年7月26日
    1
  • 如何添加smtp服务器_smtp服务器设置

    如何添加smtp服务器_smtp服务器设置在现在这个时代中,人们传输信息基本上都是用邮件传输,那么你知道电脑之间是怎么用邮件传输的么。就是通过smtp服务器,通过这个服务器,人们可以把自己写的东西通过邮件经过这个服务器传输到你想让邮件传输到的地方,接下来就让小编好好给大家介绍一下。Smtp传输器是什么?Smpt的意思是简单的邮件传输协议,它是一组用于源地址到目的地传送邮件的规则,并且由它决定邮件的中转方式。Smtp传输器使用由tcp提供的…

    2022年9月1日
    1
  • java axis_Java 使用Axis实现WebService实例

    java axis_Java 使用Axis实现WebService实例在上一篇WebService实例中,基于jdk1.6以上的javax.jws发布webservice接口。这篇博文则主要用eclipse/myeclipse使用axis插件进行发布和调用WebService。1.下载axis,并解压到tomcat/webapps目录下2.在tomcat部署axis2启动tomcat,可以看到多了个axis2文件在浏览器输入:http://localho…

    2022年7月21日
    11

发表回复

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

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