From e6486a0f6b3ade0dc92e9ddc1fb9e515e814eb68 Mon Sep 17 00:00:00 2001
From: Redkale <22250530@qq.com>
Date: Fri, 12 May 2017 14:17:27 +0800
Subject: [PATCH]
---
net.html | 20 ++++++++++----------
redkale.html | 2 +-
service.html | 38 +++++++++++++++++++-------------------
source.html | 37 +++++++++++++++++++++----------------
4 files changed, 51 insertions(+), 46 deletions(-)
diff --git a/net.html b/net.html
index 6876e0696..146bcb459 100644
--- a/net.html
+++ b/net.html
@@ -37,10 +37,10 @@
7、内置WebSocket的集群与组功能,且提供伪WebSocket连接功能。
8、HttpResponse只能异步输出。
编写Redkale的HttpServlet与 JSR 340中的javax.servlet.http.HttpServlet 基本相同,只需继承 org.redkale.net.http.HttpServlet, Redkale也提供了更友好的基类 org.redkale.net.http.HttpBaseServlet, 比较好的习惯是一个项目先定义一个项目级的BaseServlet类,这样方便以后加入类似javax.servlet.Filter的功能。
+
编写Redkale的HttpServlet与 JSR 340中的javax.servlet.http.HttpServlet 基本相同,只需继承 org.redkale.net.http.HttpServlet, 比较好的习惯是一个项目先定义一个项目级的BaseServlet类,这样方便以后加入类似javax.servlet.Filter的功能。
一个典型的BaseSerlvet实现:
public class BaseSerlvet extends org.redkale.net.http.HttpBaseServlet {
+ public class BaseSerlvet extends org.redkale.net.http.HttpServlet {
protected final Logger logger = Logger.getLogger(this.getClass().getSimpleName());
@@ -69,7 +69,7 @@
//在调用authenticate之前调用, 返回false表示请求不合法
//该方法可以用于判断请求源是否合法或加入一些全局的拦截操作
@Override
- public void preExecute(final HttpRequest request, final HttpResponse response, HttpServlet next) throws IOException {
+ public void preExecute(final HttpRequest request, final HttpResponse response) throws IOException {
if (!request.getHeader("User-Agent", "").contains("Redkale-Agent")) { //只用移动APP的接口可以判断User-Agent是否正确
response.addHeader("retcode", "10001");
response.addHeader("retmessage", "User-Agent error");
@@ -77,32 +77,32 @@
return;
}
//可以加上一些统计操作
- if (fine) response.setRecycleListener((req, resp) -> { //记录处理时间太长的请求操作
+ if (fine) response.recycleListener((req, resp) -> { //记录处理时间太长的请求操作
long e = System.currentTimeMillis() - request.getCreatetime();
if (e > 500) logger.fine("耗时居然用了 " + e + " 毫秒. 请求为: " + req);
});
- next.execute(request, response);
+ response.nextEvent();
}
//标记为@AuthIgnore 的方法将不会调用authenticate方法
//一般用于判断用户的登录态, 返回false表示鉴权失败
- //moduleid值来自 @WebServlet.moduleid()用于定义模块ID; actionid值自来@WebMapping.actionid()用于定义操作ID; 需要系统化的鉴权需要定义这两个值
+ //moduleid值来自 @WebServlet.moduleid()用于定义模块ID; actionid值自来@HttpMapping.actionid()用于定义操作ID; 需要系统化的鉴权需要定义这两个值
@Override
- public void authenticate(int moduleid, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
+ public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
UserInfo info = currentUser(request);
if (info == null) {
response.finishJson(RetCodes.retResult(RetCodes.RET_USER_UNLOGIN));
return;
- } else if (!info.checkAuth(module, actionid)) {
+ } else if (!info.checkAuth(request.getModuleid(), request.getActionid())) {
response.finishJson(RetCodes.retResult(RetCodes.RET_USER_AUTH_ILLEGAL));
return;
}
- next.execute(request, response);
+ response.nextEvent();
}
}
- 继承HttpBaseServlet的子类可以使用其自带的鉴权、请求分支、缓存等功能, 一个典型的操作用户HttpServlet:
+ 继承HttpServlet的子类可以使用其自带的鉴权、请求分支、缓存等功能, 一个典型的操作用户HttpServlet:
@WebServlet(value = {"/user/*"}, comment = "用户模块服务") //拦截所有 /user/ 开头的请求
public class UserServlet extends BaseSerlvet {
diff --git a/redkale.html b/redkale.html
index b4e78e9cb..48ac93a4a 100644
--- a/redkale.html
+++ b/redkale.html
@@ -633,7 +633,7 @@
<!--
REST的核心配置项, 存在[rest]节点则Server启动时会加载REST服务, 当Server为SNCP协议时,则SncpServer会变成REST的HttpServer, 节点可以多个
- base: REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。
+ base: REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.RestHttpServlet。
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
mustsign:默认值"true" 是否只加载标记为RestService的Service类,默认只加载标记RestService且ignore=false的Service
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
diff --git a/service.html b/service.html
index a6e8c7187..fbd7ac20c 100644
--- a/service.html
+++ b/service.html
@@ -290,7 +290,7 @@
生成远程模式Service时发现参数带有@RpcCall注解的方法,在远程调用返回结果时会进行回调处理。
Service REST
- RestService提供类似Spring Boot的功能。开启REST功能的HTTP Server在实例化标记为@RestService的Service后自动生成对应的HttpServlet,免去开发人员编写HttpServlet的工作量。RestService生成的HttpServlet均是RestHttpServlet的子类。主要通过@RestService、@RestMapping、@RestParam这三个注解来实现,同时为了获取其他类型的参数也有@RestAddress、@RestCookie、@RestHeader、@RestSessionid、RestOutput 提供其扩展功能。
+ RestService提供类似Spring Boot的功能。开启REST功能的HTTP Server在实例化标记为@RestService的Service后自动生成对应的HttpServlet,免去开发人员编写HttpServlet的工作量。RestService生成的HttpServlet均是RestHttpServlet的子类。主要通过@RestService、@RestMapping、@RestParam这三个注解来实现,同时为了获取其他类型的参数也有@RestAddress、@RestCookie、@RestHeader、@RestSessionid、@RestBody 提供其扩展功能。
@RestService :
@@ -354,15 +354,15 @@
//默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX且XXXService为Service的类名将只截取XXX之前)
String name() default "";
- String comment() default ""; //备注描述, 对应@WebMapping.comment
+ String comment() default ""; //备注描述, 对应@HttpMapping.comment
boolean authignore() default true; //是否鉴权,默认不鉴权, 对应@AuthIgnore
int cacheseconds() default 0; //结果缓存的秒数, 为0表示不缓存, 对应@HttpCacheable.seconds
- int actionid() default 0; //操作ID值,鉴权时用到, 对应@WebMapping.actionid
+ int actionid() default 0; //操作ID值,鉴权时用到, 对应@HttpMapping.actionid
- String[] methods() default {}; //允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@WebMapping.methods
+ String[] methods() default {}; //允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应@HttpMapping.methods
}
@@ -383,7 +383,7 @@
int radix() default 10; //转换数字byte/short/int/long时所用的进制数, 默认10进制
- String comment() default ""; //备注描述, 对应@WebMapping.comment
+ String comment() default ""; //备注描述, 对应@HttpMapping.comment
}
开启REST功能的步骤很简单:在 application.xml 的 <server> 节点下增加<rest>指明RestHttpServlet的子类。
<!--
REST的核心配置项, 存在[rest]节点则Server启动时会加载REST服务, 当Server为SNCP协议时,则SncpServer会变成REST的HttpServer, 节点可以多个
- base: REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.DefaultRestServlet。
+ base: REST服务的BaseServlet,必须是 org.redkale.net.http.RestHttpServlet 的子类,该属性值默认值为 org.redkale.net.http.RestHttpServlet。
autoload:默认值"true" 默认值. 加载当前server所能使用的Servce对象;
mustsign:默认值"true" 是否只加载标记为RestService的Service类,默认只加载标记RestService且ignore=false的Service
includes:当autoload="true", 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
excludes:当autoload="true", 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开
-->
- <rest base="org.redkale.net.http.DefaultRestServlet" mustsign="true" autoload="true" includes="" excludes="">
+ <rest base="org.redkale.net.http.RestHttpServlet" mustsign="true" autoload="true" includes="" excludes="">
<!--
value: Service类名,列出的表示必须被加载的Service对象
ignore: 是否忽略,设置为true则不会加载该Service对象,默认值为false
@@ -428,7 +428,7 @@
//普通鉴权
@Override
- public void authenticate(int module, int actionid, HttpRequest request, HttpResponse response, HttpServlet next) throws IOException {
+ public void authenticate(HttpRequest request, HttpResponse response) throws IOException {
UserInfo info = currentUser(request);
if (info == null) {
response.finishJson(RET_UNLOGIN);
@@ -437,7 +437,7 @@
response.finishJson(RET_AUTHILLEGAL);
return;
}
- next.execute(request, response);
+ response.nextEvent();
}
}
@@ -539,8 +539,8 @@
//异步查询单个
@RestMapping(name = "asyncfind", auth = false, comment = "根据id查找单个Hello对象")
- public HelloEntity findHello(AsyncHandler handler, @RestParam(name = "#") int id) { //通过 /pipes/hello/asyncfind/1234 查询对象
- return source.findAsync(handler, HelloEntity.class, id);
+ public CompletableFuture<HelloEntity> findAsyncHello(@RestParam(name = "#") int id) { //通过 /pipes/hello/asyncfind/1234 查询对象
+ return source.findAsync(HelloEntity.class, id);
}
}
- 如上图DataSourceService的源码,当DataSource为本地实例时,异步接口(含AsyncHandler参数或返回类型为CompletableFuture)与同步接口执行流程相同。当DataSource为远程模式时,调用异步接口时,通信接口发到远程服务器时AsyncHandler参数的值传null,返回数据后再调用本地的AsyncHandler参数值执行。
+ 如上图源码,异步接口(含AsyncHandler参数或返回类型为CompletableFuture)与同步接口执行流程相同。当Service为远程模式时,调用异步接口时,通信接口发到远程服务器时AsyncHandler参数的值传null,返回数据后再调用本地的AsyncHandler参数值执行。
异步调用方式是提高服务并发性的有效手段,特别是在远程模式Service比较多的情况下效果更明显。以HTTP服务为例,在Tomcat刚刚改版成NIO的时候,网上随处可见都是大谈NIO性能比BIO多好,认为BIO与NIO的不同,是BIO往往会引入多线程,每个连接一个单独的线程;NIO则是使用单线程或者只使用少量的多线程,每个连接共用一个线程。而事实上呢,通常还是通过增加线程数来提高并发量。为什么NIO作用不大呢, 因为一个HTTP动态请求耗时最多是业务逻辑层,特别是操作数据库,IO操作的耗时比重小得多,只有在静态资源请求这种纯IO操作才能体现NIO、AIO(NIO.2)的优势。举例一个简单的数据查询请求,采用BIO方式耗时(为了方便比较将所耗时间扩大几倍)如下:
1、服务器TCP连接开始到进入HttpServlet,耗时 10ms
2、用户态判断和参数验证, 耗时 10ms
diff --git a/source.html b/source.html
index 327165afe..54cb1aade 100644
--- a/source.html
+++ b/source.html
@@ -404,14 +404,19 @@
以上是个简单的范例,用于用户模块存放sessionid。
<!-- 其配置算是标准的JPA配置文件的缩略版 -->
+ <!-- 其配置算是标准的JPA配置文件的缩略版 -->
<persistence>
<!-- 系统基本库 -->
- <persistence-unit name="demouser">
+ <persistence-unit name="demouser">
<!-- 为NONE表示不启动缓存,@Cacheable 失效; 非NONE值(通常用ALL)表示开启缓存。 -->
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
- <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
+ <!--
+ DataSource的实现类,没有设置默认为org.redkale.source.DataJdbcSource的实现,使用常规基于JDBC的数据库驱动一般无需设置
+ -->
+ <property name="javax.persistence.datasource" value="org.redkale.source.DataJdbcSource"/>
+
+ <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbuser?characterEncoding=utf8"/>
<!--
javax.persistence.jdbc.driver在JPA的值是JDBC驱动,Redkale有所不同,值应该是javax.sql.DataSource的子类。
为了兼容用户习惯,Redkale内置常见JDBC驱动到javax.sql.DataSource的映射关系:
@@ -423,32 +428,32 @@
因此 com.mysql.jdbc.Driver 会被自动转换成 com.mysql.jdbc.jdbc2.optional.MysqlConnectionPoolDataSource
并且如果JDBC驱动是以上几个版本,javax.persistence.jdbc.driver属性都可以省略,Redkale会根据javax.persistence.jdbc.url的值来识别驱动
-->
- <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
- <property name="javax.persistence.jdbc.user" value="root"/>
- <property name="javax.persistence.jdbc.password" value="123456"/>
+ <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
+ <property name="javax.persistence.jdbc.user" value="root"/>
+ <property name="javax.persistence.jdbc.password" value="123456"/>
<!-- 最大连接数,默认值:CPU数*16 -->
- <property name="javax.persistence.connections.limit" value="32"/>
+ <property name="javax.persistence.connections.limit" value="32"/>
<!-- 包含的SQL模板,相当于反向LIKE,不同的JDBC驱动的SQL语句不一样,Redkale内置了MySQL的语句 -->
- <property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
- <property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
+ <property name="javax.persistence.contain.sqltemplate" value="LOCATE(${keystr}, ${column}) > 0"/>
+ <property name="javax.persistence.notcontain.sqltemplate" value="LOCATE(${keystr}, ${column}) = 0"/>
<!-- 复制表结构的SQL模板,Redkale内置了MySQL的语句 -->
- <property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
- <property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
+ <property name="javax.persistence.tablenotexist.sqlstates" value="42000;42S02"/>
+ <property name="javax.persistence.tablecopy.sqltemplate" value="CREATE TABLE ${newtable} LIKE ${oldtable}"/>
</properties>
</persistence-unit>
<!-- IM消息库 -->
- <persistence-unit name="demoim">
+ <persistence-unit name="demoim">
<shared-cache-mode>NONE</shared-cache-mode>
<properties>
<!-- jdbc:mysql://127.0.0.1:3306/dbim?autoReconnect=true&autoReconnectForPools=true&characterEncoding=utf8 -->
- <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
- <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
- <property name="javax.persistence.jdbc.user" value="root"/>
- <property name="javax.persistence.jdbc.password" value="123456"/>
+ <property name="javax.persistence.jdbc.url" value="jdbc:mysql://127.0.0.1:3306/dbim?characterEncoding=utf8"/>
+ <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
+ <property name="javax.persistence.jdbc.user" value="root"/>
+ <property name="javax.persistence.jdbc.password" value="123456"/>
</properties>
</persistence-unit>
</persistence>