Hable sobre cómo usar el modo de canalización para la orquestación empresarial (Parte 2)

prefacio

En el último artículo, presentamos dos implementaciones de orquestación empresarial mediante el patrón de canalización. Este artículo presenta otros métodos de implementación.

Método para realizar

Método 1: use springboot para ensamblar automáticamente

1. Crear una nueva entidad de canalización
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PipelineDefinition {

public static final String PREFIX = "lybgeek_pipeline_";

private String comsumePipelineName;

private List<String> pipelineClassNames;




}
复制代码

}

@Data
@AllArgsConstructor
@NoArgsConstructor
@ConfigurationProperties(prefix = PipelineDefinitionProperties.PREFIX)
public class PipelineDefinitionProperties {



public final static String PREFIX = "lybgeek.pipeline";

private List<PipelineDefinition> chain;




}
复制代码

}

2. Escribir clase de ensamblaje automático
@Configuration
@EnableConfigurationProperties(PipelineDefinitionProperties.class)
public class PipelineAutoConfiguration implements BeanFactoryAware,InitializingBean, SmartInitializingSingleton {



@Autowired
private PipelineDefinitionProperties pipelineDefinitionProperties;

private DefaultListableBeanFactory defaultListableBeanFactory;


@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {

    defaultListableBeanFactory = (DefaultListableBeanFactory)beanFactory;

}

private void registerPipeline(DefaultListableBeanFactory defaultListableBeanFactory, PipelineDefinition pipelineDefinition) {
    LinkedBlockingDeque linkedBlockingDeque = buildPipelineQuque(pipelineDefinition);
    GenericBeanDefinition beanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder.genericBeanDefinition(ChannelPipeline.class).getBeanDefinition();
    beanDefinition.getPropertyValues().addPropertyValue("channelHandlers",linkedBlockingDeque);
    defaultListableBeanFactory.registerBeanDefinition(PipelineDefinition.PREFIX + pipelineDefinition.getComsumePipelineName() ,beanDefinition);
}

@SneakyThrows
private LinkedBlockingDeque buildPipelineQuque(PipelineDefinition pipelineDefinition) {
    List<String> pipelineClassNames = pipelineDefinition.getPipelineClassNames();
    if(CollectionUtil.isEmpty(pipelineClassNames)){
       throw new PipelineException("pipelineClassNames must config");
    }

    LinkedBlockingDeque linkedBlockingDeque = new LinkedBlockingDeque();
    for (String pipelineClassName : pipelineClassNames) {
        Class<?> pipelineClassClass = Class.forName(pipelineClassName);
        if(!AbstactChannelHandler.class.isAssignableFrom(pipelineClassClass)){
            throw new PipelineException("pipelineClassNames must be 【com.github.lybgeek.pipeline.handler.AbstactChannelHandler】 subclass");
        }
        Object pipeline = pipelineClassClass.getDeclaredConstructor().newInstance();
        linkedBlockingDeque.addLast(pipeline);
    }

    return linkedBlockingDeque;
}

@Override
public void afterPropertiesSet() throws Exception {
    if(CollectionUtil.isNotEmpty(pipelineDefinitionProperties.getChain())){
        for (PipelineDefinition pipelineDefinition : pipelineDefinitionProperties.getChain()) {
            registerPipeline(defaultListableBeanFactory, pipelineDefinition);
        }
    }
}

@Override
public void afterSingletonsInstantiated() {
    Map<String, ChannelPipeline> pipelineBeanMap = defaultListableBeanFactory.getBeansOfType(ChannelPipeline.class);
    pipelineBeanMap.forEach((key,bean)->{
        bean.setHandlerContext(ChannelHandlerContext.getCurrentContext());
    });

}




}
复制代码

}

3. Escribe spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=

com.github.lybgeek.pipeline.spring.autoconfigure.PipelineAutoConfiguration</code>复制代码

业务项目如何使用该方式实现业务编排

示例:

