1. 程式人生 > >activiti 動態配置 activiti 監聽引擎啟動和初始化(高階原始碼篇)

activiti 動態配置 activiti 監聽引擎啟動和初始化(高階原始碼篇)

1.1.1. 前言

使用者故事:現在有這樣一個需求,第一個需求:公司的開發環境,測試環境以及線上環境,我們使用的資料庫是不一樣的,我們必須能夠任意的切換資料庫進行測試和釋出,對資料庫連線字串我們需要加密,保證我們的資料庫連線不能被發現。必須確保我們的資料庫不能暴露出去,第二個需求,我們需要監控activiti 工作流引擎,在流程啟動的之前,我們要保證我們的所有屬性都注入進去,如果有些屬性沒有注入進去,我們是不能讓流程啟動起來的。也就是進行必要餓屬性檢測,如果沒有期望的屬性,直接報錯,在流程例項化之後,輸出log日誌,確保我們的屬性都是正確的。並且監控引擎中所有的值

第一個需求如何解決呢?

我們來看一下常規的資料庫配置,程式的配置如下:

 <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

      <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti"/>

        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>

        <property name="jdbcUsername"

 value="root"/>

  <property name="jdbcPassword" value="123"/>

 </bean>

看到上面的配置,是不是似曾相識的感覺,沒錯就是這麼簡單,但是如何確保能任意的切換呢,仔細想想還是很簡單的,那裡變化隔離那裡嘛,這個時候我們可以把這些這些變化的東西隔離出去,放到jdbc.properties中,新建jdbc.properties把變化的內容設定進去到jdbc.propertiesjdbc.properties內容如下:

jdbcUrl=jdbc:mysql://localhost:3306/activiti

jdbcDriver=com.mysql.jdbc.Driver

jdbcUsername=root

jdbcPassword=123

上面把變化的東西隔離出來,那程式怎麼能夠使用jdbc.properties中的配置資訊呢?這是一個很關鍵的問題,我們之前用的activiti版本是5.12,所以當時的設計就是修改原始碼,主要修改org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl類,在init()方法中我們設計一個鉤子函式,然後子類負責實現上面的這些功能,主要就修改的類是org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl,修改ProcessEngineConfigurationImpl類中的資料庫連線的資訊,由於目前最新的版本activiti 5.19版本,這個版本已經支援了這種實現,具體的實現都差不多,只是我們不用修改原始碼,直接擴充套件了,這不就是軟體設計中的開閉原則。對新增開放對修改關閉。

下面看下activiti 5.19是如何可以實現這種功能需求的。

1.1.2. activiti 原始碼

首先看一下org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl類中的init()方法哪個可以實現這種需求,瞭解底層核心實現才能很方便的擴充套件嘛。

ProcessEngineConfigurationImpl中的init()部分方法如下:

//初始化configurators集合

initConfigurators();

//呼叫configurator.beforeInit方法

configuratorsBeforeInit();

...

//呼叫configurator.configure()方法

configuratorsAfterInit();

上面的三個核心方法實現如下所示:

