java 微服务框架 redkale 入门介绍-亚博电竞手机版

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、初始化 节点中的资源。

3、解析所有的 节点。

4、初始化并启动所有 节点的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作简单的配置即可:

                                           	 

2、多点部署

在生产环境需要避免单点问题,一个服务一般会部署多套。在此做个简单的容灾部署,最前端部署一个nginx作反向代理和负载均衡服务器,后面部署两套系统。

如上图,两个进程间的serivce都是本地模式,两者会通过sncp服务保持数据同步,若datasource开启了数据缓存也会自动同步。两套的配置文件相同,配置如下:

        	                                                                                                              	                                                                                                                                                                               	 

3、分层部署

随着业务的复杂度增加,接入层与业务层混在一起会越来越难部署和维护,因此需要进行分层部署。

如上图,对httpservlet与service进行了分离。每个接入层的service都是远程模式,业务层只需提供sncp供远程调用。

接入层中每个进程的配置相同,配置如下:

       	                                                                                                                                                                	 

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

       	                                                                                                                                                                                                                 	 

4、微服务部署

当用户量和发帖量增加到上百万的时候,明显地将所有模块的服务部署到一个进程里是不行的。 因此需要将service服务都独立部署形成微服务架构。

如上图,将serivice都独立部署并进行容灾部署,当然如果有需要,servlet之间、source都可以各自分离独立部署。不同类型的service之间都是远程模式调用。

接入层中每个进程的配置相同,配置如下:

        	                                                                                                                                                                                                      	                                                                                         	 

用户模块userservice服务群中各个进程的配置相同,配置如下:

       	                                                                                                                                                              	                                                                                                                                            	 

通知模块notifyservice服务群中各个进程的配置相同,配置如下:

       	                                                                                                                                                              	                                                                                             	 

帖子模块forumservice服务群中各个进程的配置相同,配置如下:

       	                                                                                                                                                              	                                                                   	 

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 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)的配置如下:

       	                                                                                                                                                                                                                                                                         	                                                                                                                                     

由以上几种部署方式的范例可以看出,redkale提供了非常强大的架构,集中式到微服务架构不需要增加修改一行代码即可随意切换,即使网关式部署也只是新增很少的代码就可切换,且不影响其他服务。真正可以做到敏捷开发,复杂的系统都可如小系统般快速地开发出来。

为了降低接入层与业务层代码的耦合, 可以将service分接口与实现两个类,接入层只加载接口包、业务层使用实现包。

appplication.xml 配置说明

                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      
展开全文
内容来源于互联网和用户投稿,文章中一旦含有亚博电竞手机版的联系方式务必识别真假,本站仅做信息展示不承担任何相关责任,如有侵权或涉及法律问题请联系亚博电竞手机版删除

最新文章

网站地图