Flowable(五):ProcessEngine系列(2)

2023-11-05 11:50

本文主要是介绍Flowable(五):ProcessEngine系列(2),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

Flowable-ProcessEngine

  • Flowable-ProcessEngine流程引擎系列(2)
    • 一、构建原理
      • 1、ProcessEngineConfiguration构建ProcessEngine
      • 2、ProcessEngines构建ProcessEngine
      • 3、总结

Flowable-ProcessEngine流程引擎系列(2)

        我们在上文已经交代了,ProcessEngine在构建过程中的一些配置方面的细节问题,那么接下来,我们就不在用放大镜的思维去研究ProcessEngine的配置的一些细节了,我们将重点放在ProcessEngine的完整构建流程上去!ProcessEngine是怎么一步一步build出来的,相信不止我一个人非常好奇,没有关系,我们现在一起来看下~

一、构建原理

在这里插入图片描述

/*** 构建ProcessEngine* @question 那么构建ProcessEngine有多少种方式呢?* @return 返回一个ProcessEngine*/
private ProcessEngine getProcessEngine(){// 第一类: 直接通过ProcessEngineConfiguration构建ProcessEngine processEngine1 = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("").buildProcessEngine();//ProcessEngineConfiguration.// 第二类 通过ProcessEngines 构建// ProcessEngines默认构建方式ProcessEngine processEngine2 = ProcessEngines.getDefaultProcessEngine();// ProcessEngines 配置文件构建ProcessEngine processEngine3 = ProcessEngines.getProcessEngine("");ProcessEngine processEngine4 = ProcessEngines.getProcessEngines().get("");return null;
}

        上文中我用三分之一的篇幅主要将ProcessEngine的构建讲了一遍,但是只提及了通过ProcessEngineConfiguration的方式构建。实际,我们还可以通过ProcessEngines这个抽象类来构建一个ProcessEngine!

1、ProcessEngineConfiguration构建ProcessEngine

        首先我们来看ProcessEngineConfiguration方式构建的ProcessEngine,这种方式都有几个共性的特点,一类是将IO流转为配置信息,以加载流数据的形式加载配置,一类是通过JavaAPI进行自定义配置。最终都是通过先完成配置类的构建,然后通过配置类去构建ProcessEngine对象。如下图所示:

image-20220826162111142
        所以,套路既然我们都清楚了,接下来就是去搞清楚到底是怎么构建的了。点开ProcessEngineConfiguration类,我们可以直接看见,在buildProcessEngine()下,它含有以下方法,除去最后两个需要加载额外的配置文件以外,其他的方法都是建立在Resource的基础之上的。这其中,有读取默认配置文件的方法,也有加载指定文件的方式,也有加载流的方式进行创建配置类。通过配置类进行配置的时候,有三种方法可以生成流程引擎配置对象:

        (1)第一种:底层方法源自于BeansConfigurationHelper类下,对XML或InputStream数据的解析函数。

        (2)第二种:底层源自于StandaloneProcessEngineConfiguration()函数。

        (3)第三种:底层源自于StandaloneInMemProcessEngineConfiguration()函数。

image-20220826173615615

        我们随便找一个方法作为样例,然后找到他下一个调用的方法,我们以此作为样例,点击进去看看里面的实现:

image-20220826172819417
        点击后,我们会进入到在BeansConfigurationHelper类下:

public class BeansConfigurationHelper {public BeansConfigurationHelper() {}public static AbstractEngineConfiguration parseEngineConfiguration(Resource springResource, String beanName) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);xmlBeanDefinitionReader.setValidationMode(3);xmlBeanDefinitionReader.loadBeanDefinitions(springResource);Collection<BeanFactoryPostProcessor> factoryPostProcessors = beanFactory.getBeansOfType(BeanFactoryPostProcessor.class, true, false).values();if (((Collection)factoryPostProcessors).isEmpty()) {factoryPostProcessors = Collections.singleton(new PropertyPlaceholderConfigurer());}Iterator var5 = ((Collection)factoryPostProcessors).iterator();while(var5.hasNext()) {BeanFactoryPostProcessor factoryPostProcessor = (BeanFactoryPostProcessor)var5.next();factoryPostProcessor.postProcessBeanFactory(beanFactory);}AbstractEngineConfiguration engineConfiguration = (AbstractEngineConfiguration)beanFactory.getBean(beanName);engineConfiguration.setBeans(new SpringBeanFactoryProxyMap(beanFactory));return engineConfiguration;}public static AbstractEngineConfiguration parseEngineConfigurationFromInputStream(InputStream inputStream, String beanName) {Resource springResource = new InputStreamResource(inputStream);return parseEngineConfiguration(springResource, beanName);}public static AbstractEngineConfiguration parseEngineConfigurationFromResource(String resource, String beanName) {Resource springResource = new ClassPathResource(resource);return parseEngineConfiguration(springResource, beanName);}
}

        点击进入后我们不难发现以下情况,跟我们开头说的不差分毫,的的确确,在BeansConfigurationHelper类下,无论给定路径直接加载配置文件的方式还是读取输入流的方式,都是底层通过调用parseEngineConfiguration( )函数实现的解析配置。在此类下的另一个方法:parseEngineConfiguration函数。