protected List<ProcessEngineConfigurator> configurators;
protected List<ProcessEngineConfigurator> allConfigurators;
 protected boolean enableConfiguratorServiceLoader = true; // Enabled by default. In certain environments this should be set to false (eg osgi)
  protected void initConfigurators() {
  //初始化陣列集合
  allConfigurators = new ArrayList<ProcessEngineConfigurator>();
  
  // Configurators that are explicitely added to the config
//如果集合存在值就迴圈新增進去
    if (configurators != null) {
      for (ProcessEngineConfigurator configurator : configurators) {
        allConfigurators.add(configurator);
      }
    }
    
    // Auto discovery through ServiceLoader 預設是true
    if (enableConfiguratorServiceLoader) {
    ClassLoader classLoader = getClassLoader();
    if (classLoader == null) {
    classLoader = ReflectUtil.getClassLoader();
    }
    //迴圈新增進去
    ServiceLoader<ProcessEngineConfigurator> configuratorServiceLoader
    = ServiceLoader.load(ProcessEngineConfigurator.class, classLoader);
    int nrOfServiceLoadedConfigurators = 0;
    for (ProcessEngineConfigurator configurator : configuratorServiceLoader) {
    allConfigurators.add(configurator);
    nrOfServiceLoadedConfigurators++;
    }
    
    if (nrOfServiceLoadedConfigurators > 0) {
    log.info("Found {} auto-discoverable Process Engine Configurator{}", nrOfServiceLoadedConfigurators++, nrOfServiceLoadedConfigurators > 1 ? "s" : "");
    }
    //如果集合不為空 存在多個值的話就按照升序排列 根據什麼作為排序規則呢,很顯然根據getPriority中的值進行排序 比如a類getPriority 10 b類getPriority 100 那麼排序後就是 a,b現執行a類對的再執行b類的。
    if (!allConfigurators.isEmpty()) {
    
    // Order them according to the priorities (usefule for dependent configurator)
    Collections.sort(allConfigurators, new Comparator<ProcessEngineConfigurator>() {
    @Override
    public int compare(ProcessEngineConfigurator configurator1, ProcessEngineConfigurator configurator2) {
    int priority1 = configurator1.getPriority();
    int priority2 = configurator2.getPriority();
    
    if (priority1 < priority2) {
    return -1;
    } else if (priority1 > priority2) {
    return 1;
    } 
    return 0;
    }
});
    
    // Execute the configurators
    log.info("Found {} Process Engine Configurators in total:", allConfigurators.size());
    for (ProcessEngineConfigurator configurator : allConfigurators) {
    log.info("{} (priority:{})", configurator.getClass(), configurator.getPriority());
    }
    
    }
    
    }
  }
  //迴圈所有allConfigurators 執行beforeInit方法
  protected void configuratorsBeforeInit() {
  for (ProcessEngineConfigurator configurator : allConfigurators) {
  log.info("Executing beforeInit() of {} (priority:{})", configurator.getClass(), configurator.getPriority());
  configurator.beforeInit(this);
  }
  }
  //迴圈所有allConfigurators 執行configuratorsAfterInit方法
  protected void configuratorsAfterInit() {
  for (ProcessEngineConfigurator configurator : allConfigurators) {
  log.info("Executing configure() of {} (priority:{})", configurator.getClass(), configurator.getPriority());
  configurator.configure(this);
  }
  }


1.1.3. activiti 動態配置實戰

好了上面說了原始碼的實現,下面來點乾貨吧,看看如何使用自定義的類實現修改配置檔案。

我們使用兩個類看他們的執行過程是否跟上面原始碼解析的一直:

定義com.daling.ch1.init.MyProcessEngineConfigurator1如下所示:

@Service
public class MyProcessEngineConfigurator1 extends  AbstractProcessEngineConfigurator{
public static int DEFAULT_CONFIGURATOR_PRIORITY = 100;
public void beforeInit(
ProcessEngineConfigurationImpl processEngineConfiguration) {
System.out.println("1111111111111");
}
 
public void configure(
ProcessEngineConfigurationImpl processEngineConfiguration) {
}
@Override
public int getPriority() {
return DEFAULT_CONFIGURATOR_PRIORITY;
}
 
}
定義com.daling.ch1.init.MyProcessEngineConfigurator2如下所示:
 
@Service
public class MyProcessEngineConfigurator2 extends  AbstractProcessEngineConfigurator{
public static int DEFAULT_CONFIGURATOR_PRIORITY = 200;
public void beforeInit(
ProcessEngineConfigurationImpl processEngineConfiguration) {
System.out.println("2222222222222222");
}
 
public void configure(
ProcessEngineConfigurationImpl processEngineConfiguration) {
}
@Override
public int getPriority() {
return DEFAULT_CONFIGURATOR_PRIORITY;
}
 
}


在spring中開啟 包的掃描程式碼: <context:component-scan base-package="com"/> 

activiti 引擎配置如下所示:

 <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">

        <property name="jdbcUrl" value="jdbc:mysql://localhost3306/activiti"></property>

        <property name="jdbcDriver" value="com.mysql.jdbc.Driver"/>

        <property name="jdbcUsername" value="root"/>

        <property name="jdbcPassword" value="a"/>

    <property name="configurators">

    <list>

   <bean class="com.daling.ch1.init.MyProcessEngineConfigurator2"></bean>

     <bean class="com.daling.ch1.init.MyProcessEngineConfigurator1"></bean>

    </list>

    </property>

