Java 微服務框架 Redkale 入門介紹
來自: http://redkale.org/redkale.html
Redkale 功能
Redkale雖然只有1.xM大小,但是麻雀雖小五臟俱全。既可作為服務器使用,也可當工具包使用。作為獨立的工具包提供以下功能:
1、convert包提供JSON的序列化和反序列化功能,類似Gson、Jackson。
2、convert包提供Java對象二進制的序列化和反序列化功能,類似Protobuf。
3、source包提供很簡便的數據庫操作功能,類似JPA、Hibernate。
4、net包提供TCP/UDP服務功能, 類似Mina。
5、net.http提供HTTP服務, 類似Tomcat、Netty。
6、ResourceFactory提供輕量級的依賴注入功能, 類似Google Guice。
Redkale 服務器
Redkale作為服務器的目錄如下:
bin : 存放啟動關閉腳本(start.sh、shutdown.sh、start.bat、shutdown.bat)
conf : 存放服務器所需配置文件:
application.xml: 服務配置文件 (必需);
logging.properties:日志配置文件 (可選);
persistence.xml:數據庫配置文件 (可選);
lib : 存放服務所依賴的第三方包,redkale.jar 放在此處。
logs : logging.properties 配置中默認的日志存放目錄。
root : application.xml 配置中HTTP服務所需頁面的默認根目錄。
Redkale啟動的流程如下:
1、加載 application.xml 并解析。
2、初始化 <resources> 節點中的資源。
3、解析所有的 <server> 節點。
4、初始化并啟動所有<server> 節點的Server服務 (優先加載SNCP協議的Server)。
5、初始化單個Server:
5.1、掃描classpath加載所有可用的Service實現類(沒有標記為@AutoLoad(false)的類)并實例化,然后相互依賴注入。
5.2、Service實例在依賴注入過程中加載所需的DataSource、CacheSource資源。
5.3、調用所有本地模式Service的init方法。
5.4、掃描classpath加載所有可用的Servlet實現類(沒有標記為@AutoLoad(false)的類)并實例化 (優先實例化WebSocketServlet)。
5.5、給所有Servlet依賴注入所需的Service。
5.6、調用所有Servlet的init方法。
5.7、啟動Server的服務監聽。
6、啟動進程本身的監聽服務。
基于Redkale的開發與調試
基于Redkale創建一個Java應用程序工程(即使是Web項目也不要創建Java-Web工程),引用redkale.jar 并創建Redkale所需的幾個目錄和文件。一個普通的Web項目只需要編寫業務層的Service和接入層的HttpServlet的代碼。數據庫DataSource通過配置文件進行設置。
編寫完代碼可以通過啟動腳本進行調試, 也可以在IDE設置項目的主類為 org.redkale.boot.Application 或者工程內定義主類進行啟動調試:
public final class Bootstrap {
public static void main(String[] args) throws Exception {
org.redkale.boot.Application.main(args);
}
}</pre></div>
若需要調試單個Service,可以通過 Application.singleton 方法進行調試:
public static void main(String[] args) throws Exception {
UserService service = Application.singleton(UserService.class);
LoginBean bean = new LoginBean();
bean.setAccount("myaccount");
bean.setPassword("123456");
System.out.println(service.login(bean));
}
Application.singleton 運行流程與通過bin腳本啟動的流程基本一致,區別在于singleton運行時不會啟動Server和Application自身的服務監聽。Redkale提倡接入層(Servlet)與業務層(Service)分開,Service在代碼上不能依賴于Servlet,因此調試Service自身邏輯時不需要啟動接入層服務(類似WebSocket依賴Servlet的功能除外)。
Redkale的依賴注入 Redkale內置的依賴注入實現很簡單,只有三個類: javax.annotation.Resource、org.redkale.util.ResourceType、org.redkale.util.ResourceFactory,采用反射技術,由于依賴注入通常不會在頻繁的操作中進行,因此性能要求不會很高。其中前兩個是注解,ResourceFactory是主要操作類,主要提供注冊和注入兩個接口。ResourceFactory的依賴注入不僅提供其他依賴注入框架的常規功能,還能動態的自動更新通過inject注入的資源。
public class AService {
@Resource(name = "property.id")
private String id;
@Resource(name = "property.id") //property.開頭的資源名允許String自動轉換成primitive數值類型
private int intid;
@Resource(name = "bigint")
private BigInteger bigint;
@Resource(name = "seqid")
private int seqid;
@Resource
private ResourceTest.BService bservice;
@Override
public String toString() {
return "{id:\"" + id + "\", intid: " + intid + ", bigint:" + bigint + "}";
}
/** 以下省略getter setter方法 */
}
public class BService {
@Resource(name = "property.id")
private String id;
@Resource
private AService aservice;
private String name = "";
@java.beans.ConstructorProperties({"name"})
public BService(String name) {
this.name = name;
}
@Override
public String toString() {
return "{name:\"" + name + "\", id: " + id + ", aserivce:" + aservice + "}";
}
/** 以下省略getter setter方法 */
}
public static void main(String[] args) throws Exception {
ResourceFactory factory = ResourceFactory.root();
factory.register("property.id", "2345"); //注入String類型的property.id
AService aservice = new AService();
BService bservice = new BService("eee");
factory.register(aservice); //放進Resource池內,默認的資源名name為""
factory.register(bservice); //放進Resource池內,默認的資源名name為""
factory.inject(aservice); //給aservice注入id、bservice,bigint沒有資源,所以為null
factory.inject(bservice); //給bservice注入id、aservice
System.out.println(aservice); //輸出結果為:{id:"2345", intid:2345, bigint:null, bservice:{name:eee}}
System.out.println(bservice); //輸出結果為:{name:"eee", id:2345, aserivce:{id:"2345", intid:2345, bigint:null, bservice:{name:eee}}}
factory.register("seqid", 200); //放進Resource池內, 同時ResourceFactory會自動更新aservice的seqid值
System.out.println(factory.find("seqid", int.class)); //輸出結果為:200
factory.register("bigint", new BigInteger("66666")); //放進Resource池內, 同時ResourceFactory會自動更新aservice對象的bigint值
System.out.println(aservice); //輸出結果為:{id:"2345", intid:2345, bigint:66666, bservice:{name:eee}}可以看出seqid與bigint值都已自動更新
factory.register("property.id", "6789"); //更新Resource池內的id資源值, 同時ResourceFactory會自動更新aservice、bservice的id值
System.out.println(aservice); //輸出結果為:{id:"6789", intid:6789, bigint:66666, bservice:{name:eee}}
System.out.println(bservice); //輸出結果為:{name:"eee", id:6789, aserivce:{id:"6789", intid:6789, bigint:66666, bservice:{name:eee}}}
bservice = new BService("ffff");
factory.register(bservice); //更新Resource池內name=""的BService資源, 同時ResourceFactory會自動更新aservice的bservice對象
factory.inject(bservice);
System.out.println(aservice); //輸出結果為:{id:"6789", intid: 6789, bigint:66666, bservice:{name:ffff}}
}</pre></div>
如上例,通過ResourceFactory.inject注入的對象都會自動更新資源的變化,若不想自動更新可以使用帶boolean autoSync參數的register系列方法(autoSync傳false)注冊新資源。
Redkale 架構部署 通常一個系統會分為三層:接入層、業務層、數據層。對應到Redkale的組件是: Servlet、Service、Source。大部分系統提供的是HTTP服務,為了方便演示Redkale從集中式到分布式的變化,以一個簡單的HTTP服務作為范例。
開發一個極簡單的小論壇系統。包含三個模塊:
用戶模塊 UserSerivice: 提供用戶注冊、登錄、更新資料等功能, UserServlet作為接入層。
帖子模塊 ForumSerivice: 提供看帖、發帖、刪帖等功能, ForumServlet作為接入層。
通知模塊 NotifySerivice: 提供用戶操作、回帖等消息通知功能, NotifyWebSocket是WebSocket的Servlet, 且name為 ws_notify,作為接入層。
其中數據源有:
DataSource: 在persistence.xml里配置的數據庫Source的name為demodb ,三個模塊都需要使用demodb。
CacheSource: 僅供UserSerivice用于存放session的緩存Service,name為 usersessions, 且session只存放用戶ID( int 類型)。
1、單點部署
在早期用戶量很少或者開發、調試環境中只需部署一個進程就可滿足需求。

