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);
    }
}

若需要调试单个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}}

}

如上例,通过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>

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>

业务层中每个进程的配置相同,配置如下:

<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>

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>

用户模块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>

通知模块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>

帖子模块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>

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);
    }
}

从代码看出,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>

由以上几种部署方式的范例可以看出,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>

Java 微服务框架 Redkale 入门介绍的更多相关文章

  1. Java微服务框架一览

    引言:本文首先简单介绍了微服务的概念以及使用微服务所能带来的优势,然后结合实例介绍了几个常见的Java微服务框架. 微服务在开发领域的应用越来越广泛,因为开发人员致力于创建更大.更复杂的应用程序,而这 ...

  2. Surging 微服务框架使用入门

    原文:Surging 微服务框架使用入门 前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正.  我对 surging 的看法 我目前所在的公司采用架构就是类似与Sur ...

  3. 基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)

    一.前言 至今为止编程开发已经11个年头,从 VB6.0,ASP时代到ASP.NET再到MVC, 从中见证了.NET技术发展,从无畏无知的懵懂少年,到现在的中年大叔,从中的酸甜苦辣也只有本人自知.随着 ...

  4. [转帖]微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务

    微服务框架Spring Cloud介绍 Part1: 使用事件和消息队列实现分布式事务 http://skaka.me/blog/2016/04/21/springcloud1/ APR 21ST,  ...

  5. golang微服务框架go-micro 入门笔记2.4 go-micro service解读

    本章节阐述go-micro 服务发现原理 go-micro架构 下图来自go-micro官方 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go- ...

  6. golang微服务框架go-micro 入门笔记2.3 micro工具之消息接收和发布

    本章节阐述micro消息订阅和发布相关内容 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go-micro环境, golang微服务框架go-mi ...

  7. golang微服务框架go-micro 入门笔记2.2 micro工具之微应用利器micro web

    micro web micro 功能非常强大,本文将详细阐述micro web 命令行的功能 阅读本文前你可能需要进行如下知识储备 golang分布式微服务框架go-micro 入门笔记1:搭建go- ...

  8. Java微服务框架

    Java的微服务框架dobbo.spring boot.redkale.spring cloud 消息中间件RabbitMQ.Kafka.RocketMQ

  9. 【非官方】Surging 微服务框架使用入门

    前言 本文非 Surging 官方教程,只是自己学习的总结.如有哪里不对,还望指正. 我对 surging 的看法 我目前所在的公司采用架构就是类似与Surging的RPC框架,在.NET 4.0框架 ...

随机推荐

  1. MYSQL视图的学习笔记

    MYSQL视图的学习笔记,学至Tarena金牌讲师,金色晨曦科技公司技术总监沙利穆 课程笔记的综合. 视图及图形化工具   1.       视图的定义 视图就是从一个或多个表中,导出来的表,是一个虚 ...

  2. 总结QueueUserWorkItem传参的几种方式

    最近在学习citrix的xenserver6.2的源代码,发现多处用到System.Threading命名空间下的ThreadPool.QueueUserWorkItem方法: public stat ...

  3. React Native 初识

    Facebook 在 React.js Conf 2015 大会上推出了基于 JavaScript 的开源框架 React Native,本中文教程翻译自 React Native 官方文档. Rea ...

  4. bui上手体验

    在最近的项目中,接触到了bui这个后台管理框架 主页地址:http://builive.com/ 主页上也有一个后台管理的Demo:http://builive.com/apps/default/ma ...

  5. 最长回文字符串(manacher算法)

    偶然看见了人家的博客发现这么一个问题,研究了一下午, 才发现其中的奥妙.Stupid. 题目描述:      回文串就是一个正读和反读都一样的字符串,比如“level”或者“noon”等等就是回文串. ...

  6. HTML5硕士学习笔记

    如今,该集团经过培训的同事给大家HTML5,他出席了两个5训练日,大概过一次给我们,在一个很形象.同事们更感兴趣的是. 课后共享所有的课件.在热情的新技术,我想工作有一个良好的早晨,我决定重新学习课件 ...

  7. Java基础知识强化53:经典排序之选择排序(SelectionSort)

    1.选择排序的原理图: 2. 选择排序代码实现: package cn.itcast_02; /* * 数组排序之选择排序: * 从0索引开始,依次和后面元素比较,小的往前放,第一次完毕,最小值出现在 ...

  8. params关键字载入空值的陷阱

    在编写方法时,不确定这个方法要传入多少个参数,或者随着程序的开发速度,该方法的参数会发生很大变化,在C#中引入了params关键字,使用params修饰object类型的数组并作为方法的参数类型,可以 ...

  9. SQL Server 2005无日志文件附加数据库

    公司网站运营两年多了,日志文件超级大,在重装系统的时候,为了省事,就没有备份日志文件,而且是没有分离就把日志文件给删掉了(下次一定要记得先分离再删日志文件).结果造成数据库怎么都附加不上.出现错误. ...

  10. iOS_SN_地图的使用(2)

    上一篇讲的是地图的基本使用,和注意事项,这一篇主要讲POI检索.百度地图SDK提供三种类型的POI检索:周边检索.区域检索和城市内检索.下面将以周边检索为例,向大家介绍如何使用检索服务. - (voi ...