activiti6.0源碼剖析之流程引擎ProcessEngine的獲取

感謝冀正,張志祥前輩《Activiti權(quán)威指南》

activiti源碼剖析--流程引擎ProcessEngine的獲取

前言

本篇文章通過源碼進行分析ProcessEngine是如何被創(chuàng)建出來热凹,在學習activiti的同時宽闲,通過源碼進行分析以對activiti流程引擎進行更深層次的理解深入。

一弊知、流程配置文件

Acticiti配置文件的風格使用了Spring中的文件配置方式阻逮,這樣有什么好處呢?那當然從Spring的特性IOC說起秩彤,依賴注入叔扼,控制反轉(zhuǎn),這里就不再多說漫雷,選取這樣的配置方式也說明了瓜富,Activiti在設(shè)計之時就考慮到了與spring的融合。activiti的配置文件類型分為 普通配置 和Spring配置(這里說明一下降盹,activiti的配置文件方式采用Spring方式食呻,但是activiti可以集成Spring開發(fā),也可以不集成,所以后者的Spring配置方式其實也就是集成Spring進行開發(fā))

  • 普通配置文件名稱為activiti.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans.xsd">
       
    <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/db_activiti" />
        <property name="jdbcDriver" value="com.mysql.jdbc.Driver" />
        <property name="jdbcUsername" value="root" />
        <property name="jdbcPassword" value="1234" />
        <property name="databaseSchemaUpdate" value="true" />
    </bean>
</beans>
  • Spring配置文件名稱為activiti-context.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--配置數(shù)據(jù)源-->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_activiti"/>
        <property name="username" value="root"/>
        <property name="password" value="1234"/>
    </bean>
    <!--配置事務(wù)管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入數(shù)據(jù)源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--配置注解方式配置事務(wù)-->
    <tx:annotation-driven  proxy-target-class="true" transaction-manager="transactionManager"/>
    <!--定義基于Spring的引擎配置對象BEAN-->
    <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
        <property name="dataSource" ref="dataSource"/>
        <property name="transactionManager" ref="transactionManager"/>
        <property name="databaseSchemaUpdate" value="true"/>
        <property name="deploymentResources" value="classpath:userAndGroupTest.bpmn20.xml"/>
        <!--<property name="jobExecutorActivate" value="false"/>-->
    </bean>

    <!--配置引擎工廠對象BEAN-->
    <bean id="processEngineFactory" class="org.activiti.spring.ProcessEngineFactoryBean">
        <property name="processEngineConfiguration" ref="processEngineConfiguration"/>
    </bean>

    <!--使用spring提供的工廠方式獲取actititi7個service接口對象-->
    <bean id="repositoryService" factory-bean="processEngineFactory" factory-method="getRepositoryService"/>
   ....7大服務(wù)
</beans>

二仅胞、構(gòu)造流程引擎實例對象

獲取流程引擎實例對象代碼如下

        ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
        //這里也可以通過自定義流程引擎名稱獲取
        //ProcessEngines.getProcessEngine(String processEngineName)

        RepositoryService repositoryService = defaultProcessEngine.getRepositoryService();
        assert repositoryService !=null;

ProcessEngines:該類負責管理所有的流程引擎ProcessEngine集合每辟,并負責流程引擎實例對象的注冊、獲取干旧、注銷等操作渠欺。

只需要ProcessEngines.getDefaultProcessEngine();一句話即可獲取到我們的重要角色:processEngine,那么它是怎么被獲取到的呢椎眯?接下來圍繞這一話題進行源碼剖析挠将。

ProcessEngines.java源碼

    public static ProcessEngine getDefaultProcessEngine() {
        return getProcessEngine("default");
    }

相信從這里也可看出來,在通過ProcessEngines獲取流程引擎的時候编整,不管使用默認的方式還是通過指定流程引擎名稱舔稀,其實都是調(diào)用的ProcessEngine(processEngineName)方法獲取

    public static ProcessEngine getProcessEngine(String processEngineName) {
        if (!isInitialized()) {
            init();
        }
        return (ProcessEngine)processEngines.get(processEngineName);
    }

在獲取流程引擎的前提要先進行初始化。如果已經(jīng)完成初始化掌测,那么返回指定名稱的流程引擎對象内贮。從這里也可以看出Activiti支持多個流程引擎實例對象一起運行,通過流程引擎名稱進行區(qū)分汞斧。

protected static Map<String, ProcessEngine> processEngines = new HashMap();

在這里processEngines為MAP結(jié)構(gòu)夜郁,key為流程引擎名稱,value為流程引擎實例對象粘勒。