如上圖,所有模塊的HttpServlet、Service與Source數據庫操作全部署在一起。 application.xml作簡單的配置即可:
<application port="5050">
<server protocol="HTTP" port="6060" root="root">
<services autoload="true" />
<servlets autoload="true"/>
</server>
</application>
2、多點部署
在生產環境需要避免單點問題,一個服務一般會部署多套。在此做個簡單的容災部署,最前端部署一個nginx作反向代理和負載均衡服務器,后面部署兩套系統。

如上圖,兩個進程間的Serivce都是本地模式,兩者會通過SNCP服務保持數據同步,若DataSource開啟了數據緩存也會自動同步。兩套的配置文件相同,配置如下:
<application port="5050">
<resources>
<group name="ALL">
<node addr="192.168.50.110" port="7070"/>
<node addr="192.168.50.120" port="7070"/>
</group>
</resources>
<!-- HTTP 監聽 Server -->
<server protocol="HTTP" port="6060" root="root">
<!-- 前端配置了nginx,需要配置才能獲取客戶端真實的IP地址 -->
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<services autoload="true" groups="ALL"/>
<servlets autoload="true" />
</server>
<!-- SNCP 監聽 Server -->
<server protocol="SNCP" port="7070">
<services autoload="true" groups="ALL">
<!-- 有WebSocketServlet的服務必須配置WebSocketNodeService,且Redkale同時會自動創建一個同名(ws_notify)的 CacheSource -->
<service name="ws_notify" value="org.redkale.service.WebSocketNodeService"/>
<!-- 存在DataSource必須配置DataSourceService -->
<service name="demodb" value="org.redkale.service.DataSourceService"/>
<!-- 存放用戶HTTP session信息的CacheSource -->
<service name="usersessions" value="org.redkale.service.CacheSourceService">
<property name="key-type" value="java.lang.String"/>
<property name="value-type" value="java.lang.Integer"/>
</service>
</services>
</server>
</application></pre></div>
3、分層部署
隨著業務的復雜度增加,接入層與業務層混在一起會越來越難部署和維護,因此需要進行分層部署。

