客戶端服務(wù)器模式
在客戶端服務(wù)器模式下,包含URule Pro Console模塊的應用(yòng)被部署成一個獨立的Server,在這個Server上創建規則項目,在項目中(zhōng)根據業務(wù)需求添加決策集、決策表、交叉決策表、決策樹、評分(fēn)卡、複雜評分(fēn)卡、決策流等,再把這些文(wén)件打包到知識包中(zhōng),最後通過HTTP協議暴露給各個客戶端業務(wù)系統使用(yòng)。
其運行示意图如下所示:
在客戶端服務(wù)器模式下,URule Server上給客戶端提供的是若幹個已經構建好的知識包對象。 當客戶端需要進行規則計算時,它會檢查當前客戶端中(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)當前客戶端緩存裏的知識包。
urule.knowledgeUpdateCycle屬性默認值為(wèi)0,一般情況下,如果我們的客戶端為(wèi)一個Java Web應用(yòng),隻需要将這個屬性置為(wèi)1即可(kě),因為(wèi)客戶端為(wèi)Web應用(yòng),服務(wù)端會通過推送方式讓客戶端知識包與服務(wù)端時刻保持一緻。
如果客戶端為(wèi)非Web應用(yòng),那麽才需要修改urule.knowledgeUpdateCycle屬性值為(wèi)一個大于1的數值,以實現定期檢查服務(wù)端知識包是否有(yǒu)更新(xīn)功能(né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>4.0.0</version>
</dependency>
可(kě)以看到,在客戶端當中(zhōng)就不再需要urule-console-pro模塊了,隻需要一個urule-core-pro模塊即可(kě)。
上面的maven依賴中(zhōng),我們使用(yòng)的是4.0.0版本,實際使用(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-4.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” 上請求對應的知識包。
如果同步不成功需要檢查url配置,确保url的末尾沒有(yǒu)添加/,例如:“http://192.168.18.11:8080/urule-server/” 是不允許的
URule Pro中(zhōng)提供了動态加載Jar包及Spring配置文(wén)件功能(néng),在客戶端配置了urule.resporityServerUrl屬性後,客戶端在啓動時會自動到服務(wù)端檢查是否有(yǒu)新(xīn)的動态Jar文(wén)件信息需要加載,如果有(yǒu)則下載到客戶端并加載,所以這時服務(wù)端的“urule/dynamic/checkLatestJarsDir”和“urule/dynamic/loadDynamicJars”這兩個URL要保證匿名(míng)可(kě)訪問(URULE框架默認允許匿名(míng)訪問),否則客戶端啓動時會産(chǎn)生錯誤。
注意:當前如果客戶端上配置了urule.resporityServerUrl屬性值,但這個屬性對應的Server不存在,或無法訪問,那麽客戶端在啓動到服務(wù)端檢查是否有(yǒu)新(xīn)的動态Jar文(wén)件信息需要加載操作(zuò)就會報錯,導緻客戶端啓用(yòng)失敗。
到這裏,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上客戶端配置
如果當前登錄用(yòng)戶為(wèi)团隊創建人員,那麽在登錄系統後,可(kě)以看到客戶端配置入口,如下图:
我們可(kě)以添中(zhōng)多(duō)個客戶端,這樣在當前項目發布知識包時就可(kě)以自動推送到這裏的客戶端上,如下图:
配置完成後,進行項目的知識包管理(lǐ)頁(yè)面,查看某個知識包的已發布知識包,在彈出窗口可(kě)以看到已發布的知識包列表,選中(zhōng)某條需要推送到客戶端的知識包,點擊右鍵,在彈出菜單中(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;
import java.util.List;
import com.bstek.urule.console.database.model.UrlConfig;
/**
* @author Jacky.Gao
* @since 2021年9月26日
*/
public interface ClientProvider {
List<UrlConfig> loadClients(String groupId);
}
實現了ClientProvider接口後,隻需要将實現類配置到Spring上下文(wén)當中(zhōng),使之成為(wèi)一個标準的Spring Bean即可(kě),這樣引擎在獲取配置的客戶端信息時就會嘗試從這個實現類中(zhōng)獲取。
一旦我們實現了該接口,并将其配置到Spring中(zhōng),重啓應用(yòng),在客戶端配置頁(yè)面就可(kě)以看到該接口實現類中(zhōng)加載的客戶端列表,同時該頁(yè)面也不再提供客戶端信息的編輯功能(néng)。
Spring-Cloud框架
例如在spring-cloud中(zhōng)我們可(kě)以通過DiscoveryClient的getInstances獲得對應服務(wù)的ip地址列表 參考代碼:
public class MemberClientProvider implements ClientProvider {
@Override
public List<UrlConfig> loadClients(String arg0) {
List<ServiceInstance> instances = Utils.getApplicationContext().getBean(DiscoveryClient).getInstances("consul-member");
List<UrlConfig> clients = new ArrayList<UrlConfig>();
for (ServiceInstance instance:instances) {
UrlConfig client = new UrlConfig();
client.setName(instance.getHost());
client.setType(UrlType.client);
client.setGroupId("bstek");
client.setUrl("http:"+instance.getHost()+":"+instance.getPort());
clients.add(client)j;
}
return clients;
}
}
K8S
如果不是spring-cloud框架,直接K8S部署,可(kě)以通過K8S提供的client-java的SDK獲取到IP地址列表,詳細辦(bàn)法參考K8S官方文(wén)檔。 一篇簡單的參考文(wén)檔:
http://events.jianshu.io/p/d8a073f8d416
前面我們介紹了在URule Pro客戶端中(zhōng)配置“urule.knowledgeUpdateCycle”屬性的含義及目的,對于客戶端為(wèi)Web應用(yòng)類型,一旦我們在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)。