接下來看看Activiti是如何做初始化準備工作的

    public static synchronized void init() {
        
        if (!isInitialized()) {
            if (processEngines == null) {
                processEngines = new HashMap();
            }

            ClassLoader classLoader = ReflectUtil.getClassLoader();
            Enumeration resources = null;

            try {
                resources = classLoader.getResources("activiti.cfg.xml");
            } catch (IOException var6) {
                throw new ActivitiIllegalArgumentException("problem retrieving activiti.cfg.xml resources on the classpath: " + System.getProperty("java.class.path"), var6);
            }

            HashSet configUrls = new HashSet();

            while(resources.hasMoreElements()) {
                configUrls.add(resources.nextElement());
            }

            Iterator iterator = configUrls.iterator();

            while(iterator.hasNext()) {
                URL resource = (URL)iterator.next();
                log.info("Initializing process engine using configuration '{}'", resource.toString());
                initProcessEngineFromResource(resource);
            }

            try {
                resources = classLoader.getResources("activiti-context.xml");
            } catch (IOException var5) {
                throw new ActivitiIllegalArgumentException("problem retrieving activiti-context.xml resources on the classpath: " + System.getProperty("java.class.path"), var5);
            }

            while(resources.hasMoreElements()) {
                URL resource = (URL)resources.nextElement();
                log.info("Initializing process engine using Spring configuration '{}'", resource.toString());
                initProcessEngineFromSpringResource(resource);
            }

            setInitialized(true);
        } else {
            log.info("Process engines already initialized");
        }

    }

首先再次判斷確認流程引擎是否已經(jīng)被初始化竞端。 接下的工作就是定位activiti配置文件啦,(在這里可以看到是從根路徑中加載配置文件庙睡,為什么的話事富,可以從這里補充補充知識getClass().getResource()和classLoader.getResource())這里也可以看出activiti配置文件的名稱啦。

普通配置文件(activiti.cfg.xml)通過initProcessEngineFromResource(resource);進行初始化加載乘陪,集成spring配置文件通過initProcessEngineFromSpringResource(resource);進行初始化加載赵颅。

2.1、初始化流程引擎之普通配置文件

再進入initProcessEngineFromResource(resource)首先是做了大量的準備工作暂刘,準備工作其實也就是清除已經(jīng)存在同名稱的流程引擎信息饺谬,之后調(diào)用buildProcessEngine(resourceUrl)構(gòu)造流程引擎實例對象,然后放入新的流程引擎信息相關(guān)信息谣拣。

    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 ActivitiIllegalArgumentException("couldn't open resource stream: " + var7.getMessage(), var7);
        } finally {
            IoUtil.closeSilently(inputStream);
        }

        return var3;
    }

buildProcessEngine(resourceUrl) 中進入ProcessEngineConfiguration processEngineConfiguration = ProcessEngineConfiguration.createProcessEngineConfigurationFromInputStream(inputStream);核心代碼

    public static ProcessEngineConfiguration createProcessEngineConfigurationFromInputStream(InputStream inputStream) {
        return createProcessEngineConfigurationFromInputStream(inputStream, "processEngineConfiguration");
    }

    public static ProcessEngineConfiguration createProcessEngineConfigurationFromInputStream(InputStream inputStream, String beanName) {
        return BeansConfigurationHelper.parseProcessEngineConfigurationFromInputStream(inputStream, beanName);
    }

從以上代碼可以看出是在獲取通過spring容器管理的id為processEngineConfiguration的bean對象募寨。即org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration(配置文件中配置)。之后Spring會解析xml配置文件實例化org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration對象

ProcessEngineConfigurationImpl類結(jié)構(gòu).png

在實例化org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration的同時森缠,也會對其父類進行初始化拔鹰,點擊ProcessEngineConfigurationImpl類進入查看

    protected RepositoryService repositoryService = new RepositoryServiceImpl();
    protected RuntimeService runtimeService = new RuntimeServiceImpl();
    protected HistoryService historyService = new HistoryServiceImpl(this);
    protected IdentityService identityService = new IdentityServiceImpl();
    protected TaskService taskService = new TaskServiceImpl(this);
    protected FormService formService = new FormServiceImpl();
    protected ManagementService managementService = new ManagementServiceImpl();
    protected DynamicBpmnService dynamicBpmnService = new DynamicBpmnServiceImpl(this);

也就是在進行各種服務(wù)類對象的初始化。在這里完成了對流程引擎配置對象的初始化贵涵,注意上述buildProcessEngine(resourceUrl)中在初始化流程引擎配置對象之后列肢,通過流程引擎配置對象來build processEngine,var3 = processEngineConfiguration.buildProcessEngine();這里方法的實現(xiàn)是在各種配置類的父類(ProcessEngineConfigurationImpl)中進行了實現(xiàn)

ProcessEngineConfigurationImpl.java

   public ProcessEngine buildProcessEngine() {
        this.init();
        ProcessEngineImpl processEngine = new ProcessEngineImpl(this);
        if (this.isActiviti5CompatibilityEnabled && this.activiti5CompatibilityHandler != null) {
            Context.setProcessEngineConfiguration(processEngine.getProcessEngineConfiguration());
            this.activiti5CompatibilityHandler.getRawProcessEngine();
        }

        this.postProcessEngineInitialisation();
        return processEngine;
    }