如上圖,對HttpServlet與Service進行了分離。每個接入層的Service都是遠程模式,業務層只需提供SNCP供遠程調用。
接入層中每個進程的配置相同,配置如下:
<application port="5050">
<resources>
<group name="ALL">
<node addr="192.168.50.110" port="7070"/>
<node addr="192.168.50.120" port="7070"/>
</group>
</resources>
<!-- HTTP 監聽 Server -->
<server protocol="HTTP" port="6060" root="root">
<!-- 前端配置了nginx,需要配置才能獲取客戶端真實的IP地址 -->
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<services autoload="true" groups="ALL">
<!-- 有WebSocketServlet的服務必須配置WebSocketNodeService,且Redkale同時會自動創建一個同名(ws_notify)的 CacheSource -->
<service name="ws_notify" value="org.redkale.service.WebSocketNodeService"/>
</services>
<servlets autoload="true" />
</server>
</application></pre></div>
業務層中每個進程的配置相同,配置如下:
<application port="5050">
<resources>
<group name="ALL">
<node addr="192.168.50.110" port="7070"/>
<node addr="192.168.50.120" port="7070"/>
</group>
</resources>
<!-- SNCP 監聽 Server -->
<server protocol="SNCP" port="7070">
<services autoload="true" groups="ALL">
<!-- 有WebSocketServlet的服務必須配置WebSocketNodeService,且Redkale同時會自動創建一個同名(ws_notify)的 CacheSource -->
<service name="ws_notify" value="org.redkale.service.WebSocketNodeService"/>
<!-- 存在DataSource必須配置DataSourceService -->
<service name="demodb" value="org.redkale.service.DataSourceService"/>
<!-- 存放用戶HTTP session信息的CacheSource -->
<service name="usersessions" value="org.redkale.service.CacheSourceService">
<property name="key-type" value="java.lang.String"/>
<property name="value-type" value="java.lang.Integer"/>
</service>
</services>
</server>
</application></pre></div>
4、微服務部署
當用戶量和發帖量增加到上百萬的時候,明顯地將所有模塊的服務部署到一個進程里是不行的。 因此需要將Service服務都獨立部署形成微服務架構。

