16.客戶端服務(wù)器配置
概述
URule Pro支持三種運行模式,分(fēn)别是嵌入模式、分(fēn)布式計算模式以及獨立服務(wù)模式,實際使用(yòng)時,根據項目情況三選一即可(kě)。
所謂的嵌入模式就是将URule嵌入到目标應用(yòng)當中(zhōng)運行,這種模式的特點部署起來簡單、方便,便于系統開發與調試; 分(fēn)布式計算模式就是把計算分(fēn)布到各個應用(yòng)當中(zhōng),規則服務(wù)器隻負責規則的構建、打包與測試,具(jù)體(tǐ)的規則計算發生在計算應用(yòng)當中(zhōng),規則服務(wù)器通過Http協議将知識包推送到各個計算應用(yòng),分(fēn)布式計算模式适用(yòng)于單個服務(wù)器不強,規則計算時需要的輸入數據結構複雜的情況。
最後一種就是獨立服務(wù)模式,這種模式也是傳統規則引擎采用(yòng)的模式,那就是規則服務(wù)器通過暴露Restful服務(wù)來接收各種類型規則計算請求,請求把輸入數據以JSON格式提供,在一台服務(wù)器上完成所有(yǒu)類型的規則計算,計算完成後再把輸出數據以JSON格式返回, 在第22小(xiǎo)節知識包Restful服務(wù)暴露與調用(yòng)中(zhōng)詳細介紹了這種模式的配置及使用(yòng)方式,本小(xiǎo)節将隻對嵌入模式和分(fēn)布式計算模式兩種類型結構進行介紹。
在之前介紹的内容當中(zhōng),安(ān)裝(zhuāng)與配置一節介紹的項目創建配置方式就是采用(yòng)的嵌入模式,在嵌入式模式下URule Pro相關Jar包與業務(wù)應用(yòng)一起打包,作(zuò)為(wèi)一個應用(yòng)來進行部署,這種模式結構比較簡單,開發、部署起來都比較容易。
再來看看分(fēn)布式計算模式示意图:
在分(fēn)布式計算模式下,包含URule Pro Console模塊的應用(yòng)被部署成一個獨立的Server,在這個Server上創建規則項目,在項目中(zhōng)根據業務(wù)需求添加決策集、決策表、交叉決策表、決策樹、評分(fēn)卡、複雜評分(fēn)卡、決策流等,再把這些文(wén)件打包到知識包中(zhōng),最後通過HTTP協議暴露給各個客戶端業務(wù)系統使用(yòng)。
分(fēn)布式計算模式下客戶端獲取服務(wù)端知識包的方式:
在分(fēn)布式計算模式下,URule Server上給客戶端提供的是若幹個已經構建好的知識包對象,當有(yǒu)客戶端需要進行規則計算時,它會檢查當前客戶端中(zhōng)配置的“urule.knowledgeUpdateCycle”屬性值,如果為(wèi)0,那麽就直接請求URule Server獲取指知識包;如果為(wèi)1,那麽它會首先檢查客戶端本地緩存當中(zhōng)是否存在指定的知識包,如果存在,就取本地緩存中(zhōng)的,如果不存在,則到URule Server下請求指定的知識包,然後将請求到的知識包緩存到客戶端内存中(zhōng),這樣下次就不再到URule Server上下載;如果“urule.knowledgeUpdateCycle”屬性值大于1,那麽客戶端會首先檢查本地緩存中(zhōng)是否存在指定的知識包,如果存在,那麽就拿(ná)當前時間與本地緩存中(zhōng)的知識包的時間戳進行比較,如果小(xiǎo)于“urule.knowledgeUpdateCycle”屬性值,那麽就直接取這個知識包,如果大于它,那麽就到URule Server上通過時間戳檢查當前知識包有(yǒu)沒有(yǒu)更新(xīn),如果有(yǒu)更新(xīn)則取到客戶端,同時更新(xīn)客戶端緩存裏對應的知識包;如果沒有(yǒu)更新(xīn),那麽就直接采用(yòng)當前客戶端緩存裏的知識包。。
搭建Server應用(yòng)
搭建URule Server應用(yòng)的與安(ān)裝(zhuāng)與配置一節中(zhōng)介紹的完全相同,就是在一個普通的java web應用(yòng)中(zhōng)将URule Pro Console模塊和URule Pro Core添加進去。需要注意的是,在URule Server應用(yòng)搭建好了之後,要保證“/urule/loadknowledge”這個URL在可(kě)以匿名(míng)訪問,比如輸入類似下面的地址,看看應用(yòng)會有(yǒu)什麽樣的響應。
在系統未登錄的情況下,訪問上述URL看到的不是一個登錄頁(yè)面,那麽就說明“/urule/loadknowledge”這個URL在可(kě)以匿名(míng)訪問,是OK的。
如果出現我們應用(yòng)中(zhōng)的登錄界面之類,那就說明“/urule/loadknowledge”這個URL被我們自己系統内部的權限模塊給攔截了,需要我們在系統中(zhōng)對内部的權限進行配置,使得“/urule/loadknowledge”URL在可(kě)以匿名(míng)訪問。做好這個工(gōng)作(zuò),那麽URule Server的搭建工(gōng)作(zuò)就完成了,下面我們看看如果配置客戶端應用(yòng)。
配置客戶端應用(yòng)
配置客戶端應用(yòng),首先要解決的是如果将URule Pro客戶端所需要的jar包添加到項目中(zhōng),這裏我們分(fēn)maven項目以及非maven項目分(fēn)别進行讨論。
maven項目配置
如果當前客戶端是基于maven的項目,那麽我們需要在其pom.xml中(zhōng)添加以下依賴:
<dependency>
<groupId>com.bstek.urule</groupId>
<artifactId>urule-core-pro</artifactId>
<version>3.0.3</version>
</dependency>
可(kě)以看到,在客戶端當中(zhōng)就不再需要urule-console-pro模塊了,隻需要一個urule-core-pro模塊即可(kě)。
上面的maven依賴中(zhōng),我們使用(yòng)的是3.0.3版本,實際使用(yòng)時,可(kě)以在網頁(yè)中(zhōng)打開https://search.maven.org/,查詢“urule-core-pro”關鍵字,找到最新(xīn)的urule-core-pro的版本信息,以确定在依賴中(zhōng)version位置要輸入的版本号信息。
到這裏,pom的配置就完成了,我們再來看看一個标準的非maven的Web項目如何配置成URule Pro客戶端。
非maven項目配置
如果是一個非maven普通的java web項目,添加URule Pro客戶端就是将urule-core-pro的jar包及其依賴的第三方jar包放到客戶端應用(yòng)的/WEB-INF/lib目錄下即可(kě),urule-core-pro的jar包我們可(kě)以到https://search.maven.org/上下載最新(xīn)的urule-core-pro-2.x的jar包,對于依賴的第三方jar包,可(kě)以點擊此處下載。
加載spring配置文(wén)件
URule Pro客戶端所需要的jar包添加到客戶端項目中(zhōng)後,接下來我們還需要加載urule-core-pro模塊中(zhōng)的spring配置文(wén)件。urule-core-pro模塊中(zhōng)的spring配置文(wén)件位于classpath根下,名(míng)為(wèi)urule-core-context.xml。
如果我們的客戶端項目沒有(yǒu)采用(yòng)spring框架,那麽可(kě)以在web.xml中(zhōng)添加如下所示Listener來加載urule-core模塊中(zhōng)的spring配置文(wén)件:
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:urule-core-context.xml</param-value>
</context-param>
如果我們的項目也采用(yòng)了spring框架,那麽隻需要打開項目中(zhōng)任意一個spring配置文(wén)件,在其中(zhōng)添加如下配置即可(kě):
<import resource="classpath:urule-core-context.xml"/>
這樣urule-core-pro的spring配置文(wén)件的加載配置就完成了。
配置服務(wù)器地址
對于URule Pro客戶端應用(yòng)來說,在進行規則計算時,如果客戶端本地緩存沒有(yǒu)相應的知識包,那麽它會到URule Server上請求對應的知識包,要給URule Pro客戶端應用(yòng)配置對應的URule Server地址,我們需要添加一個properties文(wén)件,比如在項目的WEB-INF目錄下新(xīn)建一個名(míng)為(wèi)configure的properties文(wén)件,然後在我們項目中(zhōng)任意一個spring配置文(wén)件中(zhōng)添加如下配置加載這個properties文(wén)件:
<bean parent="urule.props">
<property name="location">
<value>/WEB-INF/configure.properties</value>
</property>
</bean>
打開這個configure.properties文(wén)件,在其中(zhōng)添加一個名(míng)為(wèi)“urule.resporityServerUrl”屬性,比如 urule.resporityServerUrl=http://192.168.18.11:8080/urule-server , 就表明我們為(wèi)當前URule客戶端應用(yòng)配置的URule Server為(wèi)“http://192.168.18.11:8080/urule-server”,這樣在進行規則計算時,如果客戶端本地緩存沒有(yǒu)相應的知識包,那麽它會到“http://192.168.18.11:8080/urule-server”上請求對應的知識包。
從2.1.1版本開始,urule-pro提供了動态加載Jar包及Spring配置文(wén)件功能(néng),具(jù)體(tǐ)見21.Spring Bean及Java類的熱部署描述,如果我們使用(yòng)的是urule-pro-2.1.1及以上版本, 那麽在采用(yòng)客戶端服務(wù)器模式配置應用(yòng)時,客戶端配置了“urule.resporityServerUrl”屬性後,客戶端在啓動時會自動到服務(wù)端檢查是否有(yǒu)新(xīn)的動态Jar文(wén)件信息需要加載,如果有(yǒu)則下載到客戶端并加載, 所以這時服務(wù)端的“urule/dynamic/checkLatestJarsDir”和“urule/dynamic/loadDynamicJars”這兩個URL要保證匿名(míng)可(kě)訪問,否則客戶端啓動時會産(chǎn)生錯誤。
到這裏,URule Pro客戶端的配置就全部完成了,通過指定urule.resporityServerUrl屬性值,我們的客戶端無論是标準的Java Web應用(yòng)還是普通的Java應用(yòng),都可(kě)以與URule Server連接,從而在運行時獲取到相應的知識包。
但是,如果我們的客戶端應用(yòng)是标準的Java Web應用(yòng),那麽除了可(kě)以通過urule.resporityServerUrl屬性指定URule Server地址,從而主動獲取知識包外,還可(kě)以通過配置一個Servlet被動接收URule Server推送過來的知識包,這樣模式,相比主動獲取知識包方式要高效的多(duō),同時還可(kě)以時刻與Server上的知識包保持同步。
下面就來看看如何給一個類型為(wèi)标準Java Web應用(yòng)的客戶端配置接收服務(wù)端推送過來知識包的Servlet。
配置web.xml
在之前内容中(zhōng)我們就提過,URule Pro的客戶端即可(kě)以是标準的Java Web應用(yòng),也可(kě)以是普通的Java應用(yòng)。如果是普通Java應用(yòng),那麽上面的那麽配置就可(kě)以了;如果是标準的Java Web應用(yòng),那麽我們還可(kě)以做些配置,使得其以主動接收來自URule Server上推送過來的最新(xīn)的知識包。
對于URule Server來說,如果在規則項目中(zhōng)配置了URule的客戶端地址,那麽在知識包發布時會自動推送到這些客戶端。所以我們的URule Pro客戶端如果是個标準的Java Web應用(yòng),那麽可(kě)以配置一個可(kě)以接收URule Server推送的知識包的Servlet。
打開項目的web.xml,在其中(zhōng)添加如下servlet配置:
<servlet>
<servlet-name>uruleClientServlet</servlet-name>
<servlet-class>com.bstek.urule.KnowledgePackageReceiverServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>uruleClientServlet</servlet-name>
<url-pattern>/knowledgepackagereceiver</url-pattern>
</servlet-mapping>
在上面的servlet配置中(zhōng),url-pattern項的“/knowledgepackagereceiver”值是固定的,不能(néng)修改為(wèi)其它值,否則将無法收到URule Server上推送過來的知識包。 同時,客戶端中(zhōng)的這個用(yòng)于接收知識包推送的Servlet還要保證其可(kě)以匿名(míng)訪問,也就是客戶端中(zhōng)如果被權限框架包裹,那麽要保證“/knowledgepackagereceiver”這個URL在不登錄的情況下就可(kě)以訪問, 否則服務(wù)端将無法把知識包推送到目标客戶端。
要實現推送功能(néng),除了要配置對應Java Web客戶端上的Servlet,還需要在URule Server上對可(kě)以接收推送的客戶端進行定義。
URule Server上客戶端配置
打開URule Pro的控制台,在規則項目中(zhōng)點擊右鍵,在彈出的菜單中(zhōng)選擇“配置接收推送客戶端”,就可(kě)以打開客戶端配置頁(yè)面,如下图:
我們可(kě)以添中(zhōng)多(duō)個客戶端,這樣在當前項目發布知識包時就可(kě)以自動推送到這裏的客戶端上,如下图:
配置完成後,點擊當前項目的“知識包”節點,選擇任意一個知識包,在知識包操作(zuò)菜單中(zhōng)點擊“發布新(xīn)知識包”菜單項,知識包發布成功後會看到如下图所示的提示:
點擊“确定”,系統會嘗試向這些客戶端推送當前發布的知識包對象,如果這些客戶端是存在的,就可(kě)以發布成功,這樣對應的客戶端本地緩存中(zhōng)就會存儲這個發布的知識包對象。
實際使用(yòng)當中(zhōng),如果希望向客戶端推送某個已發布的知識包版本,我們也可(kě)以點擊知識包操作(zuò)菜單中(zhōng)“已發布的知識包”菜單項,在彈出的窗口當中(zhōng),可(kě)以看到所有(yǒu)已經發布的知識包列表,如下图所示:
如果需要将某個知識包推送到客戶端,那麽可(kě)以點擊上图中(zhōng)紅框内按鈕,這樣就可(kě)以将當前版本知識包推送到客戶端當中(zhōng)。
客戶端動态配置
實際使用(yòng)時,我們可(kě)能(néng)會在諸如docker之類的容器中(zhōng)部署客戶端應用(yòng),在這種情況下,客戶端的IP地址不是固定的,此時要在服務(wù)端指定客戶地址的話,采用(yòng)上面的方法就行不通了。 為(wèi)了兼容這種客戶端IP地址動态變化的場景,URule Pro當中(zhōng)還提供了一個名(míng)為(wèi)ClientProvider接口,通過實現這個接口來動态指定客戶端IP地址,ClientProvider接口類源碼如下:
package com.bstek.urule.console.repository;
import java.util.List;
/**
* @author Jacky.gao
* @since 2019年12月29日
*/
public interface ClientProvider {
/**
* @param project 規則項目名(míng)稱
* @param all 是否加載所有(yǒu)的客戶端信息,如果為(wèi)true,則包括禁用(yòng)的客戶端信息
* @return 返回客戶端地址的集合
*/
List<ClientConfig> loadClients(String project,boolean all);
}
實現了ClientProvider接口後,隻需要将實現類配置到Spring上下文(wén)當中(zhōng),使之成為(wèi)一個标準的Spring Bean即可(kě),這樣引擎在獲取配置的客戶端信息時就會嘗試從這個實現類中(zhōng)獲取。 下面是我們編寫的一個測試用(yòng)的ClientProvider接口實現類:
package test;
import java.util.ArrayList;
import java.util.List;
import com.bstek.urule.console.repository.ClientConfig;
import com.bstek.urule.console.repository.ClientProvider;
public class TestClientProvider implements ClientProvider {
@Override
public List<ClientConfig> loadClients(String project, boolean all) {
List<ClientConfig> list=new ArrayList<ClientConfig>();
ClientConfig cc=new ClientConfig();
list.add(cc);
cc.setName("測試");
cc.setClient("www.baidu.com");
cc.setEnabled(true);
cc.setProject("保險行業示例項目");
return list;
}
}
将該實現類配置到Spring當中(zhōng),重啓應用(yòng),再次打開項目中(zhōng)“配置接收推送客戶端”頁(yè)面,則會看到如下图所示效果:
可(kě)以看到當前頁(yè)面會把實現類中(zhōng)配置的客戶端信息展示出來,同時該頁(yè)面也不再提供客戶端信息的編輯功能(néng)。
前面我們介紹了在URule Pro客戶端中(zhōng)配置“urule.knowledgeUpdateCycle”屬性的含義及目的,一旦我們在URule Server中(zhōng)配置了客戶端地址,那麽知識包每次發布都會被推送到這些客戶端。這樣在生産(chǎn)環境下,對于客戶端來說,“urule.knowledgeUpdateCycle”屬性值隻要設置成1即可(kě),也就是每次都在客戶端本地緩存中(zhōng)查找目标知識包是否存在,如果存在直接使用(yòng)。如果知識包有(yǒu)更新(xīn),URule Server會動推送到目标客戶端,對于客戶端來說直接從本地緩存中(zhōng)就可(kě)以取到最新(xīn)的知識包,這樣可(kě)以剔除所有(yǒu)不必要的客戶端與服務(wù)端的交互,節省網絡資源,同時可(kě)以大幅提高客戶端規則計算性能(néng)。
我們在對URule Pro進行性能(néng)測試時,一定要将“urule.knowledgeUpdateCycle”屬性值隻要設置成1,因為(wèi)“urule.knowledgeUpdateCycle”屬性值默認為(wèi)0,所以每次執行規則都會編譯一次規則包,這樣會帶來很(hěn)差的測試結果,所以這點非常關鍵; 在客戶端中(zhōng),将“urule.knowledgeUpdateCycle”設置成1後,檢驗該屬性是否生效最好的方法是在客戶端調用(yòng)服務(wù)端知識包時觀察控制台是否有(yǒu)類似“Load knowledgepackage [ packageId ] from remote...”這樣的字符輸出,如果有(yǒu)類似輸出,則說明urule.knowledgeUpdateCycle=1未生效, 我們需要進一步檢查配置,找到未生效的原因。 同時,名(míng)為(wèi)"urule.debug"的屬性也會對性能(néng)産(chǎn)生一點影響,這個屬性值默認為(wèi)true,表示允許進行調試信息輸出,這樣對于性能(néng)測試來說無疑會造成影響,所以在性能(néng)測試或生産(chǎn)環境中(zhōng)建議将“urule.debug”屬性設置為(wèi)false,這樣可(kě)以減少不必要的調試信息輸出,可(kě)顯著提升性能(néng)。