image-20220826172918756
        因此,从上一篇文章看到现在,对于ProcessEngineConfiguration的方式构建ProcessEngine配置类(除去其他的半自动配置),看似ProcessEngineConfiguration里面一堆构建ProcessEngineConfiguation的方法,实际上也就三种。一种来自于BeansConfigurationHelper类的私有方法,一种是来自于StandaloneInMemProcessEngineConfiguration类的构造方法,再有就是StandaloneProcessEngineConfiguration的私有构造方法。

2、ProcessEngines构建ProcessEngine

基于ProcessEngines构建ProcessEngine,我们还是根据源码来回顾一下吧。

image-20220829093307842

        我们先看第一个默认的方法构建ProcessEngine,这种方法的下一层是这么实现的:

image-20220829093414128

        这里我们重点解读一下init方法,因为获取ProcessEngine的方法的核心是在初始化了之后从map中获取的。

map是指 return (ProcessEngine)processEngines.get(processEngineName); 这段代码中,他的依赖函数是通过map取出ProcessEngine的。

        那么,init方法主要干了什么事情呢?我们把源码拿过来看看:

        不难发现,最初是初始化了一个map,然后通过XML加载器去加载位于默认位置,也就是classpath下的配置文件,然后读取数据。我们可以发现,同样的一套代码,在这个初始化函数中,写了两遍,说明什么问题呢?说明Flowable不仅仅支持flowable的默认配置文件,也支持通过spring文件进行加载,但是需要注意的是,这里的文件名称是写死的,所以也就是说默认配置如果需要使用的话,需要自行遵守默认配置所依赖的加载的文件名称。

public static synchronized void init() {// 初始化一个mapif (!isInitialized()) {if (processEngines == null) {processEngines = new HashMap();}ClassLoader classLoader = ReflectUtil.getClassLoader();Enumeration resources = null;try {resources = classLoader.getResources("flowable.cfg.xml");} catch (IOException var6) {throw new FlowableIllegalArgumentException("problem retrieving flowable.cfg.xml resources on the classpath: " + System.getProperty("java.class.path"), var6);}HashSet configUrls = new HashSet();while(resources.hasMoreElements()) {configUrls.add(resources.nextElement());}Iterator var3 = configUrls.iterator();while(var3.hasNext()) {URL resource = (URL)var3.next();LOGGER.info("Initializing process engine using configuration '{}'", resource);initProcessEngineFromResource(resource);}try {resources = classLoader.getResources("flowable-context.xml");} catch (IOException var5) {throw new FlowableIllegalArgumentException("problem retrieving flowable-context.xml resources on the classpath: " + System.getProperty("java.class.path"), var5);}while(resources.hasMoreElements()) {URL resource = (URL)resources.nextElement();LOGGER.info("Initializing process engine using Spring configuration '{}'", resource);initProcessEngineFromSpringResource(resource);}setInitialized(true);} else {LOGGER.info("Process engines already initialized");}}

        除此之外,我们也不难发现,这种加载默认配置的方式,也有一个共性,就是同样调用了initProcessEngineFromResource ( ) 函数,那么这就需要我们去研究一下,这个共性方法里面究竟做了那些事情吧!

image-20220829094207057

        接下来我们一起看一下,这个函数的源码:initProcessEngineFromResource ( ) 函数

private static EngineInfo initProcessEngineFromResource(URL resourceUrl) {EngineInfo processEngineInfo = (EngineInfo)processEngineInfosByResourceUrl.get(resourceUrl.toString());String resourceUrlString;if (processEngineInfo != null) {processEngineInfos.remove(processEngineInfo);if (processEngineInfo.getException() == null) {resourceUrlString = processEngineInfo.getName();processEngines.remove(resourceUrlString);processEngineInfosByName.remove(resourceUrlString);}processEngineInfosByResourceUrl.remove(processEngineInfo.getResourceUrl());}resourceUrlString = resourceUrl.toString();try {LOGGER.info("initializing process engine for resource {}", resourceUrl);ProcessEngine processEngine = buildProcessEngine(resourceUrl);String processEngineName = processEngine.getName();LOGGER.info("initialised process engine {}", processEngineName);processEngineInfo = new EngineInfo(processEngineName, resourceUrlString, (String)null);processEngines.put(processEngineName, processEngine);processEngineInfosByName.put(processEngineName, processEngineInfo);} catch (Throwable var5) {LOGGER.error("Exception while initializing process engine: {}", var5.getMessage(), var5);processEngineInfo = new EngineInfo((String)null, resourceUrlString, ExceptionUtils.getStackTrace(var5));}processEngineInfosByResourceUrl.put(resourceUrlString, processEngineInfo);processEngineInfos.add(processEngineInfo);return processEngineInfo;
}

        我们重点关注一下这个函数:

image-20220829094904140

        所以,废话不啰嗦,直接看buildProcessEngine()函数:终于我们找到了源头,我们前面讲了,这种是通过ProcessEngines的默认方式获得ProcessEngine的。所以,默认方式的最底层究竟是怎么实现的,我们现在终于拨云见雾了。原来:ProcessEngines默认方法构建ProcessEngine底层就是通过ProcessEngineConfiguration实现的。

private static ProcessEngine buildProcessEngine(URL resource) {InputStream inputStream = null;ProcessEngine var3;try {inputStream = resource.openStream();ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream);var3 = processEngineConfiguration.buildProcessEngine();} catch (IOException var7) {throw new FlowableIllegalArgumentException("couldn't open resource stream: " + var7.getMessage(), var7);} finally {IoUtil.closeSilently(inputStream);}return var3;
}