該操作完成了以下操作:

  • 調(diào)用init方法初始化了各種屬性值

    這里呢就是對一些諸如數(shù)據(jù)源恰画、配置器、流程圖片生成器瓷马、表達式管理器等一系列的初始化拴还。

  • 實例化ProcessEngineImpl類

    那么這里就是實例化流程引擎的重頭戲了∨菲福看代碼實現(xiàn)

    public ProcessEngineImpl(ProcessEngineConfigurationImpl processEngineConfiguration) {
        this.processEngineConfiguration = processEngineConfiguration;
        this.name = processEngineConfiguration.getProcessEngineName();
        this.repositoryService = processEngineConfiguration.getRepositoryService();
       ....這里就是在填充7大服務(wù)對象
        this.dynamicBpmnService = processEngineConfiguration.getDynamicBpmnService();
        this.asyncExecutor = processEngineConfiguration.getAsyncExecutor();//異步作業(yè)執(zhí)行器
        this.commandExecutor = processEngineConfiguration.getCommandExecutor();//命令執(zhí)行器
        this.sessionFactories = processEngineConfiguration.getSessionFactories();
        this.transactionContextFactory = processEngineConfiguration.getTransactionContextFactory();//事務(wù)
       ...
        if (processEngineConfiguration.isUsingRelationalDatabase() && processEngineConfiguration.getDatabaseSchemaUpdate() != null) {
            this.commandExecutor.execute(processEngineConfiguration.getSchemaCommandConfig(), new SchemaOperationsProcessEngineBuild());//這里就是通過databaseSchemaUpdate值進行數(shù)據(jù)庫生成策略
        }
       ...

        ProcessEngines.registerProcessEngine(this);//注冊流程引擎
        if (this.asyncExecutor != null && this.asyncExecutor.isAutoActivate()) {
            this.asyncExecutor.start();//啟動異步執(zhí)行器
        }

        if (processEngineConfiguration.getProcessEngineLifecycleListener() != null) {
            processEngineConfiguration.getProcessEngineLifecycleListener().onProcessEngineBuilt(this);//觸發(fā)流程引擎生命周期監(jiān)聽器
        }
 processEngineConfiguration.getEventDispatcher().dispatchEvent(ActivitiEventBuilder.createGlobalEvent(ActivitiEventType.ENGINE_CREATED));
    }

上述代碼看出片林,在對一些屬性裝配完成之后,操作引擎表(具體策略以及如何生成看這里activiti源碼剖析之操作引擎表)之后注冊流程引擎怀骤,也就是將processEngineImpl實例對象注冊進ProssEngines中费封,到這里想必已經(jīng)明白了文章開始代碼,ProcessEngines是如何獲取到processEngine的蒋伦。

到這里弓摘,大致已經(jīng)明白是ProcessEngine流程引擎是如何初始化并且注冊進processEngines流程引擎管理對象了。

希望大家指正痕届,內(nèi)容也會隨著學習深入與實踐的過程中進行改善

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末韧献,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子爷抓,更是在濱河造成了極大的恐慌势决,老刑警劉巖阻塑,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蓝撇,死亡現(xiàn)場離奇詭異,居然都是意外死亡陈莽,警方通過查閱死者的電腦和手機渤昌,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來走搁,“玉大人独柑,你說我怎么就攤上這事∷街玻” “怎么了忌栅?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長曲稼。 經(jīng)常有香客問我索绪,道長,這世上最難降的妖魔是什么贫悄? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任瑞驱,我火速辦了婚禮,結(jié)果婚禮上窄坦,老公的妹妹穿的比我還像新娘唤反。我一直安慰自己凳寺,他們只是感情好,可當我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布彤侍。 她就那樣靜靜地躺著肠缨,像睡著了一般。 火紅的嫁衣襯著肌膚如雪拥刻。 梳的紋絲不亂的頭發(fā)上怜瞒,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天,我揣著相機與錄音般哼,去河邊找鬼吴汪。 笑死,一個胖子當著我的面吹牛蒸眠,可吹牛的內(nèi)容都是我干的漾橙。 我是一名探鬼主播,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼楞卡,長吁一口氣:“原來是場噩夢啊……” “哼霜运!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蒋腮,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤淘捡,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后池摧,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體焦除,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年作彤,在試婚紗的時候發(fā)現(xiàn)自己被綠了膘魄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡竭讳,死狀恐怖创葡,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情绢慢,我是刑警寧澤灿渴,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站胰舆,受9級特大地震影響骚露,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜思瘟,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一荸百、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧滨攻,春花似錦够话、人聲如沸蓝翰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽畜份。三九已至,卻和暖如春欣尼,著一層夾襖步出監(jiān)牢的瞬間爆雹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工愕鼓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留钙态,地道東北人。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓菇晃,卻偏偏與公主長得像册倒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子磺送,可洞房花燭夜當晚...
    茶點故事閱讀 43,566評論 2 349