关于商品详情页接口流程编排框架的一点实践

        商品详情页,其实就是查各种接口,然后集中对用户展示商品各种各类信息,最核心的就是商品信息,还包括关键信息诸如价格信息、优惠券、促销信息、配送信息,还有一些可有可无的内容,比如问答、评价等信息。

        我们实践中对于可有可无的信息,都是通过单独接口查询来实现展示的。我们这里就不多赘述。

        核心商品接口以及关键信息接口查询,我们要求是包装在一个大接口中一并返回,因为信息都很关键,单独查询会造成数据不同步显示,影响用户体验。因为上游接口非常多,之间的关系非常复杂,并且有的是具有依赖关系的接口,还要考虑接口速度,不能串行执行。这就要求我们需要在设计中进行流程编排,让串行、并行同时存在。

        要达到以上的目的,我们一方面可以自己在代码中分析然后自己编程实现,这样的代码可能效率上和内存占用上会更友好,但是会出现代码乱,维护困难的情况。如果新加入接口,我们就得在一大堆代码中找到我们应该加在那里,是串行还是并行,怎么效率更高。这样显然不是个非常好的方案。

        我们的解决方案是有一套流程编排的框架,可以解决让查询串行并行结合,各个接口前后依赖明确,这里我大概写个简陋的demo,来展示实现思路,抛砖引玉。

这里的例子是定义了一个人员的信息的查询接口,我们在里边需要用到流程编排,来填充人员的各种信息。

package com.example.springdemo.domain;


import lombok.Getter;
import lombok.Setter;

/**
 * 这里定义了一个人的类,name是基础信息,只有知道是谁才能够去查他的各种信息,
 * 查high 然后才可以判断是否可以打篮球 查钱才能确认是否可以买房
 * 查high money facevalue 才可以确定是否是高富帅
 */
@Getter
@Setter
public class Person {

    /**
     * 人的基础信息名称
     */
    private String name;

    /**
     * 人的基础信息身高
     */
    private Integer high;

    /**
     * 有多少钱
     */
    private Integer money;

    /**
     * 颜值
     */
    private Integer faceValue;

    /**
     * 是否是高富帅
     */
    private Boolean isGFS;

    /**
     * 能打篮球
     */
    private Boolean canPlayBasketBall;

    /**
     * 能买房子
     */
    private Boolean canBuyHouse;



}

简单解释下,我们的核心接口是填充人员姓名name,知道name之后,我们则可以去查询他的身高high、有多少钱money、颜值多高faceValue。这三个查询是严格依赖于name的,必须等到name接口返回,这几个才能查询。

       再来看是否可以打篮球canPlayBasketBall属性,他就是严格依赖身高,如果高过一定数值才可以打。同理canBuyHouse是否可以买房,就严格依赖他的money值,这就有了两条串行线。Name->money->canBuyHouse,name->high->canPlayBasketBall,但是money和high的查询是可以并行的,canBuyHouse和canPlayBasketBall也是可以并行的。canBuyHouse和high也是可以并行的,这里就不穷举了。

       再看是否高富帅isGFS这个属性,他是依赖money、high 和faceValue三个接口返回的。

        画了一个简单的依赖图

 接下来看代码实现,我定义了一个接口handler,每个查询都实现这个接口。

package com.example.springdemo.service;

import com.example.springdemo.domain.Person;

public interface IPersonHandler {

    void doHand(Person person);
}

再来看具体实现类,这里写几个,sleep模拟rpc接口的耗时。接口之前的依赖关系通过注解定义。

package com.example.springdemo.service.impl;

import com.example.springdemo.domain.Person;
import com.example.springdemo.service.IPersonHandler;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