如上圖,將Serivice都獨立部署并進行容災部署,當然如果有需要,Servlet之間、Source都可以各自分離獨立部署。不同類型的Service之間都是遠程模式調用。
接入層中每個進程的配置相同,配置如下:
<application port="5050">
<resources>
<group name="USER_SERVICE">
<node addr="192.168.50.110" port="7070"/>
<node addr="192.168.50.111" port="7070"/>
</group>
<group name="NOTIFY_SERVICE">
<node addr="192.168.50.120" port="7070"/>
<node addr="192.168.50.121" port="7070"/>
</group>
<group name="FORUM_SERVICE">
<node addr="192.168.50.130" port="7070"/>
<node addr="192.168.50.131" port="7070"/>
</group>
</resources>
<!-- HTTP 監聽 Server -->
<server protocol="HTTP" port="6060" root="root">
<!-- 前端配置了nginx,需要配置才能獲取客戶端真實的IP地址 -->
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<services autoload="true">
<service value="org.redkale.demo.UserService" groups="USER_SERVICE"/>
<service value="org.redkale.demo.NotifyService" groups="NOTIFY_SERVICE"/>
<service value="org.redkale.demo.ForumService" groups="FORUM_SERVICE"/>
<!-- 有WebSocketServlet的服務必須配置WebSocketNodeService,且Redkale同時會自動創建一個同名(ws_notify)的 CacheSource -->
<service name="ws_notify" value="org.redkale.service.WebSocketNodeService" groups="NOTIFY_SERVICE"/>
</services>
<servlets autoload="true" />
</server>
</application></pre></div>
用戶模塊UserService服務群中各個進程的配置相同,配置如下:
<application port="5050">
<resources>
<group name="USER_SERVICE">
<node addr="192.168.50.110" port="7070"/>
<node addr="192.168.50.111" port="7070"/>
</group>
<group name="NOTIFY_SERVICE">
<node addr="192.168.50.120" port="7070"/>
<node addr="192.168.50.121" port="7070"/>
</group>
<group name="FORUM_SERVICE">
<node addr="192.168.50.130" port="7070"/>
<node addr="192.168.50.131" port="7070"/>
</group>
</resources>
<!-- SNCP 監聽 Server -->
<server protocol="SNCP" port="7070">
<services autoload="true">
<service value="org.redkale.demo.NotifyService" groups="NOTIFY_SERVICE"/>
<service value="org.redkale.demo.ForumService" groups="FORUM_SERVICE"/>
<!-- 存在DataSource必須配置DataSourceService -->
<service name="demodb" value="org.redkale.service.DataSourceService" groups="USER_SERVICE"/>
<!-- 存放用戶HTTP session信息的CacheSource -->
<service name="usersessions" value="org.redkale.service.CacheSourceService" groups="USER_SERVICE">
<property name="key-type" value="java.lang.String"/>
<property name="value-type" value="java.lang.Integer"/>
</service>
</services>
</server>
</application></pre></div>
通知模塊NotifyService服務群中各個進程的配置相同,配置如下:
<application port="5050">
<resources>
<group name="USER_SERVICE">
<node addr="192.168.50.110" port="7070"/>
<node addr="192.168.50.111" port="7070"/>
</group>
<group name="NOTIFY_SERVICE">
<node addr="192.168.50.120" port="7070"/>
<node addr="192.168.50.121" port="7070"/>
</group>
<group name="FORUM_SERVICE">
<node addr="192.168.50.130" port="7070"/>
<node addr="192.168.50.131" port="7070"/>
</group>
</resources>
<!-- SNCP 監聽 Server -->
<server protocol="SNCP" port="7070">
<services autoload="true">
<service value="org.redkale.demo.UserService" groups="USER_SERVICE"/>
<service value="org.redkale.demo.ForumService" groups="FORUM_SERVICE"/>
<!-- 有WebSocketServlet的服務必須配置WebSocketNodeService,且Redkale同時會自動創建一個同名(ws_notify)的 CacheSource -->
<service name="ws_notify" value="org.redkale.service.WebSocketNodeService" groups="NOTIFY_SERVICE"/>
<!-- 存在DataSource必須配置DataSourceService -->
<service name="demodb" value="org.redkale.service.DataSourceService" groups="NOTIFY_SERVICE"/>
</services>
</server>
</application></pre></div>
帖子模塊ForumService服務群中各個進程的配置相同,配置如下:
<application port="5050">
<resources>
<group name="USER_SERVICE">
<node addr="192.168.50.110" port="7070"/>
<node addr="192.168.50.111" port="7070"/>
</group>
<group name="NOTIFY_SERVICE">
<node addr="192.168.50.120" port="7070"/>
<node addr="192.168.50.121" port="7070"/>
</group>
<group name="FORUM_SERVICE">
<node addr="192.168.50.130" port="7070"/>
<node addr="192.168.50.131" port="7070"/>
</group>
</resources>
<!-- SNCP 監聽 Server -->
<server protocol="SNCP" port="7070">
<services autoload="true">
<service value="org.redkale.demo.UserService" groups="USER_SERVICE"/>
<service value="org.redkale.demo.NotifyService" groups="NOTIFY_SERVICE"/>
<!-- 存在DataSource必須配置DataSourceService -->
<service name="demodb" value="org.redkale.service.DataSourceService" groups="FORUM_SERVICE"/>
</services>
</server>
</application></pre></div>
5、API網關式部署
隨著用戶量到了上千萬時,一個UserService的服務進程是無法提供全部用戶服務。 因此可以考慮按用戶段進行分布式部署。將192.168.50.110、192.168.50.111上的UserService服務改成網關式的服務。下面是以 Service本地模式介紹中的UserService 為范例進行編寫:
@ResourceType({UserService.class})
public class UserServiceGateWay extends UserService {
@Resource(name = "userservice_reg")
private UserService regUserService; //只用于注冊的服務節點
@Resource(name = "userservice_mob")
private UserService mobUserService; //只用于查詢手機號碼對應的userid的服務節點
@Resource(name = "userservice_node01")
private UserService userService01; //userid小于2000000的用戶的服務節點
@Resource(name = "userservice_node02")
private UserService userService02; //userid小于4000000的用戶的服務節點
@Resource(name = "userservice_node03")
private UserService userService03; //userid小于6000000的用戶的服務節點
@Resource(name = "userservice_node04")
private UserService userService04; //userid大于6000000的用戶的服務節點
private UserService getService(int userid) {
if (userid <= 200_0000) return userService01;
if (userid <= 400_0000) return userService02;
if (userid <= 600_0000) return userService03;
return userService04;
}
@Override
public UserInfo findUserInfo(int userid) {
return this.getService(userid).findUserInfo(userid);
}
@Override
public RetResult<UserInfo> login(LoginBean bean) { //手機號碼用long存儲,0表示無手機號碼
int userid = mobUserService.findUserid(bean.getMobile());
if (userid < 1) return new RetResult<>(10001, "not found mobile " + bean.getMobile());
return this.getService(userid).login(bean);
}
@Override
public void register(UserInfo user) {
regUserService.register(user); //會生成userid
this.getService(user.getUserid()).putUserInfo(user);
}
@Override
public UserInfo updateUsername(int userid, String username) {
return this.getService(userid).updateUsername(userid, username);
}
}</pre></div>
從代碼看出,UserServiceGateWay繼承了UserService, 確保了UserService對外的服務接口不變,上面代碼是用戶量在600-800萬之間的寫法,通過簡單的用戶ID分段,根據不同用戶ID調不同的服務節點。