image-20220829095303675

        这是偶然吗?我们再看看另一种方法吧:ProcessEngines的另一个函数:ProcessEngines.getProcessEngine(" "); 其实我想,还用看吗?答案呼之欲出了,默认方法底层就是调用的这个方法,传递的是一个固定值default而已啊!

image-20220829100144920
        那有人说,还有一个方法呢?ProcessEngines.getProcessEngines().get(" ");这个,如果你Java基础足够,你应该一眼就看出来,这还是在通过先初始化ProcessEngine的一个Map然后通过key-value在中间做映射啊!
image-20220829100442991
image-20220829100509517

3、总结

        其实我们看了这些源码后,有了很明确的结论:

        (1)ProcessEngine构建的方式方法只有一种,源头就是配置构建,离不开ProcessEngineConfiguration配置类。

        (2)ProcessEngine构建非常依赖于配置,也就告诉你,ProcessEngine高度可定义,ProcessEngine可以通过ProcessEngineConfiguration来进行任意构建。

        好了今天就聊到这里吧,更多精彩,尽在码农修炼笔记!
在这里插入图片描述

这篇关于Flowable(五):ProcessEngine系列(2)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/349659

相关文章

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl

【生成模型系列(初级)】嵌入(Embedding)方程——自然语言处理的数学灵魂【通俗理解】

【通俗理解】嵌入(Embedding)方程——自然语言处理的数学灵魂 关键词提炼 #嵌入方程 #自然语言处理 #词向量 #机器学习 #神经网络 #向量空间模型 #Siri #Google翻译 #AlexNet 第一节:嵌入方程的类比与核心概念【尽可能通俗】 嵌入方程可以被看作是自然语言处理中的“翻译机”,它将文本中的单词或短语转换成计算机能够理解的数学形式,即向量。 正如翻译机将一种语言

flume系列之:查看flume系统日志、查看统计flume日志类型、查看flume日志

遍历指定目录下多个文件查找指定内容 服务器系统日志会记录flume相关日志 cat /var/log/messages |grep -i oom 查找系统日志中关于flume的指定日志 import osdef search_string_in_files(directory, search_string):count = 0

GPT系列之:GPT-1,GPT-2,GPT-3详细解读

一、GPT1 论文:Improving Language Understanding by Generative Pre-Training 链接:https://cdn.openai.com/research-covers/languageunsupervised/language_understanding_paper.pdf 启发点:生成loss和微调loss同时作用,让下游任务来适应预训

Java基础回顾系列-第七天-高级编程之IO

Java基础回顾系列-第七天-高级编程之IO 文件操作字节流与字符流OutputStream字节输出流FileOutputStream InputStream字节输入流FileInputStream Writer字符输出流FileWriter Reader字符输入流字节流与字符流的区别转换流InputStreamReaderOutputStreamWriter 文件复制 字符编码内存操作流(

Java基础回顾系列-第五天-高级编程之API类库

Java基础回顾系列-第五天-高级编程之API类库 Java基础类库StringBufferStringBuilderStringCharSequence接口AutoCloseable接口RuntimeSystemCleaner对象克隆 数字操作类Math数学计算类Random随机数生成类BigInteger/BigDecimal大数字操作类 日期操作类DateSimpleDateForma

Java基础回顾系列-第三天-Lambda表达式

Java基础回顾系列-第三天-Lambda表达式 Lambda表达式方法引用引用静态方法引用实例化对象的方法引用特定类型的方法引用构造方法 内建函数式接口Function基础接口DoubleToIntFunction 类型转换接口Consumer消费型函数式接口Supplier供给型函数式接口Predicate断言型函数式接口 Stream API 该篇博文需重点了解:内建函数式

Java基础回顾系列-第二天-面向对象编程

面向对象编程 Java类核心开发结构面向对象封装继承多态 抽象类abstract接口interface抽象类与接口的区别深入分析类与对象内存分析 继承extends重写(Override)与重载(Overload)重写(Override)重载(Overload)重写与重载之间的区别总结 this关键字static关键字static变量static方法static代码块 代码块String类特

Java基础回顾系列-第六天-Java集合

Java基础回顾系列-第六天-Java集合 集合概述数组的弊端集合框架的优点Java集合关系图集合框架体系图java.util.Collection接口 List集合java.util.List接口java.util.ArrayListjava.util.LinkedListjava.util.Vector Set集合java.util.Set接口java.util.HashSetjava