@Service
@Log4j2
public class PersonNameHandler implements IPersonHandler {
    @Override
    public void doHand(Person person) {
        person.setName("yaoming");
        log.info(Thread.currentThread().getName() + " ---PersonNameHandler");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.example.springdemo.service.impl;

import com.example.springdemo.common.Dep;
import com.example.springdemo.domain.Person;
import com.example.springdemo.service.IPersonHandler;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

@Service
@Log4j2
@Dep(parent = {PersonNameHandler.class})
public class PersonMoneyHandler implements IPersonHandler {
    @Override
    public void doHand(Person person) {
        if ("yaoming".equals(person.getName())) {
            person.setMoney(10000000);
        }
        log.info(Thread.currentThread().getName() + " ---PersonMoneyHandler");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.example.springdemo.service.impl;

import com.example.springdemo.common.Dep;
import com.example.springdemo.domain.Person;
import com.example.springdemo.service.IPersonHandler;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

@Service
@Log4j2
@Dep(parent = {PersonMoneyHandler.class})
public class PersonBuyHouseHandler implements IPersonHandler {
    @Override
    public void doHand(Person person) {
        if (person.getMoney() != null && person.getMoney() > 5000000) {
            person.setCanBuyHouse(true);
        }
        log.info(Thread.currentThread().getName() + " ---PersonBuyHouseHandler");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
package com.example.springdemo.service.impl;

import com.example.springdemo.common.Dep;
import com.example.springdemo.domain.Person;
import com.example.springdemo.service.IPersonHandler;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;

@Service
@Log4j2
@Dep(parent = {PersonMoneyHandler.class, PersonHighHandler.class, PersonFaceValueHandler.class})
public class PersonGFSHandler implements IPersonHandler {
    @Override
    public void doHand(Person person) {
        if (person.getMoney() != null && person.getMoney() > 5000000 && person.getHigh() != null && person.getHigh() > 190 &&
            person.getFaceValue() != null && person.getFaceValue() > 70) {
            person.setIsGFS(true);
        }
        log.info(Thread.currentThread().getName() + " ---PersonGFSHandler");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

依赖注解的定义,里边定义了依赖的类。

package com.example.springdemo.common;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 *
 * @date 2022-02-19 02:18 2022-02-19 02:50
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Dep {
    Class[] parent();
}

以上是查询接口,我们需要写代码,将以接口进行流程编排。下面进行简单时实现。主要看test方法,test1可能会卡流程请忽

具体解释写在代码里了,以上就基本实现了一个简单的流程编排框架。

这个框架比较简陋,也有一定的缺点,比如开始把所有的任务都提交了再在线程中判断父级是否执行完毕,这样会造成线程池的浪费,不如父级执行完了再在父级线程中将子任务提交线程池。

还有一个缺点是类名的地方,在用代理类后class会变,还得注意读取方式

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
任务编排框架 DSL(Domain Specific Language)是一种专门用于编写任务流程的领域特定语言。任务编排框架 DSL 的主要作用是简化任务的编排和管理,提高任务流程的可读性和可维护性。 任务编排框架 DSL 提供了一种轻量级的、易于理解和编写的语法结构,使开发人员能够直观地描述任务之间的依赖关系和执行顺序。通过任务编排框架 DSL,我们可以将复杂的任务流程拆分为多个简单的任务,并指定它们之间的执行顺序,以达到任务的有序执行和逻辑的清晰表达。 任务编排框架 DSL 还可以提供其他辅助功能,例如错误处理和重试机制。通过在任务编排框架 DSL 中引入错误处理和重试机制,我们可以更好地应对任务执行过程中可能出现的错误和异常。这些功能的引入可以大大增加任务流程的可靠性和容错性。 与传统的编程语言相比,任务编排框架 DSL 更加专注于任务的描述和编排,提供了更简洁、更直观的语法结构。这使得开发人员能够更快地理解和编写任务编排逻辑,提高开发效率。 总之,任务编排框架 DSL 是一种用于编写任务流程的领域特定语言,它可以简化任务的编排和管理,提高任务流程的可读性和可维护性,并且提供了错误处理和重试机制等辅助功能,通过引入任务编排框架 DSL,我们可以更快地编写和维护任务编排逻辑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值