• Flowable(五):ProcessEngine系列(2)


    在这里插入图片描述

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

            上文中我用三分之一的篇幅主要将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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

            点击进入后我们不难发现以下情况,跟我们开头说的不差分毫,的的确确,在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() {
        // 初始化一个map
        if (!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");
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

            除此之外,我们也不难发现,这种加载默认配置的方式,也有一个共性,就是同样调用了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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

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

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    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来进行任意构建。

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

  • 相关阅读:
    使用百度EasyDL语音识别打造Smart汽车原创音乐
    Java PipedReader类简介说明
    Audio参数讲解
    C、指针基础1
    【C++】深度解剖多态
    告别HR管理繁琐,免费低代码平台来帮忙
    什么软件可以语音转文字?快把这些软件收好
    LeetCode50天刷题计划(Day 25— 旋转图像(11.20-12.30)
    数据结构零基础入门篇(C语言实现)
    K8S内容分发网络之集群,nginx,负载均衡,防火墙
  • 原文地址:https://blog.csdn.net/weixin_44085593/article/details/127124985