1、创建管道执行器
@Slf4j
public class UserCheckChannelHandler extends AbstactChannelHandler {



@Override
public boolean handler(ChannelHandlerContext chx) {
    ChannelHandlerRequest channelHandlerRequest = chx.getChannelHandlerRequest();
    System.out.println("yml------------------------------------步骤一:用户数据校验【"+channelHandlerRequest.getRequestId()+"】");
    Object params = channelHandlerRequest.getParams();
    if(params instanceof User){
        User user = (User)params;
        if(StringUtils.isBlank(user.getFullname())){
            log.error("用户名不能为空");
            return false;
        }
        return true;
    }


    return false;
}




}
复制代码
@Slf4j
public class UserFillUsernameAndEmailChannelHandler extends AbstactChannelHandler {
@SneakyThrows
@Override
public boolean handler(ChannelHandlerContext chx) {
ChannelHandlerRequest channelHandlerRequest = chx.getChannelHandlerRequest();
System.out.println("yml------------------------------------步骤二:用户名以及邮箱填充【将汉语转成拼音填充】【"+channelHandlerRequest.getRequestId()+"】");
Object params = channelHandlerRequest.getParams();
if(params instanceof User){
User user = (User)params;
String fullname = user.getFullname();
HanyuPinyinOutputFormat hanyuPinyinOutputFormat = new HanyuPinyinOutputFormat();
hanyuPinyinOutputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
String username = PinyinHelper.toHanYuPinyinString(fullname, hanyuPinyinOutputFormat);
user.setUsername(username);
user.setEmail(username + "@qq.com");
return true;
}



    return false;
}




}
复制代码

。。。其他执行器具体查看链接代码

2、配置yml文件
lybgeek:
pipeline:
chain:
- comsumePipelineName: userYmlService
pipelineClassNames:
- com.github.lybgeek.pipeline.spring.test.yml.handler.UserCheckChannelHandler
- com.github.lybgeek.pipeline.spring.test.yml.handler.UserFillUsernameAndEmailChannelHandler
- com.github.lybgeek.pipeline.spring.test.yml.handler.UserPwdEncryptChannelHandler
- com.github.lybgeek.pipeline.spring.test.yml.handler.UserMockSaveChannelHandler
- com.github.lybgeek.pipeline.spring.test.yml.handler.UserPrintChannleHandler复制代码
3、具体业务service引入管道bean
@Service
public class UserYmlServiceImpl implements UserYmlService {



@Autowired
private ApplicationContext applicationContext;

@Override
public boolean save(User user) {

    ChannelPipeline pipeline =  applicationContext.getBean(ChannelPipeline.class,PipelineDefinition.PREFIX + StringUtils.uncapitalize(UserYmlService.class.getSimpleName()));

    return pipeline.start(ChannelHandlerRequest.builder().params(user).build());
}




}复制代码
4、测试
    @Test
public void testPipelineYml(){
boolean isOk = userYmlService.save(user);
Assert.assertTrue(isOk);



}


复制代码

方式二:利用spring自定义标签

1、定义xsd约束文件pipeline.xsd
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns="http://lybgeek.github.com/schema/pipeline"
targetNamespace="http://lybgeek.github.com/schema/pipeline">



&lt;xsd:import namespace="http://www.w3.org/XML/1998/namespace"/&gt;
&lt;xsd:import namespace="http://www.springframework.org/schema/beans"
            schemaLocation="http://www.springframework.org/schema/beans/spring-beans.xsd"/&gt;
&lt;xsd:import namespace="http://www.springframework.org/schema/tool"/&gt;

&lt;xsd:annotation&gt;
    &lt;xsd:documentation&gt;
        &lt;![CDATA[ Namespace support for pipeline services ]]&gt;&lt;/xsd:documentation&gt;
&lt;/xsd:annotation&gt;


&lt;xsd:complexType name="pipelineType"&gt;
    &lt;xsd:choice&gt;
        &lt;xsd:element ref="pipelineHandler" minOccurs="1" maxOccurs="unbounded"/&gt;
    &lt;/xsd:choice&gt;
    &lt;xsd:attribute name="id" type="xsd:ID"&gt;
        &lt;xsd:annotation&gt;
            &lt;xsd:documentation&gt;&lt;![CDATA[ The unique identifier for a bean. ]]&gt;&lt;/xsd:documentation&gt;
        &lt;/xsd:annotation&gt;
    &lt;/xsd:attribute&gt;
    &lt;xsd:attribute name="consumePipelinesServiceClassName" type="xsd:string" use="required"&gt;
        &lt;xsd:annotation&gt;
            &lt;xsd:documentation&gt;&lt;![CDATA[ consumePipelinesService class name  ]]&gt;&lt;/xsd:documentation&gt;
        &lt;/xsd:annotation&gt;
    &lt;/xsd:attribute&gt;
    &lt;xsd:attribute name="consumePipelinesMethod" type="xsd:string" use="required"&gt;
        &lt;xsd:annotation&gt;
            &lt;xsd:documentation&gt;&lt;![CDATA[ consumePipelinesMethod name  ]]&gt;&lt;/xsd:documentation&gt;
        &lt;/xsd:annotation&gt;
    &lt;/xsd:attribute&gt;
    &lt;xsd:attribute name="argsType" type="xsd:string" use="required"&gt;
        &lt;xsd:annotation&gt;
            &lt;xsd:documentation&gt;&lt;![CDATA[ consumePipelinesMethod args type , multiple args types are separated by commas ]]&gt;&lt;/xsd:documentation&gt;
        &lt;/xsd:annotation&gt;
    &lt;/xsd:attribute&gt;