<property name="activityFontName" value="宋體"></property>

   </bean>

測試程式碼如下:

ProcessEnginesDemodemo =newProcessEnginesDemo();

RepositoryServicerepositoryService2 =demo.getRepositoryService();

先來執行一下程式看輸出是否正確,部分輸出如下所示:

1111111111111

20:20:18.245 [main] INFO  o.a.e.i.c.ProcessEngineConfigurationImpl - Executing beforeInit() of class com.daling.ch1.init.MyProcessEngineConfigurator2 (priority:200)

2222222222222222

確實說明了程式的執行順序就是按照getPriority()方法值升序執行的。

ProcessEngineConfigurator類的定義如下:

public interface ProcessEngineConfigurator {
/**
 * Called <b>before</b> any initialisation has been done.
 * This can for example be useful to change configuration settings
 * before anything that uses those properties is created.
 *
 * Allows to tweak the process engine by passing the {@link ProcessEngineConfigurationImpl}
   * which allows tweaking it programmatically.
 *
 * An example is the jdbc url. When a {@link ProcessEngineConfigurator} instance
 * wants to change it, it needs to do it in this method, or otherwise
 * the datasource would already have been created with the 'old' value
 * for the jdbc url.
 */
void beforeInit(ProcessEngineConfigurationImpl processEngineConfiguration);
  
  /**
   * Called when the engine boots up, before it is usable, but after
   * the initialisation of internal objects is done.
   *  
   * Allows to tweak the process engine by passing the {@link ProcessEngineConfigurationImpl}
   * which allows tweaking it programmatically.
   *
   * An example is the ldap user/group manager, which is an addition to the engine.
   * No default properties need to be overridden for this (otherwise the {@link #beforeInit(ProcessEngineConfigurationImpl)} 
   * method should be used) so the logic contained in this method is executed
   * after initialisation of the default objects.
   *
   * Probably a better name would be 'afterInit' (cfr {@link #beforeInit(ProcessEngineConfigurationImpl)}),
   * but not possible due to backwards compatibility.
   */
  void configure(ProcessEngineConfigurationImpl processEngineConfiguration);
  
  /**
   * When the {@link ProcessEngineConfigurator} instances are used, they are first
   * ordered by this priority number (lowest to highest).
   * If you have dependencies between {@link ProcessEngineConfigurator}
   * instances, use the priorities accordingly to order them as needed.
   */
  int getPriority();
 
}


ProcessEngineConfigurator類圖關係如下:

 

上面的類圖AbstractProcessEngineConfigurator類實現了ProcessEngineConfigurator介面,AbstractProcessEngineConfigurator是一個抽象類,所以我們使用的時候繼承AbstractProcessEngineConfigurator類複寫裡面的方法即可(模板方法)

上面我們自定義的類MyProcessEngineConfigurator1中的方法

publicvoidbeforeInit(

ProcessEngineConfigurationImplprocessEngineConfiguration){

System.out.println("1111111111111");

}

publicvoidconfigure(

ProcessEngineConfigurationImplprocessEngineConfiguration){

}

我們可以拿到ProcessEngineConfigurationImpl這個物件其實就是StandaloneProcessEngineConfiguration的父類,裡面有很多的屬性我們就可以修改了。

怎麼修改呢?只要拿到這個物件我們就很方便修改了。

具體的修改如下:

//虛擬碼 載入jdbc.properties檔案 獲取配置的值,進行解密然後設定進去 解密演算法後續講解,當然懂的話可以自己直接修改。

descJdbc(ProperUtils.load());

processEngineConfiguration.setJdbcDriver(jdbcDriver);

processEngineConfiguration.setJdbcPassword(jdbcPassword);

processEngineConfiguration.setJdbcUrl(jdbcUrl);

processEngineConfiguration.setJdbcUsername(jdbcUsername)

上面提到的引擎初始化完畢會呼叫configure()中的方法,所以這裡可以自定義實現的功能即可。