如上圖,網關下的UserService部署分三類: userservice_reg只用于注冊用戶;userservice_mob提供查詢手機號碼與用戶ID間的關系的服務;userservice_node按用戶段提供已有用戶的服務。且每個UserService的實例在UserServiceGateWay都是遠程模式。每種類型可以部署多個節點(為了結構圖簡單,上圖每個類型只部署一個節點)。UserServiceGateWay(192.168.50.110、192.168.50.111)的配置如下:
<application port="5050">
<resources>
<group name="USER_SERVICE_REG">
<node addr="192.168.70.110" port="7070"/>
</group>
<group name="USER_SERVICE_MOB">
<node addr="192.168.70.150" port="7070"/>
</group>
<group name="USER_SERVICE_NODE01">
<node addr="192.168.70.201" port="7070"/>
</group>
<group name="USER_SERVICE_NODE02">
<node addr="192.168.70.202" port="7070"/>
</group>
<group name="USER_SERVICE_NODE03">
<node addr="192.168.70.203" port="7070"/>
</group>
<group name="USER_SERVICE_NODE04">
<node addr="192.168.70.204" port="7070"/>
</group>
<group name="USER_SERVICE">
<node addr="192.168.50.110" port="7070"/>
<node addr="192.168.50.111" port="7070"/>
</group>
</resources>
<!-- SNCP 監聽 Server -->
<server protocol="SNCP" port="7070">
<services autoload="true">
<!-- 配置UserService網關 -->
<service name="" value="org.redkale.demo.UserServiceGateWay" groups="USER_SERVICE"/>
<!-- 配置UserService分段節點 -->
<service name="userservice_reg" value="org.redkale.demo.UserService" groups="USER_SERVICE_REG"/>
<service name="userservice_mob" value="org.redkale.demo.UserService" groups="USER_SERVICE_MOB"/>
<service name="userservice_node01" value="org.redkale.demo.UserService" groups="USER_SERVICE_NODE01"/>
<service name="userservice_node02" value="org.redkale.demo.UserService" groups="USER_SERVICE_NODE02"/>
<service name="userservice_node03" value="org.redkale.demo.UserService" groups="USER_SERVICE_NODE03"/>
<service name="userservice_node04" value="org.redkale.demo.UserService" groups="USER_SERVICE_NODE03"/>
</services>
</server>
</application></pre></div>
由以上幾種部署方式的范例可以看出,Redkale提供了非常強大的架構,集中式到微服務架構不需要增加修改一行代碼即可隨意切換,即使網關式部署也只是新增很少的代碼就可切換,且不影響其他服務。真正可以做到敏捷開發,復雜的系統都可如小系統般快速地開發出來。
為了降低接入層與業務層代碼的耦合, 可以將Service分接口與實現兩個類,接入層只加載接口包、業務層使用實現包。
appplication.xml 配置說明<?xml version="1.0" encoding="UTF-8"?>
<!--
文件說明:
${APP_HOME} 指當前程序的根目錄APP_HOME
required: 被聲明required的屬性值不能為空
-->
<!--
address: 本地的IP地址, 默認值為默認網卡的ip,當不使用默認值需要指定值,如127.0.0.1
port: required 程序的管理Server的端口,用于關閉或者與監管系統進行數據交互
host: 程序的管理Server的地址; 默認為127.0.0.1。
lib: 加上額外的lib路徑,多個路徑用分號;隔開; 默認為空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;
-->
<application port="6560" lib="">
<!-- 所有服務所需的資源 -->
<resources>
<!--
transport節點只能有一個,用于配置所有Transport的池參數,沒配置該節點將自動創建一個。
threads: 線程總數, 默認: <group>節點數*CPU核數*8
bufferCapacity: ByteBuffer的初始化大小, 默認: 8K;
bufferPoolSize: ByteBuffer池的大小,默認: <group>節點數*CPU核數*8
-->
<transport capacity="8192" bufferPoolSize="32" threads="32"/>
<!--
一個組包含多個NODE, 同一Service服務可以由多個進程提供,這些進程稱為一個GROUP,且同一GROUP內的進程必須在同一機房或局域網內
一個group節點對應一個 Transport 對象。
name: 服務組ID,長度不能超過11個字節. 默認為空字符串。 注意: name不能包含$符號。
protocol:值只能是UDP TCP, 默認TCP
注意: 一個node只能所屬一個group。只要存在protocol=SNCP的Server節點信息, 就必須有group節點信息。
-->
<group name="" protocol="TCP">
<!--
需要將本地node的addr與port列在此處。
同一個<node>節點值只能存在一個<group>節點內,即同一個addr+port只能屬于一個group。
addr: required IP地址
port: required 端口
clients: 連接池數, 默認: CPU核數*4
buffers: ByteBuffer對象池的大小, 默認: CPU核數*8
-->
<node addr="127.0.0.1" port="7070"/>
</group>
<!--
全局的參數配置, 可以通過@Resource(name="property.xxxxxx") 進行注入, 被注解的字段類型只能是String、primitive class
如果name是system.property.開頭的值將會在進程啟動時進行System.setProperty("yyyy", "YYYYYY")操作。
如果name是mimetype.property.開頭的值將會在進程啟動時進行MimeType.add("yyyy", "YYYYYY")操作。
load: 加載文件,多個用;隔開。
默認置入的system.property.的有:
System.setProperty("convert.json.tiny", "true");
System.setProperty("convert.bson.tiny", "true");
System.setProperty("convert.json.pool.size", "128");
System.setProperty("convert.bson.pool.size", "128");
System.setProperty("convert.json.writer.buffer.defsize", "4096");
System.setProperty("convert.bson.writer.buffer.defsize", "4096");
-->
<properties load="config.properties">
<property name="system.property.yyyy" value="YYYYYY"/>
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</properties>
</resources>
<!--
protocol: required server所啟動的協議,有HTTP、SNCP, 目前只支持HTTP、SNCP。SNCP使用TCP實現;
host: 服務所占address , 默認: 0.0.0.0
port: required 服務所占端口
root: 如果是web類型服務,則包含頁面 默認:{APP_HOME}/root
lib: server額外的class目錄, 默認為空
charset: 文本編碼, 默認: UTF-8
backlog: 默認10K
threads: 線程總數, 默認: CPU核數*16
maxbody: request.body最大值, 默認: 64K
bufferCapacity: ByteBuffer的初始化大小, 默認: 8K; 如果是HTTP協議則默認: 16K + 8B (兼容HTTP 2.0)
bufferPoolSize: ByteBuffer池的大小,默認: CPU核數*512
responsePoolSize: Response池的大小,默認: CPU核數*256
readTimeoutSecond: 讀操作超時秒數, 默認0, 表示永久不超時
writeTimeoutSecond: 寫操作超時秒數, 默認0, 表示永久不超時
-->
<server protocol="HTTP" host="127.0.0.1" port="6060" root="root" lib="">
<!--
加載所有的Service服務;
在同一個進程中同一個name同一類型的Service將共用同一個實例
autoload="true" 默認值. 自動加載以下目錄(如果存在的話)下所有的Service類:
server.lib; server.lib/*; server.classes;
autoload="false" 需要顯著的指定Service類
includes: 當autoload="true", 拉取類名與includes中的正則表達式匹配的類, 多個正則表達式用分號;隔開
excludes: 當autoload="true", 排除類名與excludes中的正則表達式匹配的類, 多個正則表達式用分號;隔開
groups: 所屬組的節點,多個節點值用;隔開,如果配置文件中存在多個SNCP協議的Server節點,需要顯式指定group屬性.
當 protocol == SNCP 時 group表示當前Server與哪些節點組關聯。
當 protocol != SNCP 時 group只能是空或者一個group的節點值,不能為多個節點值。
-->
<services autoload="true" includes="" excludes="">
<!-- 顯著加載指定的Service的接口類 -->
<service value="com.xxx.XXX1Service"/>
<!--
name: 顯式指定name,覆蓋默認的空字符串值。 注意: name不能包含$符號。
groups: 顯式指定groups,覆蓋<services>節點的groups默認值。
-->
<service value="com.xxx.XXX2Service" name="" groups="xxx;yyy"/>
<!-- 給Service增加配置屬性 -->
<service value="com.xxx.XXX1Service">
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="xxxxxx" value="XXXXXXXX"/>
</service>
</services>
<!--
當Server為HTTP協議時, request節點才有效。
remoteaddr 節點: 替換請求方節點的IP地址, 通常請求方是由nginx等web靜態服務器轉發過的則需要配置該節點。
且value值只能是以request.headers.開頭,表示從request.headers中獲取對應的header值。
例如下面例子獲取request.getRemoteAddr()值,如果header存在X-RemoteAddress值則返回X-RemoteAddress值,不存在返回getRemoteAddress()。
-->
<request>
<remoteaddr value="request.headers.X-RemoteAddress"/>
</request>
<!--
當Server為HTTP協議時, response節點才有效。
defcookie 節點: 當response里輸出的cookie沒有指定domain 和path時,使用該節點的默認值。
如果addheader、setheader 的value值以request.headers.開頭則表示從request.headers中獲取對應的header值
例如下面例子是在Response輸出header時添加兩個header(一個addHeader, 一個setHeader)。
-->
<response>
<defcookie domain="" path=""/>
<addheader name="Access-Control-Allow-Origin" value="request.headers.Origin" />
<setheader name="Access-Control-Allow-Credentials" value="true"/>
</response>
<!--
加載所有的Servlet服務;
path: servlet的ContextPath前綴 默認為空
autoload="true" 默認值. 自動加載以下目錄(如果存在的話)下所有的Servlet類:
${APP_HOME}/lib; ${APP_HOME}/root/lib/*; ${APP_HOME}/root/classes;
autoload="false" 需要顯著的指定Service類
includes: 當autoload="true", 拉取類名與includes中的正則表達式匹配的類, 多個正則表達式用分號;隔開
excludes: 當autoload="true", 排除類名與excludes中的正則表達式匹配的類, 多個正則表達式用分號;隔開
-->
<servlets path="/pipes" autoload="true" includes="" excludes="">
<!--
當Server為HTTP協議時,ResourceServlet才有效. 默認存在一個有默認屬性的resource-servlet節點
webroot: web資源的根目錄, 默認取server節點中的root值
-->
<resource-servlet webroot="root">
<!--
資源緩存的配置, 默認存在一個含默認屬性的caches節點
limit: 資源緩存最大容量, 默認: 128M, 為0表示不緩存, 單位可以是B、K、M、G,不區分大小寫
lengthmax: 可緩存的文件大小上限, 默認: 1M(超過1M的文件不會被緩存)
-->
<caches limit="128M" lengthmax="1M" />
<!--
支持類似nginx中的rewrite, 目前只支持靜態資源對靜態資源的跳轉。
type: 匹配的類型, 目前只支持location(匹配requestURI), 默認: location
match: 匹配的正則表達式
forward: 需跳轉后的資源鏈接
例如下面例子是將/xxx-yyy.html的頁面全部跳轉到/xxx.html
-->
<rewrite type="location" match="^/([^-]+)-[^-\.]+\.html(.*)" forward="/$1.html"/>
</resource-servlet>
<!-- 顯著加載指定的Servlet -->
<servlet value="com.xxx.XXX1Servlet" />
<servlet value="com.xxx.XXX2Servlet" />
<servlet value="com.xxx.XXX3Servlet" >
<property name="xxxxxx" value="XXXXXXXX"/>
<property name="yyyyyy" value="YYYYYYYY"/>
</servlet>
</servlets>
</server>
<server protocol="SNCP" host="127.0.0.1" port="7070" root="root" lib="">
<!-- 參數完全同上 -->
<services autoload="true" includes="" excludes="" />
</server>
</application></pre></div>
本文由用戶 ntrp1882 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
相關經驗
sesese色