&lt;/xsd:complexType&gt;

&lt;xsd:complexType name="pipelineHandlerType"&gt;
    &lt;xsd:attribute name="className" type="xsd:string" use="required"&gt;
        &lt;xsd:annotation&gt;
            &lt;xsd:documentation&gt;&lt;![CDATA[ pipelineHanlder class name]]&gt;&lt;/xsd:documentation&gt;
        &lt;/xsd:annotation&gt;
    &lt;/xsd:attribute&gt;
    &lt;xsd:attribute name="order" type="xsd:string" use="required"&gt;
        &lt;xsd:annotation&gt;
            &lt;xsd:documentation&gt;&lt;![CDATA[ pipeline class name]]&gt;&lt;/xsd:documentation&gt;
        &lt;/xsd:annotation&gt;
    &lt;/xsd:attribute&gt;
&lt;/xsd:complexType&gt;



&lt;xsd:element name="pipelineHandler" type="pipelineHandlerType"&gt;
    &lt;xsd:annotation&gt;
        &lt;xsd:documentation&gt;&lt;![CDATA[ The pipelineHandler config ]]&gt;&lt;/xsd:documentation&gt;
    &lt;/xsd:annotation&gt;
&lt;/xsd:element&gt;

&lt;xsd:element name="pipeline" type="pipelineType"&gt;
    &lt;xsd:annotation&gt;
        &lt;xsd:documentation&gt;&lt;![CDATA[ The pipeline config ]]&gt;&lt;/xsd:documentation&gt;
    &lt;/xsd:annotation&gt;
&lt;/xsd:element&gt;




</xsd:schema>
复制代码
2、配置xsd约束文件

在classpath下的resources文件夹新建META-INF文件夹,再建立一个文件spring.schemas,内容如下

http://lybgeek.github.com/schema/pipeline/pipeline.xsd=META-INF/pipeline.xsd复制代码
3、定义解析自定义标签的类
public class PipelineNamespaceHandler extends NamespaceHandlerSupport {



@Override
public void init() {
   registerBeanDefinitionParser("pipeline",new PipelineBeanDefinitionParser());
}




}
复制代码
public class PipelineBeanDefinitionParser implements BeanDefinitionParser {



@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
    PipelineConfig pipelineConfig = buildPipelineConfig(element);
    List&lt;HandlerInvotation&gt; handlerInvotations = this.buildHandlerInvotations(pipelineConfig);
    GenericBeanDefinition beanDefinition = getGenericBeanDefinition(element, parserContext, pipelineConfig, handlerInvotations);
    return beanDefinition;
}

private GenericBeanDefinition getGenericBeanDefinition(Element element, ParserContext parserContext, PipelineConfig pipelineConfig, List&lt;HandlerInvotation&gt; handlerInvotations) {
    GenericBeanDefinition beanDefinition = (GenericBeanDefinition) BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
    beanDefinition.getPropertyValues().addPropertyValue("pipelineServiceClz",pipelineConfig.getConsumePipelinesService());
    beanDefinition.getPropertyValues().addPropertyValue("handlerInvotations",handlerInvotations);
    beanDefinition.getPropertyValues().addPropertyValue("createByXml",true);
    beanDefinition.setBeanClass(ComsumePipelineFactoryBean.class);
    String beanName = BeanUtils.generateBeanName(element,"id",parserContext,pipelineConfig.getConsumePipelinesService().getSimpleName());
    parserContext.getRegistry().registerBeanDefinition(beanName,beanDefinition);
    return beanDefinition;
}

