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)注册新资源。