@SneakyThrows
private List&lt;HandlerInvotation&gt; buildHandlerInvotations(PipelineConfig pipelineConfig){
    List&lt;HandlerInvotation&gt; handlerInvotations = new ArrayList&lt;&gt;();
    for (PipelineHandlerConfig pipelineHandlerConfig : pipelineConfig.getPipelineChain()) {
        if(!AbstactChannelHandler.class.isAssignableFrom(pipelineHandlerConfig.getPipelineClass())){
            throw new PipelineException("pipelineHandler className must be 【com.github.lybgeek.pipeline.handler.AbstactChannelHandler】 subclass");
        }

        AbstactChannelHandler channelHandler = (AbstactChannelHandler) pipelineHandlerConfig.getPipelineClass().getDeclaredConstructor().newInstance();
        HandlerInvotation invotation = HandlerInvotation.builder()
                .args(pipelineConfig.getArgs())
                .handler(channelHandler)
                .order(pipelineHandlerConfig.getOrder())
                .consumePipelinesMethod(pipelineConfig.getConsumePipelinesMethod())
                .build();
        handlerInvotations.add(invotation);

    }
    return handlerInvotations;
}

@SneakyThrows
private PipelineConfig buildPipelineConfig(Element element){
    String argsType = element.getAttribute("argsType");
    String[] argsTypeArr = trimArrayElements(commaDelimitedListToStringArray(argsType));
    String consumePipelinesMethod = element.getAttribute("consumePipelinesMethod");
    String consumePipelinesServiceClassName = element.getAttribute("consumePipelinesServiceClassName");


    Class[] args = null;
    if(ArrayUtil.isNotEmpty(argsTypeArr)){
        args = new Class[argsTypeArr.length];
        for (int i = 0; i &lt; argsTypeArr.length; i++) {
            Class argType = Class.forName(argsTypeArr[i]);
            args[i] = argType;
        }
    }

    List&lt;PipelineHandlerConfig&gt; pipelineHandlerConfigs = buildPipelineHandlerConfig(element);

    return PipelineConfig.builder().args(args)
            .consumePipelinesMethod(consumePipelinesMethod)
            .consumePipelinesService(Class.forName(consumePipelinesServiceClassName))
            .pipelineChain(pipelineHandlerConfigs)
            .build();
}

@SneakyThrows
private List&lt;PipelineHandlerConfig&gt; buildPipelineHandlerConfig(Element element){
    NodeList nodeList = element.getChildNodes();
    if (nodeList == null) {
        return Collections.emptyList();
    }

    List&lt;PipelineHandlerConfig&gt; pipelineHandlerConfigs = new ArrayList&lt;&gt;();
    for (int i = 0; i &lt; nodeList.getLength(); i++) {
        if (!(nodeList.item(i) instanceof Element)) {
            continue;
        }
        Element childElement = (Element) nodeList.item(i);
        if ("pipelineHandler".equals(childElement.getNodeName()) || "pipelineHandler".equals(childElement.getLocalName())) {
            String pipelineHanlderClassName = childElement.getAttribute("className");
            String pipelineHanlderOrder = childElement.getAttribute("order");
            Class pipelineHanlderClass = Class.forName(pipelineHanlderClassName);
            PipelineHandlerConfig pipelineHandlerConfig = PipelineHandlerConfig.builder()
                    .PipelineClass(pipelineHanlderClass)
                    .order(Integer.valueOf(pipelineHanlderOrder))
                    .build();
            pipelineHandlerConfigs.add(pipelineHandlerConfig);
        }
    }

    return pipelineHandlerConfigs;
}




}
复制代码
4、注册解析类

在META-INF文件夹新建spring.handlers文件,内容如下

http://lybgeek.github.com/schema/pipeline=com.github.lybgeek.pipeline.spring.shema.PipelineNamespaceHandler复制代码

业务项目如何使用该方式实现业务编排

示例:

1、创建管道执行器
@Slf4j
public class UserCheckChannelHandler extends AbstactChannelHandler {



@Override
public boolean handler(ChannelHandlerContext chx) {
    ChannelHandlerRequest channelHandlerRequest = chx.getChannelHandlerRequest();
    System.out.println("XML------------------------------------步骤一:用户数据校验【"+channelHandlerRequest.getRequestId()+"】");
    String json = JSON.toJSONString(channelHandlerRequest.getParams());
    List&lt;User&gt; users = JSON.parseArray(json,User.class);
    if(CollectionUtil.isEmpty(users) || StringUtils.isBlank(users.get(0).getFullname())){
        log.error("用户名不能为空");
        return false;
    }
    return true;


}




}
复制代码
@Slf4j
public class UserFillUsernameAndEmailChannelHandler extends AbstactChannelHandler {
@SneakyThrows
@Override
public boolean handler(ChannelHandlerContext chx) {
ChannelHandlerRequest channelHandlerRequest = chx.getChannelHandlerRequest();
System.out.println("XML------------------------------------步骤二:用户名以及邮箱填充【将汉语转成拼音填充】【"+channelHandlerRequest.getRequestId()+"】");
String json = JSON.toJSONString(channelHandlerRequest.getParams());
List<User> users = JSON.parseArray(json,User.class);
if(CollectionUtil.isNotEmpty(users)){
User user = users.get(0);
String fullname = user.getFullname();
HanyuPinyinOutputFormat hanyuPinyinOutputFormat = new HanyuPinyinOutputFormat();
hanyuPinyinOutputFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
String username = PinyinHelper.toHanYuPinyinString(fullname, hanyuPinyinOutputFormat);
user.setUsername(username);
user.setEmail(username + "@qq.com");
return true;



    }



    return false;
}




}
复制代码

。。。其他执行器具体查看链接代码

2、定义管道xml
<?xml version="1.0" encoding="UTF-8"?>




<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:lybgeek="http://lybgeek.github.com/schema/pipeline"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://lybgeek.github.com/schema/pipeline http://lybgeek.github.com/schema/pipeline/pipeline.xsd">



&lt;lybgeek:pipeline consumePipelinesServiceClassName="com.github.lybgeek.pipeline.spring.test.xml.service.UserXmlService" consumePipelinesMethod="save" argsType="com.github.lybgeek.pipeline.spring.test.model.User"&gt;
    &lt;lybgeek:pipelineHandler className="com.github.lybgeek.pipeline.spring.test.xml.handler.UserCheckChannelHandler" order="1"/&gt;
    &lt;lybgeek:pipelineHandler className="com.github.lybgeek.pipeline.spring.test.xml.handler.UserFillUsernameAndEmailChannelHandler" order="2"/&gt;
    &lt;lybgeek:pipelineHandler className="com.github.lybgeek.pipeline.spring.test.xml.handler.UserPwdEncryptChannelHandler" order="3"/&gt;
    &lt;lybgeek:pipelineHandler className="com.github.lybgeek.pipeline.spring.test.xml.handler.UserMockSaveChannelHandler" order="4"/&gt;
    &lt;lybgeek:pipelineHandler className="com.github.lybgeek.pipeline.spring.test.xml.handler.UserPrintChannleHandler" order="5"/&gt;
&lt;/lybgeek:pipeline&gt;


复制代码
3、创建业务管道类
public interface UserXmlService {
boolean save(User user);
}
复制代码

直接定义接口即可

4、项目启动类上加上@ImportResource("classpath:/pipeline.xml")
@SpringBootApplication
@ImportResource("classpath:/pipeline.xml")
public class SpringPipelineApplication  {



public static void main(String[] args) {
    SpringApplication.run(SpringPipelineApplication.class);
}




}
复制代码
5、测试
    @Test
public void testPipelineXml(){
boolean isOk = userXmlService.save(user);
Assert.assertTrue(isOk);



}</code></pre><p></p><h2>总结</h2><p>本文的管道模式的核心逻辑内核和上篇文章是一样,只是把管道执行器通过配置文件集中管理起来,这个后续维护也比较不容易出错</p><h2>demo链接</h2><p><a href="https://link.segmentfault.com/?enc=vCBa8EMOH2UK5HgT%2FdaQ4Q%3D%3D.87KfMl3PdP7e0VLkJztNPLPBek5VZuMK%2BMNKEQ9MgNm3uHGpbez6uMD0zEb51H2OBrlQScpQpqlxTGIeo%2BxDpeUqjHKK5z0DS9I%2BRXSwq8k%3D" rel="nofollow">https://github.com/lyb-geek/springboot-learning/tree/master/springboot-pipeline</a></p><blockquote>




本文来源:聊聊如何利用管道模式来进行业务编排(下篇)


复制代码

Supongo que te gusta

Origin juejin.im/post/7147723948459819021
Recomendado
Clasificación