This commit is contained in:
redkale
2023-12-06 09:11:11 +08:00
parent ee184ac29b
commit 2c57cbc6f0
71 changed files with 0 additions and 7180 deletions

View File

@@ -1,68 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="articles.html" class="btn">技术文章</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
</section>
<section class="main-content">
<h3>Redkale 技术详解 03 -- Convert高性能序列化</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="/convert.html" target="_blank">Convert</a>是个重复造轮子的组件却是个飞速的轮子。Redkale之所以重复造轮子主要追求性能和需要与网络数据的序列化很好的结合(<a href="/convert.html#json_net_bytebuffer" target="_blank">Convert与ByteBuffer的结合</a>)。 Convert在API设计思路上也与其他同类型的框架不一样配置与序列化方法是分开的大部分场景下配置项是固定的因此不同的配置会动态生成对应的处理类以保证性能。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从包结构可以看出Convert分三层序列化与反序列化的抽象基础包JSON包、BSON包。即使boolean、int、String这种基础数据类型都不是包含在Convert基础包中。以下是详细的结构图
</p>
<p style="text-align: center;"><img src="images/convertimg_1.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从上图可以看出JSON与BSON是Convert基础包的实现主要是实现Reader与Writer类。若需要实现XML格式的序列化可以以JSON为参考自己编写。对于不是内置(ext子包下的数据类型)的且没有自定义处理(Encoder、Decoder)的数据类型, Convert会动态生成ObjectEncoder、ObjectDecoder对象。
</p>
<p>Convert 的性能</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一切不谈性能的框架都是在耍流氓下面以JSON为例与其他主流的JSON框架做个简单的性能比较(测试环境: DELL的普通笔记本)fastjson一直号称是Java性能最好的JSON解析框架其使用Benchmark是 <a href="https://github.com/eishay/jvm-serializers/wiki" target="_blank">https://github.com/eishay/jvm-serializers/wiki</a>Redkale根据该数据编写了<a href="https://github.com/redkale/redkale/tree/master/test/org/redkale/test/convert/media" target="_blank">MediaContent</a>类。实例由MediaContent.createDefault()方法所得。
</p>
<p style="text-align: center;"><img src="images/convertimg_2.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由上图第一份报告看出以MediaContent对象进行比较fastjson的反序列化性能是最好的gson性能最差。redkale、fastjson、jackson在序列化方面差距不大。第二份报告的测试对象是将第一份的MediaContent对象中所有的数值改成负数进行测试的可以看出fastjson对于负数的处理性能很差只是比gson稍强。第三份报告的测试对象是<a href="https://github.com/redkale/redkale/blob/master/test/org/redkale/test/convert/ConvertRecord.java" target="_blank">ConvertRecord</a>对象该对象的特点是包含int[]、long[]、List、Map数据。从结果可以看出fastjson的反序列化性能最差。redkale与jackson一直保持高性能。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;综合起来看Redkale的Convert性能是最好的。数据相差50毫秒以下的差距基本可以忽略因为每次测试的结果会上下波动几十毫秒。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_convert.html" target="_blank">https://redkale.org/article_convert.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,205 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 技术详解 02 -- Creator构建对象</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.redkale.util.Creator是采用ASM技术来实现代替反射构造函数的对象构建类。在根据流反序列化成对象、数据表记录转换成对象时都需要构建对象。常见的处理办法是利用反射如Gson框架中反序列化是通过反射进行对象创建。众所周知反射的性能是比较低的所以Redkale需要自实现一个对象构建类。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creator是一个接口 只有一个public T create(Object... params)方法可变参数既适合空参数的Constructor也适合含参数的Constructor。得利于Java 8的新语法特性可以在接口上加上静态方法Creator对象可以通过Creator.create(Class clazz)方法创建。构建原理是通过Constructor的参数来动态创建的。
</p>
<div class="highlight"><pre><span></span> <span class="nx">Constructor</span><span class="o">&lt;</span><span class="nx">T</span><span class="o">&gt;</span> <span class="nx">constructor0</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span>
<span class="nx">SimpleEntry</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nx">Class</span><span class="o">&gt;</span><span class="p">[]</span> <span class="nx">constructorParameters0</span> <span class="o">=</span> <span class="kc">null</span><span class="p">;</span> <span class="c1">//构造函数的参数</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">constructor0</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 1、查找public的空参数构造函数</span>
<span class="k">for</span> <span class="p">(</span><span class="nx">Constructor</span> <span class="nx">c</span> <span class="o">:</span> <span class="nx">clazz</span><span class="p">.</span><span class="nx">getConstructors</span><span class="p">())</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getParameterCount</span><span class="p">()</span> <span class="o">==</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">constructor0</span> <span class="o">=</span> <span class="nx">c</span><span class="p">;</span>
<span class="nx">constructorParameters0</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">SimpleEntry</span><span class="p">[</span><span class="mi">0</span><span class="p">];</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">constructor0</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 2、查找public带ConstructorProperties注解的构造函数</span>
<span class="k">for</span> <span class="p">(</span><span class="nx">Constructor</span> <span class="nx">c</span> <span class="o">:</span> <span class="nx">clazz</span><span class="p">.</span><span class="nx">getConstructors</span><span class="p">())</span> <span class="p">{</span>
<span class="nx">ConstructorProperties</span> <span class="nx">cp</span> <span class="o">=</span> <span class="p">(</span><span class="nx">ConstructorProperties</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">getAnnotation</span><span class="p">(</span><span class="nx">ConstructorProperties</span><span class="p">.</span><span class="kr">class</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">cp</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="nx">SimpleEntry</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nx">Class</span><span class="o">&gt;</span><span class="p">[]</span> <span class="nx">fields</span> <span class="o">=</span> <span class="nx">ConstructorParameters</span><span class="p">.</span><span class="nx">CreatorInner</span><span class="p">.</span><span class="nx">getConstructorField</span><span class="p">(</span><span class="nx">clazz</span><span class="p">,</span> <span class="nx">cp</span><span class="p">.</span><span class="nx">value</span><span class="p">());</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">fields</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">constructor0</span> <span class="o">=</span> <span class="nx">c</span><span class="p">;</span>
<span class="nx">constructorParameters0</span> <span class="o">=</span> <span class="nx">fields</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">constructor0</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 3、查找public且不带ConstructorProperties注解的构造函数</span>
<span class="nx">List</span><span class="o">&lt;</span><span class="nx">Constructor</span><span class="o">&gt;</span> <span class="nx">cs</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">();</span>
<span class="k">for</span> <span class="p">(</span><span class="nx">Constructor</span> <span class="nx">c</span> <span class="o">:</span> <span class="nx">clazz</span><span class="p">.</span><span class="nx">getConstructors</span><span class="p">())</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getAnnotation</span><span class="p">(</span><span class="nx">ConstructorProperties</span><span class="p">.</span><span class="kr">class</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getParameterCount</span><span class="p">()</span> <span class="o">&lt;</span> <span class="mi">1</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="nx">cs</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">c</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">//优先参数最多的构造函数</span>
<span class="nx">cs</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">o1</span><span class="p">,</span> <span class="nx">o2</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">o2</span><span class="p">.</span><span class="nx">getParameterCount</span><span class="p">()</span> <span class="o">-</span> <span class="nx">o1</span><span class="p">.</span><span class="nx">getParameterCount</span><span class="p">());</span>
<span class="k">for</span> <span class="p">(</span><span class="nx">Constructor</span> <span class="nx">c</span> <span class="o">:</span> <span class="nx">cs</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">SimpleEntry</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nx">Class</span><span class="o">&gt;</span><span class="p">[]</span> <span class="nx">fields</span> <span class="o">=</span> <span class="nx">ConstructorParameters</span><span class="p">.</span><span class="nx">CreatorInner</span><span class="p">.</span><span class="nx">getConstructorField</span><span class="p">(</span><span class="nx">clazz</span><span class="p">,</span> <span class="nx">Type</span><span class="p">.</span><span class="nx">getConstructorDescriptor</span><span class="p">(</span><span class="nx">c</span><span class="p">));</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">fields</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">constructor0</span> <span class="o">=</span> <span class="nx">c</span><span class="p">;</span>
<span class="nx">constructorParameters0</span> <span class="o">=</span> <span class="nx">fields</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">constructor0</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 4、查找非private带ConstructorProperties的构造函数</span>
<span class="k">for</span> <span class="p">(</span><span class="nx">Constructor</span> <span class="nx">c</span> <span class="o">:</span> <span class="nx">clazz</span><span class="p">.</span><span class="nx">getDeclaredConstructors</span><span class="p">())</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">Modifier</span><span class="p">.</span><span class="nx">isPublic</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getModifiers</span><span class="p">())</span> <span class="o">||</span> <span class="nx">Modifier</span><span class="p">.</span><span class="nx">isPrivate</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getModifiers</span><span class="p">()))</span> <span class="k">continue</span><span class="p">;</span>
<span class="nx">ConstructorProperties</span> <span class="nx">cp</span> <span class="o">=</span> <span class="p">(</span><span class="nx">ConstructorProperties</span><span class="p">)</span> <span class="nx">c</span><span class="p">.</span><span class="nx">getAnnotation</span><span class="p">(</span><span class="nx">ConstructorProperties</span><span class="p">.</span><span class="kr">class</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">cp</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="nx">SimpleEntry</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nx">Class</span><span class="o">&gt;</span><span class="p">[]</span> <span class="nx">fields</span> <span class="o">=</span> <span class="nx">ConstructorParameters</span><span class="p">.</span><span class="nx">CreatorInner</span><span class="p">.</span><span class="nx">getConstructorField</span><span class="p">(</span><span class="nx">clazz</span><span class="p">,</span> <span class="nx">cp</span><span class="p">.</span><span class="nx">value</span><span class="p">());</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">fields</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">constructor0</span> <span class="o">=</span> <span class="nx">c</span><span class="p">;</span>
<span class="nx">constructorParameters0</span> <span class="o">=</span> <span class="nx">fields</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">constructor0</span> <span class="o">==</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span> <span class="c1">// 5、查找非private且不带ConstructorProperties的构造函数</span>
<span class="nx">List</span><span class="o">&lt;</span><span class="nx">Constructor</span><span class="o">&gt;</span> <span class="nx">cs</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">ArrayList</span><span class="o">&lt;&gt;</span><span class="p">();</span>
<span class="k">for</span> <span class="p">(</span><span class="nx">Constructor</span> <span class="nx">c</span> <span class="o">:</span> <span class="nx">clazz</span><span class="p">.</span><span class="nx">getDeclaredConstructors</span><span class="p">())</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">Modifier</span><span class="p">.</span><span class="nx">isPublic</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getModifiers</span><span class="p">())</span> <span class="o">||</span> <span class="nx">Modifier</span><span class="p">.</span><span class="nx">isPrivate</span><span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getModifiers</span><span class="p">()))</span> <span class="k">continue</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getAnnotation</span><span class="p">(</span><span class="nx">ConstructorProperties</span><span class="p">.</span><span class="kr">class</span><span class="p">)</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">c</span><span class="p">.</span><span class="nx">getParameterCount</span><span class="p">()</span> <span class="o">&lt;</span> <span class="mi">1</span><span class="p">)</span> <span class="k">continue</span><span class="p">;</span>
<span class="nx">cs</span><span class="p">.</span><span class="nx">add</span><span class="p">(</span><span class="nx">c</span><span class="p">);</span>
<span class="p">}</span>
<span class="c1">//优先参数最多的构造函数</span>
<span class="nx">cs</span><span class="p">.</span><span class="nx">sort</span><span class="p">((</span><span class="nx">o1</span><span class="p">,</span> <span class="nx">o2</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nx">o2</span><span class="p">.</span><span class="nx">getParameterCount</span><span class="p">()</span> <span class="o">-</span> <span class="nx">o1</span><span class="p">.</span><span class="nx">getParameterCount</span><span class="p">());</span>
<span class="k">for</span> <span class="p">(</span><span class="nx">Constructor</span> <span class="nx">c</span> <span class="o">:</span> <span class="nx">cs</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">SimpleEntry</span><span class="o">&lt;</span><span class="nb">String</span><span class="p">,</span> <span class="nx">Class</span><span class="o">&gt;</span><span class="p">[]</span> <span class="nx">fields</span> <span class="o">=</span> <span class="nx">ConstructorParameters</span><span class="p">.</span><span class="nx">CreatorInner</span><span class="p">.</span><span class="nx">getConstructorField</span><span class="p">(</span><span class="nx">clazz</span><span class="p">,</span> <span class="nx">Type</span><span class="p">.</span><span class="nx">getConstructorDescriptor</span><span class="p">(</span><span class="nx">c</span><span class="p">));</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">fields</span> <span class="o">!=</span> <span class="kc">null</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">constructor0</span> <span class="o">=</span> <span class="nx">c</span><span class="p">;</span>
<span class="nx">constructorParameters0</span> <span class="o">=</span> <span class="nx">fields</span><span class="p">;</span>
<span class="k">break</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从以上代码可以看出根据优先级选择Constructor为了减少学习成本Creator直接重用了java.beans.ConstructorProperties注解又因ConstructorProperties只能标记在Constructor上因此定义一个Creator.ConstructorParameters注解用于标记在Creator的create方法上。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Record</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">id</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">name</span><span class="o">;</span>
<span class="nd">@ConstructorProperties</span><span class="o">({</span><span class="s">&quot;id&quot;</span><span class="o">,</span> <span class="s">&quot;name&quot;</span><span class="o">})</span>
<span class="n">Record</span><span class="o">(</span><span class="kt">int</span> <span class="n">id</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">id</span> <span class="o">=</span> <span class="n">id</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getId</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">id</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getName</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setName</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="na"><b>Record.class通过ASM自动构建与Record同package的Creator类如下:</b></span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">Record_DynCreator</span> <span class="kd">implements</span> <span class="n">Creator</span><span class="o">&lt;</span><span class="n">Record</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="nd">@Creator.ConstructorParameters</span><span class="o">({</span><span class="s">&quot;id&quot;</span><span class="o">,</span> <span class="s">&quot;name&quot;</span><span class="o">})</span>
<span class="kd">public</span> <span class="n">Record</span> <span class="nf">create</span><span class="o">(</span><span class="n">Object</span><span class="o">...</span> <span class="n">params</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">Record</span><span class="o">((</span><span class="n">Integer</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">],</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上代码若构造参数是primitive类而Creator.create传入的参数可能是null因此需要给null的primitive对象赋予默认值0。细心的人可能发现了Record的构造函数并不是public的虽然Record_DynCreator与Record在同一package但由于两者不是同一个ClassLoader故不能直接new Record。Redkale曲线救国通过URLClassLoader的私有方法在Record.class的ClassLoader加载Record_DynCreator。
</p>
<div class="highlight"><pre><span class="k">if</span> <span class="o">(</span><span class="n">loader</span> <span class="k">instanceof</span> <span class="n">URLClassLoader</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">Modifier</span><span class="o">.</span><span class="na">isPublic</span><span class="o">(</span><span class="n">constructor</span><span class="o">.</span><span class="na">getModifiers</span><span class="o">()))</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">URLClassLoader</span> <span class="n">urlLoader</span> <span class="o">=</span> <span class="o">(</span><span class="n">URLClassLoader</span><span class="o">)</span> <span class="n">loader</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">URL</span> <span class="n">url</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">URL</span><span class="o">(</span><span class="s">&quot;memclass&quot;</span><span class="o">,</span> <span class="s">&quot;localhost&quot;</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">,</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">newDynName</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="sc">&#39;/&#39;</span><span class="o">,</span> <span class="sc">&#39;.&#39;</span><span class="o">)</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">URLStreamHandler</span><span class="o">()</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">protected</span> <span class="n">URLConnection</span> <span class="nf">openConnection</span><span class="o">(</span><span class="n">URL</span> <span class="n">u</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">URLConnection</span><span class="o">(</span><span class="n">u</span><span class="o">)</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">connect</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">InputStream</span> <span class="nf">getInputStream</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">ByteArrayInputStream</span><span class="o">(</span><span class="n">bytes</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="o">});</span>
<span class="n">Method</span> <span class="n">addURLMethod</span> <span class="o">=</span> <span class="n">URLClassLoader</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getDeclaredMethod</span><span class="o">(</span><span class="s">&quot;addURL&quot;</span><span class="o">,</span> <span class="n">URL</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">addURLMethod</span><span class="o">.</span><span class="na">setAccessible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
<span class="n">addURLMethod</span><span class="o">.</span><span class="na">invoke</span><span class="o">(</span><span class="n">urlLoader</span><span class="o">,</span> <span class="n">url</span><span class="o">);</span>
<span class="n">resultClazz</span> <span class="o">=</span> <span class="n">urlLoader</span><span class="o">.</span><span class="na">loadClass</span><span class="o">(</span><span class="n">newDynName</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="sc">&#39;/&#39;</span><span class="o">,</span> <span class="sc">&#39;.&#39;</span><span class="o">));</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">Throwable</span> <span class="n">t</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//异常无需理会, 使用下一种loader方式</span>
<span class="n">t</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上代码构建一个虚拟协议的URL来实现加载若Record.class的ClassLoader不是URLClassLoader导致resultClazz为null则会抛出异常。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creator是一个典型通过ASM构建一个简单功能地动态类同类型还有 <a href="https://redkale.org/javadoc/org/redkale/util/Attribute.html" target="_blank">org.redkale.util.Attribute</a><a href="https://redkale.org/javadoc/org/redkale/util/Copier.html" target="_blank">org.redkale.util.Copier</a>
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_creator.html" target="_blank">https://redkale.org/article_creator.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 技术详解 01 -- 双亲委托模型</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,135 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 让你重新认识Java</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Java 已经22岁了依靠强大的功能、庞大的开发社区和无人能及的生态系统长期占据世界编程语言排行榜首成为当之无愧的业界之王。本人在大学时期被这种很有艺术性的开发语言所吸引果断抛弃C学习方式很简单只看JDK API源码直到现在都是如此。刚毕业就一直从事Java开发方面的工作至今也有十来年了。从JSP、WebWork到Struts、JSF从JDBC、Hibernate到TopLink、JPA。从NIO、Mina到Netty、Grizzly。很多框架都用过研究过。后来渐渐觉得各阶段主流的框架功能很强大设计理念也很好但是我们大部分情况只使用其中一小部分功能框架在实现上性能也普遍一般(除少数追求性能的框架)且适应新版JDK发布的版本普及也会滞后两三年以上。慢慢地发现用了那么多整合的框架并没有比JBuilder时代的开发速度敏捷多少很多时候在原始的Servlet、JDBC基础上做一定的封装就能满足大部分的需求。个人觉得一个优秀的框架除了保证性能和稳定性也要注重简易性而不是满足开发者需求的同时大量依赖包、繁琐的配置(过多的配置性的注解也是配置)和臃肿的jar刷其存在感。在长期看JDK API源码、学习开源框架设计理念和参考JavaEE规范接口设计的习惯下自然有了自己的思路和设计想法开始学写自己的框架。于是在2015年框架基本雏形出来并命名为<a href="http://redkale.org" target="_blank">Redkale</a>2016年正式开源。<br/>
</p>
<p>&nbsp;&nbsp;<b>太臃肿</b></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如今在Java界Tomcat、Struts2、Hibernate、MyBatis、Jetty、Spring MVC/Spring Boot/Spring XXX这些框架大家都耳熟能详似乎不懂其中一二都不好意思说自己会JavaSpring已经成了Java的代名词很多四五年以上的开发人员只识开源框架不识JDK谈起这些框架的原理、优缺点各种SOA、集群、分布式、事务、微服务概念头头是道都可以出书了但是写出来的代码或做出来的数据结构设计堪比实习生。2004年发布正式版的Spring以其轻量著称一战成名打败了J2EE成为Java事实上的"标准"。然而经过十几年的发展其生态越来越庞大功能的增多复杂的配置兼容性历史包袱使得整个框架体系越来越臃肿还有不计其数的衍生插件已经不比当年J2EE轻多少了。在那个JBuilder还是主流IDE的年代建一个Web系统还是比较简单除了Tomcat比较大点其他都算轻量。现在很多人建一个Web项目需要复杂的Maven建工程一行代码还没开始写仅仅是导入SSH/SSM这些框架就需要好几十M还得进行一堆SSH配置,简单的日志都需要配备log4j/snf4j。可能只是简单的管理系统必须要搞这么复杂吗 现在一个1-2M的框架大家都认为是轻量级MyBatis是JDBC基础上的再次封装jar包大小近6M但比Hibernate还是轻量些。这些只是基础框架如果系统还需要其他功能性的框架(Lucene、Mail、Json) 会使开发包更大。同时大量的开源框架抑制了新JDK的普及NIO出来都十五年 AIO(NIO.2)也出来六年了如今还有很多人把NIO给贴上高性能的标签JDK 5——Java第一个重大更新的版本在2004年发布直到五-六年后Spring的注解方式才得到普及(Spring旧版本xml方式普及度高) Java第二个重大更新的版本JDK 8发布也有三年了大部分人还停留在只识语法糖Lambda的程度在JDK功能越来越强大的情况下开发Java系统并不简化多少。相对于现在流行的NodeJs做个Web系统来说Java就是个巨无霸。其实呢Java无需这么复杂真的可以很简单。
</p>
<p>&nbsp;&nbsp;<b>异步呢</b></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用Java开发异步系统是件很难的事情首先Java规范中异步接口很少Servlet 3.0虽然支持异步也出来好几年了但现在直接用Servlet写代码的人已经不多而基于Servlet的Struts、Spring Boot这些框架又没把异步太当回事基本都是实现的Servet同步方法。其次JDBC更是迄今为止还没有异步接口基于JDBC的Hibernate、MyBatis同样不会有异步接口。再者开源框架以异步接口为主的凤毛麟角。 所以Java程序员在写业务代码时基本都是用同步方式特别是最耗时的数据源操作JDBC无法异步。
</p>
<div class="highlight"><pre><span></span><span class="nd">@WebServlet</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="o">{</span><span class="s">&quot;/order/*&quot;</span><span class="o">},</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;订单模块&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">OrderServlet</span> <span class="kd">extends</span> <span class="n">HttpBaseServlet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">OrderService</span> <span class="n">service</span><span class="o">;</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/order/find&quot;</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;查询单个订单&quot;</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;#&quot;</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="kt">long</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;订单ID&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">logout</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="kt">long</span> <span class="n">orderid</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getRequstURILastPath</span><span class="o">(</span><span class="mi">0</span><span class="n">L</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">service</span><span class="o">.</span><span class="na">findOrder</span><span class="o">(</span><span class="n">orderid</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="nd">@Comment</span><span class="o">(</span><span class="s">&quot;订单服务&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">OrderService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">DataSource</span> <span class="n">source</span><span class="o">;</span>
<span class="nd">@Comment</span><span class="o">(</span><span class="s">&quot;查询单个订单&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">Order</span> <span class="nf">findOrder</span><span class="o">(</span><span class="kt">long</span> <span class="n">orderid</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">source</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="n">Order</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">orderid</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以上范例是大多数Java开发者的常规写法Servlet调用ServiceSerivce调用数据库操作返回结果都是同步操作, 而基于JDBC的开发使得最耗时的数据库操作占用了大量的线程时间即使HTTP使用NIO、AIO(NIO.2)都收效甚微。而在NodeJs里IO操作都是异步的。如下
</p>
<div class="highlight"><pre><span></span><span class="nx">http</span><span class="p">.</span><span class="nx">post</span><span class="p">(</span><span class="s">&quot;/url&quot;</span><span class="p">,</span> <span class="p">{</span><span class="nx">id</span><span class="o">:</span><span class="mi">10</span><span class="p">},</span> <span class="kd">function</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="nx">response</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">service</span><span class="p">.</span><span class="nx">getResource</span><span class="p">(</span><span class="nx">request</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">result</span><span class="p">){</span>
<span class="nx">response</span><span class="p">.</span><span class="nx">write</span><span class="p">(</span><span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">result</span><span class="p">));</span>
<span class="nx">response</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="kd">var</span> <span class="nx">mysql</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s">&#39;mysql&#39;</span><span class="p">);</span>
<span class="kd">var</span> <span class="nx">pool</span> <span class="o">=</span> <span class="nx">mysql</span><span class="p">.</span><span class="nx">createPool</span><span class="p">(</span><span class="nx">config</span><span class="p">);</span>
<span class="nx">pool</span><span class="p">.</span><span class="nx">getConnection</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">connection</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">connection</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span> <span class="s">&#39;SELECT * FROM table&#39;</span><span class="p">,</span> <span class="kd">function</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">rows</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">connection</span><span class="p">.</span><span class="nx">end</span><span class="p">();</span>
<span class="p">});</span>
<span class="p">});</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这也是Nodejs做些小系统比Java还快。Java在语言和IO上的性能优势弥补不了同步来带的线程消耗。
</p>
<p>&nbsp;&nbsp;<b><a href="http://redkale.org" target="_blank">Redkale</a></b></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://redkale.org" target="_blank">Redkale</a> 一个全新设计的Java异步微服务框架。集HTTP、WebSocket、REST、JSON、RPC、DB操作、依赖注入等功能于一身<a href="http://repo.maven.apache.org/maven2/org/redkale/redkale/1.6.1/" target="_blank">redkale-1.6.1.jar</a> 包大小仅790K且不依赖任何第三方包。大部分框架自身就很庞大满足了开发者的需求同时也带来复杂的配置。如同上班只有三四里路要买辆汽车代步开车轻松的同时会带来车的保险保养堵车加油下车库找停车位等副作用 其效果还不如一辆自行车来得简单高效。<a href="http://redkale.org" target="_blank">Redkale</a> 返璞归真,抛弃沉重的历史包袱(javax.servlet、JPA等)基于JDK 8设计微服务架构尽可能挖掘新JDK的优势在保证高性能的情况下追求框架的简易性。其核心分三层结构接入层Servlet、逻辑层Service、数据层Source。 并且三层都支持异步接口从HTTP接收请求到Service处理逻辑再到Source拉取数据全程都可异步最大限度的提高CPU使用率。为适应前后台分工的开发场景<a href="http://redkale.org" target="_blank">Redkale</a>提供方便的API文档生成功能无需编写标准的Doc文档也能让前端开发人员知道后台API接口。<br>
</p>
<p>&nbsp;&nbsp;<b>Servlet</b></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在API设计上<a href="http://redkale.org" target="_blank">Redkale</a>下足了功夫敢于抛弃标准。其HTTP服务不再是javax.servlet——J2EE中使用最多的规范的实现在接口形式上与NodeJs的HTTP模块很类似易于操作。Servlet规范对于现在的应用来说过于体系化。时下移动APP、发达的前端、高性能浏览器、静动分离、REST、分布式这些因素已经让JSP、PHP、ASP这些通过后台生成页面的集中式开发框架显得不适时宜。NodeJs中的HTTP模块源码不过十几K而Java里HTTP服务主流还是Tomcat——一个8M的重型机器。 <a href="http://redkale.org" target="_blank">Redkale</a>摒弃了已经落伍的规范和功能(JSP、InputStream/OutputStream操作、Session对象等)弱化Web概念HTTP与SNCP服务一样只是接入层无需做过重的设计。 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其他语言的HTTP框架在处理请求后大多是以response关闭整个请求处理的方式为主而Servlet规范却是在service方法执行后关闭Servlet3.0规范虽然支持异步显然与其他语言框架比比较生涩难懂其API使用方式还需与同步方式区别对待且接口设计本身就会导致实现上性能不佳而response关闭的方式天然的把同步与异步等同对待无论是当前线程还是另开线程处理请求都由response来结束请求处理。同样Servlet规范中WebSocket接口设计上也是过于复杂且只是针对协议本身的实现没有考虑大多开发者的使用场景WebSocket本质上就像一个keepalive的Http请求,雷同HttpServlet。所以<a href="http://redkale.org" target="_blank">Redkale</a>在设计WebSocket时尽量与HttpServlet形态保持一致同时还集成了分布式功能让开发者也可以很简单的实现多部署。 <br>
</p>
<p>&nbsp;&nbsp;<b>Service</b></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://redkale.org" target="_blank">Redkale</a>所有API设计中最精简的当属RPC功能RPC没有直接调用的API其功能依附在Service。RPC或类似功能的框架在Java里一直是比较重量级的从古老的Corba、RMI到后来的EJB、WebService还有其他很多RPC开源框架都有着复杂的配置和大量API学习成本有些还需要区分客户端和服务端(如WebService)。 Service不仅只是个逻辑层的规范定义还集成了很强大的RPC和异步调用功能远程模式的Service就是RPC功能系统在依赖注入过程中创建Service时通过基本的IP配置自动识别是创建本地模式的Service还是远程模式的Service远程模式的Service使用的就是RPC但在代码层Service的调用本地模式与远程模式完全一样。更神奇的是带有异步回调函数CompletionHandler 或返回类型为CompletableFuture的Service方法同样能执行远程模式。这种RPC的简易性是其他框架都无可匹敌的。REST风格的Service在接口设计上尽量减少注解性的配置同时保留灵活性,减少HttpServlet的编写。<br>
</p>
<p>&nbsp;&nbsp;<b>Source</b></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;除了开发类似数据库管理工具大部分情况下开发者只用基本的增删改查操作Hibernate、MyBatis这些框架对于对象新增/更新/删除和主键查找对象等接口定义都比较简单但是带有过滤条件的操作就变得难用。MyBatis需要配各种SQL大量if elseHibernate需要写HQL或SQLJPA规范需要写JPQL或使用Criteria功能。过滤查询、翻页查询、过滤修改、局部修改、过滤删除都是很常见的操作而主流ORM框架对这类操作进行简化程度很有限。<a href="http://redkale.org" target="_blank">Redkale</a> 结合常规的使用场景以JavaBean的方式提供过滤功能无需编写SQL或类似SQL的配置使过滤性的操作(删改查)API变得异常简单。DataSource另一个亮点是分表分库操作与单表操作的API一样。同时每个操作都提供成异步接口但是又限于JDBC的同步性DataSource的默认实现提供的异步接口也只是JDBC的同步操作若开发者追求性能极致的话可以使用AIO(NIO.2)技术编写不基于JDBC的DataSource异步实现。 DataSource提供的缓存功能还能保持进程间的同步(得利于RPC)。<br>
</p>
<p>&nbsp;&nbsp;<b>思维</b></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="http://redkale.org" target="_blank">Redkale</a> 追求大道至简不仅提供高性能的功能和简易的API还带来不同的设计思维。作为一名有追求的开发者不能只停留在API层面更多的是需要掌握设计能力一个好的设计方案往往能少写很多代码。Java里很多规范和框架就是考虑太过全面为了迎合各种良莠不齐的想法和设计。比如HTTP服务只是系统的一个接入层有必须设计ServletConfig、ServletContextListener、HttpSessionListener等这么多API吗开发者在系统初期养成定义全局的BaseHttpServlet这些基类的习惯就可以控制很多东西普通功能也无需去使用什么拦截器或AOP功能。提交表单前先将表单数据转换成JSON字符串传给后台后台的接口既可用于Web也可用于APP非要按原始表单提交那只能使用Struts这类笨重的框架了。再如DB操作开发者设计好的数据结构可以把关系型数据库当NoSQL数据库操作会发现对JDBC做一定的封装就可以基本杜绝写SQL。非要写存储过程、关联五六张表进行复杂查询再好的DB框架都满足不了你。再如DateDate对象的本质是long值很多人习惯性的数据库就用Date类型这样会增加很多麻烦增加数据库的通用性难度JSON还需要提供各种DateFormat如果使用long类型时间只交给页面去format就简单很多long的性能也更好。说了这么多只是想表达一个观点开发时摆脱传统思维的桎栲换个思路去思考很多东西会变得很简单。<br>
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;想了解更多关于Redkale的资料 请访问Redkale官网: <a href="http://redkale.org" target="_blank">http://redkale.org</a>
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_regain.html" target="_blank">https://redkale.org/article_regain.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,181 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 技术详解 04 -- DataSource简易的DB操作</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;长期以来Hibernate和Mybatis一直是大家使用最多的持久层开发框架。针对这两种框架网络上是各种比较各种讨论优缺点。其实这两个框架(算上前身ibatis)都是2002年左右发布, 迄今已有15载已笨重不堪一个mybatis.jar包大小6M左右Hibernate更是巨大毫无轻巧灵活可言提供简化SQL操作的同时带来了复杂繁琐的配置和高学习门槛。而Redkale的Source组件非常轻量级通过十多个<span style="color: #2041B4;">interface</span><span style="color: #2041B4;">enum</span>和十多个<span style="color: #2041B4;">class</span>完成常见的DB操作功能。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Source组件在接口设计上参考了JPA接口为了降低学习成本部分注解仍沿用javax.persistence中的类以多个注解结合一个主操作类 <a href="http://redkale.org/javadoc/org/redkale/source/DataSource.html" target="_blank">DataSource</a> 的方式提供API。在没有IDE自动生成代码的插件支持的情况下Redkale提供了一个Demo代码<a href="https://github.com/redkale/redkale-demo/blob/master/src/org/redkale/demo/base/AutoClassCreator.java" target="_blank"> AutoClassCreator</a> 能很方便的将数据库表生成Entity类。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Source组件在接口设计上参考了JPA接口为了降低学习成本部分注解仍沿用javax.persistence中的类以多个注解结合一个主操作类 <a href="http://redkale.org/javadoc/org/redkale/source/DataSource.html" target="_blank">DataSource</a> 的方式提供API。在没有IDE自动生成代码的插件支持的情况下Redkale提供了一个Demo代码<a href="https://github.com/redkale/redkale-demo/blob/master/src/org/redkale/demo/base/AutoClassCreator.java" target="_blank"> AutoClassCreator</a> 能很方便的将数据库表生成Entity类。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</p>
<div class="highlight"><pre><span class="n">Constructor</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">constructor0</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Constructor</span> <span class="n">c</span> <span class="o">:</span> <span class="n">clazz</span><span class="o">.</span><span class="na">getConstructors</span><span class="o">())</span> <span class="o">{</span> <span class="c1">//优先找public 的构造函数</span>
<span class="k">if</span> <span class="o">(</span><span class="n">c</span><span class="o">.</span><span class="na">getParameterCount</span><span class="o">()</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="n">constructor0</span> <span class="o">=</span> <span class="n">c</span><span class="o">;</span>
<span class="k">break</span><span class="o">;</span>
<a href="articles.html"></a>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">constructor0</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span><span class="c1">//其次找非private带ConstructorProperties的构造函数</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Constructor</span> <span class="n">c</span> <span class="o">:</span> <span class="n">clazz</span><span class="o">.</span><span class="na">getDeclaredConstructors</span><span class="o">())</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">Modifier</span><span class="o">.</span><span class="na">isPrivate</span><span class="o">(</span><span class="n">c</span><span class="o">.</span><span class="na">getModifiers</span><span class="o">()))</span> <span class="k">continue</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">c</span><span class="o">.</span><span class="na">getAnnotation</span><span class="o">(</span><span class="n">ConstructorProperties</span><span class="o">.</span><span class="na">class</span><span class="o">)</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">constructor0</span> <span class="o">=</span> <span class="n">c</span><span class="o">;</span>
<span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">constructor0</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span><span class="c1">//再次找非private且带-parameters编译项的构造函数 java 8以上才支持</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Constructor</span> <span class="n">c</span> <span class="o">:</span> <span class="n">clazz</span><span class="o">.</span><span class="na">getDeclaredConstructors</span><span class="o">())</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">Modifier</span><span class="o">.</span><span class="na">isPrivate</span><span class="o">(</span><span class="n">c</span><span class="o">.</span><span class="na">getModifiers</span><span class="o">()))</span> <span class="k">continue</span><span class="o">;</span>
<span class="n">Parameter</span><span class="o">[]</span> <span class="n">params</span> <span class="o">=</span> <span class="n">c</span><span class="o">.</span><span class="na">getParameters</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">params</span><span class="o">.</span><span class="na">length</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="k">continue</span><span class="o">;</span>
<span class="kt">boolean</span> <span class="n">flag</span> <span class="o">=</span> <span class="kc">true</span><span class="o">;</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Parameter</span> <span class="n">param</span> <span class="o">:</span> <span class="n">params</span><span class="o">)</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">clazz</span><span class="o">.</span><span class="na">getDeclaredField</span><span class="o">(</span><span class="n">param</span><span class="o">.</span><span class="na">getName</span><span class="o">());</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">Exception</span> <span class="n">e</span><span class="o">)</span> <span class="o">{</span>
<span class="n">flag</span> <span class="o">=</span> <span class="kc">false</span><span class="o">;</span>
<span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">flag</span><span class="o">)</span> <span class="o">{</span>
<span class="n">constructor0</span> <span class="o">=</span> <span class="n">c</span><span class="o">;</span>
<span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(</span><span class="n">constructor0</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span><span class="c1">//最后找非private的空构造函数</span>
<span class="k">for</span> <span class="o">(</span><span class="n">Constructor</span> <span class="n">c</span> <span class="o">:</span> <span class="n">clazz</span><span class="o">.</span><span class="na">getDeclaredConstructors</span><span class="o">())</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">Modifier</span><span class="o">.</span><span class="na">isPrivate</span><span class="o">(</span><span class="n">c</span><span class="o">.</span><span class="na">getModifiers</span><span class="o">()))</span> <span class="k">continue</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">c</span><span class="o">.</span><span class="na">getParameterCount</span><span class="o">()</span> <span class="o">==</span> <span class="mi">0</span><span class="o">)</span> <span class="o">{</span>
<span class="n">constructor0</span> <span class="o">=</span> <span class="n">c</span><span class="o">;</span>
<span class="k">break</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从以上代码可以看出根据优先级选择Constructor为了减少学习成本Creator直接重用了java.beans.ConstructorProperties注解又因ConstructorProperties只能标记在Constructor上因此定义一个Creator.ConstructorParameters注解用于标记在Creator的create方法上。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">Record</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">id</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">name</span><span class="o">;</span>
<span class="nd">@ConstructorProperties</span><span class="o">({</span><span class="s">&quot;id&quot;</span><span class="o">,</span> <span class="s">&quot;name&quot;</span><span class="o">})</span>
<span class="n">Record</span><span class="o">(</span><span class="kt">int</span> <span class="n">id</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">id</span> <span class="o">=</span> <span class="n">id</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getId</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">id</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getName</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setName</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="na"><b>Record.class通过ASM自动构建与Record同package的Creator类如下:</b></span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">Record_DynCreator</span> <span class="kd">implements</span> <span class="n">Creator</span><span class="o">&lt;</span><span class="n">Record</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="nd">@Creator.ConstructorParameters</span><span class="o">({</span><span class="s">&quot;id&quot;</span><span class="o">,</span> <span class="s">&quot;name&quot;</span><span class="o">})</span>
<span class="kd">public</span> <span class="n">Record</span> <span class="nf">create</span><span class="o">(</span><span class="n">Object</span><span class="o">...</span> <span class="n">params</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">Record</span><span class="o">((</span><span class="n">Integer</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">],</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上代码若构造参数是primitive类而Creator.create传入的参数可能是null因此需要给null的primitive对象赋予默认值0。细心的人可能发现了Record的构造函数并不是public的虽然Record_DynCreator与Record在同一package但由于两者不是同一个ClassLoader故不能直接new Record。Redkale曲线救国通过URLClassLoader的私有方法在Record.class的ClassLoader加载Record_DynCreator。
</p>
<div class="highlight"><pre><span class="k">if</span> <span class="o">(</span><span class="n">loader</span> <span class="k">instanceof</span> <span class="n">URLClassLoader</span> <span class="o">&amp;&amp;</span> <span class="o">!</span><span class="n">Modifier</span><span class="o">.</span><span class="na">isPublic</span><span class="o">(</span><span class="n">constructor</span><span class="o">.</span><span class="na">getModifiers</span><span class="o">()))</span> <span class="o">{</span>
<span class="k">try</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">URLClassLoader</span> <span class="n">urlLoader</span> <span class="o">=</span> <span class="o">(</span><span class="n">URLClassLoader</span><span class="o">)</span> <span class="n">loader</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">URL</span> <span class="n">url</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">URL</span><span class="o">(</span><span class="s">&quot;memclass&quot;</span><span class="o">,</span> <span class="s">&quot;localhost&quot;</span><span class="o">,</span> <span class="o">-</span><span class="mi">1</span><span class="o">,</span> <span class="s">&quot;/&quot;</span> <span class="o">+</span> <span class="n">newDynName</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="sc">&#39;/&#39;</span><span class="o">,</span> <span class="sc">&#39;.&#39;</span><span class="o">)</span> <span class="o">+</span> <span class="s">&quot;/&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">URLStreamHandler</span><span class="o">()</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">protected</span> <span class="n">URLConnection</span> <span class="nf">openConnection</span><span class="o">(</span><span class="n">URL</span> <span class="n">u</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">URLConnection</span><span class="o">(</span><span class="n">u</span><span class="o">)</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">connect</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">InputStream</span> <span class="nf">getInputStream</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">ByteArrayInputStream</span><span class="o">(</span><span class="n">bytes</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="o">});</span>
<span class="n">Method</span> <span class="n">addURLMethod</span> <span class="o">=</span> <span class="n">URLClassLoader</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getDeclaredMethod</span><span class="o">(</span><span class="s">&quot;addURL&quot;</span><span class="o">,</span> <span class="n">URL</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">addURLMethod</span><span class="o">.</span><span class="na">setAccessible</span><span class="o">(</span><span class="kc">true</span><span class="o">);</span>
<span class="n">addURLMethod</span><span class="o">.</span><span class="na">invoke</span><span class="o">(</span><span class="n">urlLoader</span><span class="o">,</span> <span class="n">url</span><span class="o">);</span>
<span class="n">resultClazz</span> <span class="o">=</span> <span class="n">urlLoader</span><span class="o">.</span><span class="na">loadClass</span><span class="o">(</span><span class="n">newDynName</span><span class="o">.</span><span class="na">replace</span><span class="o">(</span><span class="sc">&#39;/&#39;</span><span class="o">,</span> <span class="sc">&#39;.&#39;</span><span class="o">));</span>
<span class="o">}</span> <span class="k">catch</span> <span class="o">(</span><span class="n">Throwable</span> <span class="n">t</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//异常无需理会, 使用下一种loader方式</span>
<span class="n">t</span><span class="o">.</span><span class="na">printStackTrace</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上代码构建一个虚拟协议的URL来实现加载若Record.class的ClassLoader不是URLClassLoader导致resultClazz为null则会抛出异常。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Creator是一个典型通过ASM构建一个简单功能地动态类同类型还有 <a href="https://redkale.org/javadoc/org/redkale/util/Attribute.html" target="_blank">org.redkale.util.Attribute</a><a href="https://redkale.org/javadoc/org/redkale/util/Copier.html" target="_blank">org.redkale.util.Copier</a>
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_source.html" target="_blank">https://redkale.org/article_creator.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,128 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<p style="display: none;" class="art-list">
<a href="course11_sncp.html" target="_blank" class="art-title">Redkale 入门教程 11 -- SNCP分布式部署</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p style="display: none;" class="art-list">
<a href="course10_websocket.html" target="_blank" class="art-title">Redkale 入门教程 10 -- WebSocket</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p style="display: none;" class="art-list">
<a href="course09_fileup.html" target="_blank" class="art-title">Redkale 入门教程 09 -- 文件上传下载</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p style="display: none;" class="art-list">
<a href="course08_httpservlet.html" target="_blank" class="art-title">Redkale 入门教程 08 -- HttpServlet</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p style="display: none;" class="art-list">
<a href="course07_convert.html" target="_blank" class="art-title">Redkale 入门教程 07 -- Convert</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p style="display: none;" class="art-list">
<a href="course06_dbdis.html" target="_blank" class="art-title">Redkale 入门教程 06 -- DataSource 分库分表</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p style="display: none;" class="art-list">
<a href="course05_dbaction.html" target="_blank" class="art-title">Redkale 入门教程 05 -- DataSource 增删改查</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p style="display: none;" class="art-list">
<a href="course04_cachedb.html" target="_blank" class="art-title">Redkale 入门教程 04 -- CacheSource缓存数据源</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p style="display: none;" class="art-list">
<a href="course03_userauth.html" target="_blank" class="art-title">Redkale 入门教程 03 -- 用户鉴权</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p class="art-list">
<a href="course02_rest.html" target="_blank" class="art-title">Redkale 入门教程 02 -- REST敏捷开发</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p class="art-list">
<a href="course01_hello.html" target="_blank" class="art-title">Redkale 入门教程 01 -- Hello Word</a>
<label class="art-date">2017-06</label><br/>
<label class="art-desc">Redkale 入门教程 </label>
</p>
<p class="art-list">
<a href="article_convert.html" target="_blank" class="art-title">Redkale 技术详解 03 -- Convert高性能序列化</a>
<label class="art-date">2016-03</label><br/>
<label class="art-desc">Convert是个重复造轮子的组件却是个飞速的轮子。</label>
</p>
<p class="art-list">
<a href="article_creator.html" target="_blank" class="art-title">Redkale 技术详解 02 -- Creator构建对象</a>
<label class="art-date">2016-02</label><br/>
<label class="art-desc">org.redkale.util.Creator是采用ASM技术来实现代替反射构造函数的对象构建类。</label>
</p>
<p class="art-list">
<a href="article_parents.html" target="_blank" class="art-title">Redkale 技术详解 01 -- 双亲委托模型</a>
<label class="art-date">2016-02</label><br/>
<label class="art-desc">Redkale 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。</label>
</p>
<br/>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,51 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="articles.html" class="btn">技术文章</a>
<a href="code.html" class="btn">Java 源码</a>
</section>
<section class="main-content">
<h3><a id="github" class="anchor" href="#" aria-hidden="true"></a>Github 源码</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/redkale" target="_blank" >Redkale Github 源码</a></p>
<h3><a id="javadoc" class="anchor" href="#" aria-hidden="true"></a>Javadoc API</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="javadoc/index.html" target="_blank" >在线 Javadoc API</a> </p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,431 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/normalize.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/github-light.css" media="screen">
<link rel="stylesheet" type="text/css" href="stylesheets/highlight.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="convert_intro" class="anchor" href="#" aria-hidden="true"></a>Convert 组件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Convert 是一个比较独立的组件仅依赖于util包。提供Java对象的序列化与反序列化功能。支持JSON(JavaScript Object Notation)、BSON(Binary Stream Object Notation)两种格式化。 两种格式使用方式完全一样其性能都大幅度超过其他JSON框架。同时JSON内置于HTTP服务中BSON也是SNCP协议数据序列化的基础。<br/></p>
<h3><a id="convert_study" class="anchor" href="#" aria-hidden="true"></a>Convert 快速上手</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本介绍仅以JSON为例(BSON与JSON使用方式雷同)。其操作类主要是JsonConvert配置类主要是JsonFactory、ConvertColumn。JsonFactory采用同ClassLoader类似的双亲委托方式设计。</br></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JsonConvert 序列化encode方法</p>
<div class="highlight"><pre> <span class="kd">public</span> <span class="n">String</span> <span class="nf">convertTo</span><span class="o">(<span class="kd">final</span> </span><span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">convertTo</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">convertTo</span><span class="o">(</span><span class="kd">final</span> <span class="n">OutputStream</span> <span class="n">out</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">convertTo</span><span class="o">(</span><span class="kd">final</span> <span class="n">OutputStream</span> <span class="n">out</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="kd">public</span> <span class="n">ByteBuffer</span><span class="o">[]</span> <span class="nf">convertTo</span><span class="o">(</span><span class="kd">final</span> <span class="n"><b>java.util.function.Supplier</b></span><span class="o">&lt;</span><span class="n">ByteBuffer</span><span class="o">&gt;</span> <span class="n">supplier</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="kd">public</span> <span class="n">ByteBuffer</span><span class="o">[]</span> <span class="nf">convertTo</span><span class="o">(</span><span class="kd">final</span> <span class="n"><b>java.util.function.Supplier</b></span><span class="o">&lt;</span><span class="n">ByteBuffer</span><span class="o">&gt;</span> <span class="n">supplier</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">convertTo</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonWriter</span> <span class="n">writer</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">convertTo</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonWriter</span> <span class="n">writer</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JsonConvert 反序列化decode方法</p>
<div class="highlight"><pre> <span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">convertFrom</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">text</span><span class="o">);</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">convertFrom</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">char</span><span class="o">[]</span> <span class="n">text</span><span class="o">);</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">convertFrom</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">char</span><span class="o">[]</span> <span class="n">text</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">start</span><span class="o">,</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">len</span><span class="o">);</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">convertFrom</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">InputStream</span> <span class="n">in</span><span class="o">);</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">convertFrom</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">ByteBuffer</span><span class="o">...</span> <span class="n">buffers</span><span class="o">);</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">convertFrom</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">JsonReader</span> <span class="n">reader</span><span class="o">);</span></pre></div>
<p id="json_net_bytebuffer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 与 ByteBuffer 的结合 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从以上的方法可以看出与其他JSON框架相比Convert多了与ByteBuffer结合的方法。特别是convertTo方法加了Supplier&lt;ByteBuffer&gt;方法这么做是为了提高数据传输的性能。在大部分情况下JSON序列化得到的数据流是为了传输出去常见的场景就是HTTP+JSON接口。Convert提供ByteBuffer接口会大量减少中间临时数据的产生。大部分输出JSON数据的方法如下:
</p>
<div class="highlight"><pre> <span class="kd">public</span> <span class="kt">void</span> <span class="nf">doPost</span><span class="o">(</span><span class="n">HttpServletRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpServletResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">ServletException</span><span class="o">,</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">json</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Gson()</span><span class="o">.</span><span class="na">toJson</span><span class="o">(record);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">setContentType</span><span class="o">(</span><span class="s">&quot;text/json; charset=UTF-8&quot;</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">getOutputStream</span><span class="o">().</span><span class="na">write</span><span class="o">(</span><span class="n">json</span><span class="o">.</span><span class="na">getBytes</span><span class="o">(</span><span class="s">&quot;UTF-8&quot;</span><span class="o">));</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;几乎所有的JSON框架提供的接口以String作为返回结果为主其内在都是以char[]作为JsonWriter的载体。以Gson为例Gson拼接JSON默认使用的是StringWriterStringWriter的扩容策略是翻倍。为了方便计算假设一个对象转换成JSON字符串大小为了10K。Gson在转换过程中产生的临时的char[]的大小: 16 + 32 + 64 + 128 + 256 + 512 + 1K + 2K + 4K + 8K + 16K = 32K, char[]转换成最终的String结果又会产生10K的char[], 最后在response输出时又会产生10K的byte[](方便计算不考虑双字节),也就是说整个对象输出过程中会产生52K的临时数据。而且常见的HTTP服务器(如实现java-servlet规范的服务器)不会把底层的ByteBuffer对象池暴露给上层。所以以String为输出结果的JSON方法都会产生5倍于数据体积大小(其他低于1倍扩容策略的框架会产生更多)的垃圾数据。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale框架的HTTP服务内置了Convert的JSON接口避免了大量的垃圾数据产生。Redkale的HTTP是基于AIO(NIO.2)实现且存在ByteBuffer对象池response的finishJson系列方法将HTTP服务的ByteBuffer对象池传给Convert 使Convert在序列化过程中直接以UTF-8编码方式输出到ByteBuffer里输出结束后将ByteBuffer交给对象池回收从而减少大量构建bye[]、char[]所产生的临时数据。</p>
<div class="highlight"><pre> <span class="kd">protected</span> <span class="kt">void</span> <span class="nf">execute</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">record</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<br/>
<p id="convert_base">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 基本用法:</p>
<div class="highlight"><pre> <span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserRecord</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">username</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">password</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">UserRecord</span><span class="o">()</span> <span class="o">{</span>
<span class="o">}</span>
<span class="o">/**</span> <span class="n">以下省略getter</span> <span class="n">setter方法</span> <span class="o">*/</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">UserRecord</span> <span class="n">user</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">UserRecord</span><span class="o">();</span>
<span class="n">user</span><span class="o">.</span><span class="na">setUserid</span><span class="o">(</span><span class="mi">100</span><span class="o">);</span>
<span class="n">user</span><span class="o">.</span><span class="na">setUsername</span><span class="o">(</span><span class="s">&quot;redkalename&quot;</span><span class="o">);</span>
<span class="n">user</span><span class="o">.</span><span class="na">setPassword</span><span class="o">(</span><span class="s">&quot;123456&quot;</span><span class="o">);</span>
<span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span> <span class="o">=</span> <span class="n">JsonConvert</span><span class="o">.</span><span class="na">root</span><span class="o">();</span>
<span class="n">String</span> <span class="n">json</span> <span class="o">=</span> <span class="n">convert</span><span class="o">.</span><span class="na">convertTo</span><span class="o">(</span><span class="n">user</span><span class="o">);</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">json</span><span class="o">);</span> <span class="c1">//应该是 {&quot;password&quot;:&quot;123456&quot;,&quot;userid&quot;:100,&quot;username&quot;:&quot;redkalename&quot;}</span>
<span class="n">UserRecord</span> <span class="n">user2</span> <span class="o">=</span> <span class="n">convert</span><span class="o">.</span><span class="na">convertFrom</span><span class="o">(</span><span class="n">UserRecord</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="n">json</span><span class="o">);</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">convert</span><span class="o">.</span><span class="na">convertTo</span><span class="o">(</span><span class="n">user2</span><span class="o">));</span> <span class="c1">//应该也是 {&quot;password&quot;:&quot;123456&quot;,&quot;userid&quot;:100,&quot;username&quot;:&quot;redkalename&quot;}</span>
<span class="cm">/**</span>
<span class="cm"> * 以下功能是为了屏蔽password字段。</span>
<span class="cm"> * 等价于 public String getPassword() 加上 @ConvertColumn </span>
<span class="cm"> *</span>
<span class="cm"> * @ConvertColumn(ignore = true, type = ConvertType.JSON)</span>
<span class="cm"> * public String getPassword() {</span>
<span class="cm"> * return password;</span>
<span class="cm"> * }</span>
<span class="cm"> **/</span>
<span class="kd">final</span> <span class="n">JsonFactory</span> <span class="n">childFactory</span> <span class="o">=</span> <span class="n">JsonFactory</span><span class="o">.</span><span class="na">root</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span>
<span class="n">childFactory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">UserRecord</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="s">&quot;password&quot;</span><span class="o">);</span> <span class="c1">//屏蔽掉password字段使其不输出</span>
<span class="n">childFactory</span><span class="o">.</span><span class="na">reloadCoder</span><span class="o">(</span><span class="n">UserRecord</span><span class="o">.</span><span class="k">class</span><span class="o">);</span> <span class="c1">//重新加载Coder使之覆盖父Factory的配置</span>
<span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">childConvert</span> <span class="o">=</span> <span class="n">childFactory</span><span class="o">.</span><span class="na">getConvert</span><span class="o">();</span>
<span class="n">json</span> <span class="o">=</span> <span class="n">childConvert</span><span class="o">.</span><span class="na">convertTo</span><span class="o">(</span><span class="n">user</span><span class="o">);</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">json</span><span class="o">);</span> <span class="c1">//应该是 {&quot;userid&quot;:100,&quot;username&quot;:&quot;redkalename&quot;}</span>
<span class="n">user2</span> <span class="o">=</span> <span class="n">childConvert</span><span class="o">.</span><span class="na">convertFrom</span><span class="o">(</span><span class="n">UserRecord</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="n">json</span><span class="o">);</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">childConvert</span><span class="o">.</span><span class="na">convertTo</span><span class="o">(</span><span class="n">user2</span><span class="o">));</span> <span class="c1">//应该也是 {&quot;userid&quot;:100,&quot;username&quot;:&quot;redkalename&quot;}</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在Redkale里存在默认的JsonConvert、BsonConvert对象。 只需在所有Service、Servlet中增加依赖注入资源。</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">XXXService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">JsonConvert</span> <span class="n">jsonConvert</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">BsonConvert</span> <span class="n">bsonConvert</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">XXXServlet</span> <span class="kd">extends</span> <span class="n">HttpServlet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">JsonConvert</span> <span class="n">jsonConvert</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">BsonConvert</span> <span class="n">bsonConvert</span><span class="o">;</span>
<span class="o">}</span>
</pre></div>
<p id="convert_diffout">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;同一类型数据通过设置新的JsonFactory可以有不同的输出。</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserSimpleInfo</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">username</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="nd">@ConvertColumn</span><span class="o">(</span><span class="n">ignore</span> <span class="o">=</span> <span class="kc">true</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">ConvertType</span><span class="o">.</span><span class="na">JSON</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">regtime</span><span class="o">;</span> <span class="c1">//注册时间</span>
<span class="nd">@ConvertColumn</span><span class="o">(</span><span class="n">ignore</span> <span class="o">=</span> <span class="kc">true</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">ConvertType</span><span class="o">.</span><span class="na">JSON</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">regaddr</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//注册IP</span>
<span class="o">/**</span> <span class="n">以下省略getter</span> <span class="n">setter方法</span> <span class="o">*/</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserInfoServlet</span> <span class="kd">extends</span> <span class="n">HttpBaseServlet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserSerice</span> <span class="n">service</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">JsonFactory</span> <span class="n">jsonRootFactory</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">JsonConvert</span> <span class="n">detailConvert</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">(</span><span class="n">HttpContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">AnyValue</span> <span class="n">config</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">JsonFactory</span> <span class="n">childFactory</span> <span class="o">=</span> <span class="n">jsonRootFactory</span><span class="o">.</span><span class="na">createChild</span><span class="o">();</span>
<span class="n">childFactory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">UserSimpleInfo</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="s">&quot;regtime&quot;</span><span class="o">,</span> <span class="s">&quot;regaddr&quot;</span><span class="o">);</span> <span class="c1">//允许输出注册时间与注册地址</span>
<span class="n">childFactory</span><span class="o">.</span><span class="na">reloadCoder</span><span class="o">(</span><span class="n">UserSimpleInfo</span><span class="o">.</span><span class="na">class</span><span class="o">);</span> <span class="c1">//重新加载Coder使之覆盖父Factory的配置</span>
<span class="k">this</span><span class="o">.</span><span class="na">detailConvert</span> <span class="o">=</span> <span class="n">childFactory</span><span class="o">.</span><span class="na">getConvert</span><span class="o">();</span>
<span class="o">}</span>
<span class="c1">// 获取他人基本信息</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/user/info/&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">info</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">userid</span> <span class="o">=</span> <span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRequstURILastPath</span><span class="o">());</span>
<span class="n">UserSimpleInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">findUserInfo</span><span class="o">(</span><span class="n">userid</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">user</span><span class="o">);</span> <span class="c1">// 不包含用户的注册时间和注册地址字段信息</span>
<span class="o">}</span>
<span class="c1">//获取用户自己的信息</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/user/myinfo&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">mydetail</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">userid</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="n">currentUser</span><span class="o">().</span><span class="na">getUserid</span><span class="o">();</span> <span class="c1">//获取当前用户ID</span>
<span class="n">UserSimpleInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">findUserInfo</span><span class="o">(</span><span class="n">userid</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">detailConvert</span><span class="o">,</span> <span class="n">user</span><span class="o">);</span> <span class="c1">// 包含用户的注册时间和注册地址字段信息</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 支持带参数构造函数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. <b>public</b> 带参数的构造函数加上 @ConstructorParameters 注解:</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserRecord</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">username</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">password</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="nd">@ConstructorParameters</span><span class="o">({</span><span class="s">&quot;userid&quot;</span><span class="o">,</span> <span class="s">&quot;username&quot;</span><span class="o">,</span> <span class="s">&quot;password&quot;</span><span class="o">})</span>
<span class="kd">public</span> <span class="nf">UserRecord</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">username</span><span class="o">,</span> <span class="n">String</span> <span class="n">password</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">userid</span> <span class="o">=</span> <span class="n">userid</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">username</span> <span class="o">=</span> <span class="n">username</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">password</span> <span class="o">=</span> <span class="n">password</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getUserid</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">userid</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getUsername</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">username</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getPassword</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">password</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. 自定义Creator</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserRecord</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">username</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">password</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="n">UserRecord</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">username</span><span class="o">,</span> <span class="n">String</span> <span class="n">password</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">userid</span> <span class="o">=</span> <span class="n">userid</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">username</span> <span class="o">=</span> <span class="n">username</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">password</span> <span class="o">=</span> <span class="n">password</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getUserid</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">userid</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getUsername</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">username</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getPassword</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">password</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/**</span>
<span class="cm"> * 自定义Creator方法。</span>
<span class="cm"> * 1) 方法名可以随意。</span>
<span class="cm"> * 2) 方法必须是static。<b>声明为private的方法只能被当前类使用若想方法被子类使用需要声明protected</b></span>
<span class="cm"> * 3方法的参数必须为空。</span>
<span class="cm"> * 4方法的返回类型必须是Creator。</span>
<span class="cm"> *</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="n">Creator</span><span class="o">&lt;</span><span class="n">UserRecord</span><span class="o">&gt;</span> <span class="nf">creator</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">Creator</span><span class="o">&lt;</span><span class="n">UserRecord</span><span class="o">&gt;()</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="nd">@ConstructorParameters</span><span class="o">({</span><span class="s">&quot;userid&quot;</span><span class="o">,</span> <span class="s">&quot;username&quot;</span><span class="o">,</span> <span class="s">&quot;password&quot;</span><span class="o">})</span> <span class="c1">//带参数的构造函数必须有ConstructorParameters注解</span>
<span class="kd">public</span> <span class="n">UserRecord</span> <span class="nf">create</span><span class="o">(</span><span class="n">Object</span><span class="o">...</span> <span class="n">params</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">UserRecord</span><span class="o">((</span><span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="mi">0</span> <span class="o">:</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">]),</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">1</span><span class="o">],</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">2</span><span class="o">]);</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常JavaBean类默认有个public空参数的构造函数因此大部分情况下不要自定义Creator其实只要不是private的空参数构造函数Convert都能自动支持(其他的框架都仅支持public的构造函数)只有仅含private的构造函数才需要自定义Creator。带参数的构造函数就需要标记@ConstructorParameters常见于Immutable Object。<br/>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 支持自定义Decode、Encode。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. 通过ConvertFactory显式的注册</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">FileSimpleCoder</span><span class="o">&lt;</span><span class="n">R</span> <span class="kd">extends</span> <span class="n">Reader</span><span class="o">,</span> <span class="n">W</span> <span class="kd">extends</span> <span class="n">Writer</span><span class="o">&gt;</span> <span class="kd">extends</span> <span class="n">SimpledCoder</span><span class="o">&lt;</span><span class="n">R</span><span class="o">,</span> <span class="n">W</span><span class="o">,</span> <span class="n">File</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">FileSimpleCoder</span> <span class="n">instance</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">FileSimpleCoder</span><span class="o">();</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">convertTo</span><span class="o">(</span><span class="n">W</span> <span class="n">out</span><span class="o">,</span> <span class="n">File</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">writeString</span><span class="o">(</span><span class="n">value</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="n">value</span><span class="o">.</span><span class="na">getPath</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">File</span> <span class="nf">convertFrom</span><span class="o">(</span><span class="n">R</span> <span class="n">in</span><span class="o">)</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">path</span> <span class="o">=</span> <span class="n">in</span><span class="o">.</span><span class="na">readString</span><span class="o">();</span>
<span class="k">return</span> <span class="n">path</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">new</span> <span class="nf">File</span><span class="o">(</span><span class="n">path</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">JsonFactory</span><span class="o">.</span><span class="na">root</span><span class="o">().</span><span class="na">register</span><span class="o">(</span><span class="n">java</span><span class="o">.</span><span class="na">io</span><span class="o">.</span><span class="na">File</span><span class="o">.</span><span class="kd">class</span><span class="o">,</span> <span class="n">FileSimpleCoder</span><span class="o">.</span><span class="na">instance</span><span class="o">);</span>
<span class="n">BsonFactory</span><span class="o">.</span><span class="na">root</span><span class="o">().</span><span class="na">register</span><span class="o">(</span><span class="n">java</span><span class="o">.</span><span class="na">io</span><span class="o">.</span><span class="na">File</span><span class="o">.</span><span class="kd">class</span><span class="o">,</span> <span class="n">FileSimpleCoder</span><span class="o">.</span><span class="na">instance</span><span class="o">);</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 通过JavaBean类自定义静态方法自动加载</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">InnerCoderEntity</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">val</span><span class="o">;</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="kt">int</span> <span class="n">id</span><span class="o">;</span>
<span class="kd">private</span> <span class="nf">InnerCoderEntity</span><span class="o">(</span><span class="kt">int</span> <span class="n">id</span><span class="o">,</span> <span class="n">String</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">id</span> <span class="o">=</span> <span class="n">id</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">val</span> <span class="o">=</span> <span class="n">value</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="n">InnerCoderEntity</span> <span class="nf">create</span><span class="o">(</span><span class="kt">int</span> <span class="n">id</span><span class="o">,</span> <span class="n">String</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="nf">InnerCoderEntity</span><span class="o">(</span><span class="n">id</span><span class="o">,</span> <span class="n">value</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/**</span>
<span class="cm"> * 该方法提供给Convert组件自动加载。</span>
<span class="cm"> * 1) 方法名可以随意。</span>
<span class="cm"> * 2) 方法必须是static</span>
<span class="cm"> * 3方法的参数有且只能有一个 且必须是org.redkale.convert.ConvertFactory或子类。</span>
<span class="cm"> * —3.1) 参数类型为org.redkale.convert.ConvertFactory 表示适合JSON和BSON。</span>
<span class="cm"> * —3.2) 参数类型为org.redkale.convert.json.JsonFactory 表示仅适合JSON。</span>
<span class="cm"> * —3.3) 参数类型为org.redkale.convert.bson.BsonFactory 表示仅适合BSON。</span>
<span class="cm"> * 4方法的返回类型必须是org.redkale.convert.Decodeable/org.redkale.convert.Encodeable/org.redkale.convert.SimpledCoder</span>
<span class="cm"> * 若返回类型不是org.redkale.convert.SimpledCoder, 就必须提供两个方法: 一个返回Decodeable 一个返回 Encodeable。</span>
<span class="cm"> *</span>
<span class="cm"> * @param factory</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="n">SimpledCoder</span><span class="o">&lt;</span><span class="n">Reader</span><span class="o">,</span> <span class="n">Writer</span><span class="o">,</span> <span class="n">InnerCoderEntity</span><span class="o">&gt;</span> <span class="nf">createConvertCoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">convert</span><span class="o">.</span><span class="na">ConvertFactory</span> <span class="n">factory</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">SimpledCoder</span><span class="o">&lt;</span><span class="n">Reader</span><span class="o">,</span> <span class="n">Writer</span><span class="o">,</span> <span class="n">InnerCoderEntity</span><span class="o">&gt;()</span> <span class="o">{</span>
<span class="c1">//必须与EnMember[] 顺序一致</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">DeMember</span><span class="o">[]</span> <span class="n">deMembers</span> <span class="o">=</span> <span class="k">new</span> <span class="n">DeMember</span><span class="o">[]{</span>
<span class="n">DeMember</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">factory</span><span class="o">,</span> <span class="n">InnerCoderEntity</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="s">&quot;id&quot;</span><span class="o">),</span>
<span class="n">DeMember</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">factory</span><span class="o">,</span> <span class="n">InnerCoderEntity</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="s">&quot;val&quot;</span><span class="o">)};</span>
<span class="c1">//必须与DeMember[] 顺序一致</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">EnMember</span><span class="o">[]</span> <span class="n">enMembers</span> <span class="o">=</span> <span class="k">new</span> <span class="n">EnMember</span><span class="o">[]{</span>
<span class="n">EnMember</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">factory</span><span class="o">,</span> <span class="n">InnerCoderEntity</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="s">&quot;id&quot;</span><span class="o">),</span>
<span class="n">EnMember</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">factory</span><span class="o">,</span> <span class="n">InnerCoderEntity</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="s">&quot;val&quot;</span><span class="o">)};</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">convertTo</span><span class="o">(</span><span class="n">Writer</span> <span class="n">out</span><span class="o">,</span> <span class="n">InnerCoderEntity</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">value</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">writeObjectNull</span><span class="o">(</span><span class="n">InnerCoderEntity</span><span class="o">.</span><span class="k">class</span><span class="o">);</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">out</span><span class="o">.</span><span class="na">writeObjectB</span><span class="o">(</span><span class="n">value</span><span class="o">);</span>
<span class="k">for</span> <span class="o">(</span><span class="n">EnMember</span> <span class="n">member</span> <span class="o">:</span> <span class="n">enMembers</span><span class="o">)</span> <span class="o">{</span>
<span class="n">out</span><span class="o">.</span><span class="na">writeObjectField</span><span class="o">(</span><span class="n">member</span><span class="o">,</span> <span class="n">value</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">out</span><span class="o">.</span><span class="na">writeObjectE</span><span class="o">(</span><span class="n">value</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">InnerCoderEntity</span> <span class="nf">convertFrom</span><span class="o">(</span><span class="n">Reader</span> <span class="n">in</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">in</span><span class="o">.</span><span class="na">readObjectB</span><span class="o">(</span><span class="n">InnerCoderEntity</span><span class="o">.</span><span class="k">class</span><span class="o">)</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="kt">int</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">;</span>
<span class="kd">final</span> <span class="n">Object</span><span class="o">[]</span> <span class="n">params</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Object</span><span class="o">[</span><span class="n">deMembers</span><span class="o">.</span><span class="na">length</span><span class="o">];</span>
<span class="k">while</span> <span class="o">(</span><span class="n">in</span><span class="o">.</span><span class="na">hasNext</span><span class="o">())</span> <span class="o">{</span>
<span class="n">DeMember</span> <span class="n">member</span> <span class="o">=</span> <span class="n">in</span><span class="o">.</span><span class="na">readFieldName</span><span class="o">(</span><span class="n">deMembers</span><span class="o">);</span> <span class="c1">//读取字段名</span>
<span class="n">in</span><span class="o">.</span><span class="na">readBlank</span><span class="o">();</span> <span class="c1">//读取字段名与字段值之间的间隔符JSON则是跳过冒号:</span>
<span class="k">if</span> <span class="o">(</span><span class="n">member</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">in</span><span class="o">.</span><span class="na">skipValue</span><span class="o">();</span> <span class="c1">//跳过不存在的字段的值, 一般不会发生</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">params</span><span class="o">[</span><span class="n">index</span><span class="o">++]</span> <span class="o">=</span> <span class="n">member</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="n">in</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="n">in</span><span class="o">.</span><span class="na">readObjectE</span><span class="o">(</span><span class="n">InnerCoderEntity</span><span class="o">.</span><span class="k">class</span><span class="o">);</span>
<span class="k">return</span> <span class="n">InnerCoderEntity</span><span class="o">.</span><span class="na">create</span><span class="o">(</span><span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">]</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="mi">0</span> <span class="o">:</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">0</span><span class="o">],</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">params</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getId</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">id</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getVal</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">val</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">JsonConvert</span><span class="o">.</span><span class="na">root</span><span class="o">().</span><span class="na">convertTo</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由上可以看出Convert的自定义配置完全符合面向对象思想提倡在JavaBean内部去自定义非常规的构造函数或Decode、Encode方法通过ConvertFactory显式配置的方式通常用于非自己定义的数据类(如 java.io.File)。</p>
<br/>
<h3><a id="convert_bson_struct" class="anchor" href="#" aria-hidden="true"></a>BSON的协议格式</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BSON类似Java自带的Serializable 其格式如下: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1). 基本数据类型: 直接转换成byte[] <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3). String: length(4 bytes) + byte[](utf8); <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4). 数组: length(4 bytes) + byte[]... <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5). Object: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. realclass (SmallString) (如果指定格式化的class与实体对象的class不一致才会有该值, 该值可以使用@ConvertEntity给其取个别名) <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2. 空字符串(SmallString) <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3. SIGN_OBJECTB 标记位值固定为0xBB (short)<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4. 循环字段值:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.1 SIGN_HASNEXT 标记位值固定为1 (byte) <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.2 字段类型; 1-9为基本类型&字符串; 101-109为基本类型&字符串的数组; 127为Object <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.3 字段名 (SmallString) <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4.4 字段的值Object <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5. SIGN_NONEXT 标记位值固定为0 (byte)<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6. SIGN_OBJECTE 标记位值固定为0xEE (short)<br/>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,177 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 01 -- Hello Word</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 可以说是Java界最精简的框架不到1M的jar包可以替代Tomcat、Spring/Spring Boot、Hibernate/MyBatis、JackJson/fastjson、Netty的集合四两拨千斤。低调开源一年多经过两次大的改善后终于达到让自己满意的地步。Redkale不仅仅提供简易的API还附有很多不同于传统思维的设计思路。由于时间有限一年多也没写入门教程现在开始抽点时间写一些教程希望能给想学Redkale的同学一点帮助。 废话不多说,下面进入正题。<br/>
</p>
<p>下载Redkale</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;源码可以从 <a href="https://github.com/redkale" target="_blank" >https://github.com/redkale</a><a href="http://git.oschina.net/redkale/redkale" target="_blank" >http://git.oschina.net/redkale/redkale</a> 下载 。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;jar包可以从 <a href="http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22org.redkale%22%20AND%20a%3A%22redkale%22" target="_blank" >http://search.maven.org</a><a href="https://repo1.maven.org/maven2/org/redkale/redkale/" target="_blank" >https://repo1.maven.org/maven2/org/redkale/redkale/</a> 下载最新版本的包。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当前最新版为 1.8 下载 redkale-1.8.0.tar.gz 放在本地。<br/>
</p>
<p>创建工程</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本人使用NetBeans很多年了所以本教程以NetBeans来创建工程 使用Eclipse的同学请自行参考。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IntelliJ IDEA 使用者见 <a href="course01_helloidea.html">Redkale 入门教程 01 -- Hello Word(IntelliJ IDEA Maven版)</a>
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先创建一个"<b>Java应用程序</b>"项目, 注意: 不管是否Web项目都不要创建Web应用程序。
</p>
<p style="text-align: center;"><img src="images/hello_01.png" alt=""/><img src="images/hello_02.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;创建完空项目后,将 redkale-1.8.0.tar.gz 解压覆盖到项目的目录下。
</p>
<p style="text-align: center;"><img src="images/hello_03.png" alt=""/><img src="images/hello_04.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;点击项目右键进入“属性”-> “库”中,点击 “添加JAR/文件夹”找到项目lib目录下的redkale-1.8.0.jar 并导入。
</p>
<p style="text-align: center;"><img src="images/hello_05.png" alt=""/><img src="images/hello_06.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;点击“源”在下面测试包中导入项目目录下的conf目录这样方便编辑conf下的配置文件(在上面src中导入会打包进jar中)。
</p>
<p style="text-align: center;"><img src="images/hello_07.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;点击“运行”,在主类中输入 "<b>org.redkale.boot.Application</b>",然后点击“确定”。
</p>
<p style="text-align: center;"><img src="images/hello_08.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编写HelloService类。
</p>
<div class="highlight"><pre><span></span><span class="kn">package</span> <span class="n">com.redkale.demo</span><span class="o">;</span>
<span class="kn">import</span> <span class="n">org.redkale.net.http.*</span><span class="o">;</span>
<span class="kn">import</span> <span class="n">org.redkale.service.Service</span><span class="o">;</span>
<span class="nd">@RestService</span><span class="o">(</span><span class="n">automapping</span> <span class="o">=</span> <span class="kc">true</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">sayHello</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Hello World"</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">hi</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Hi, "</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此类提供两个方法say 和 hi。编写完后按"<b>F6</b>" 直接运行。
</p>
<p style="text-align: center;"><img src="images/hello_09.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在浏览器输入: http://127.0.0.1:6060/pipes/hello/say 可以看到结果:
</p>
<p style="text-align: center;"><img src="images/hello_10.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在浏览器输入: http://127.0.0.1:6060/pipes/hello/hi?name=Redkale 可以看到结果:
</p>
<p style="text-align: center;"><img src="images/hello_11.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;访问地址的端口6060和前缀pipes是通过conf/application.xml文件进行配置
</p>
<div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">application</span> <span class="na">port</span><span class="o">=</span><span class="s">"5050"</span><span class="p">&gt;</span>
<span class="c">&lt;!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml --&gt;</span>
<span class="p">&lt;</span><span class="nt">resources</span><span class="p">&gt;</span>
<span class="c">&lt;!-- </span>
<span class="c"> &lt;properties&gt;</span>
<span class="c"> &lt;property name="system.property.convert.json.tiny" value="true"/&gt;</span>
<span class="c"> &lt;/properties&gt;</span>
<span class="c"> --&gt;</span>
<span class="p">&lt;/</span><span class="nt">resources</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">server</span> <span class="na">protocol</span><span class="o">=</span><span class="s">"HTTP"</span> <span class="na">host</span><span class="o">=</span><span class="s">"0.0.0.0"</span> <span class="na">port</span><span class="o">=</span><span class="s">"6060"</span> <span class="na">root</span><span class="o">=</span><span class="s">"root"</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">services</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span><span class="p">/&gt;</span>
<span class="c">&lt;!-- base指定的自定义HttpServlet子类必须标记@HttpUserType, 不设置base则视为没有当前用户信息设置 --&gt;</span>
<span class="p">&lt;</span><span class="nt">rest</span> <span class="na">path</span><span class="o">=</span><span class="s">"/pipes"</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">servlets</span> <span class="na">path</span><span class="o">=</span><span class="s">"/pipes"</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">server</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">application</span><span class="p">&gt;</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;至此一个简单的Hello服务就开发和调试完成了。可以看出代码简单很多不需要太多配置、maven和其他依赖包。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可能有人会疑惑: HelloServie为什么能分配到hello前缀 sayHello为什么会映射到/pipes/hello/say 请求? Redkale为了减少Annotation配置采取了一些默认值的策略 在Redkale里 一个Service视为一个模块或服务所以需要有模块(服务)名的概念,用于服务管理和鉴权,通常需要通过@RestServie.name来指定模块名没有指定则默认将Service类名的Service字样之前的字符串视为模块名如HelloService和HelloServiceImpl都会采用hello作为模块名。方法名的默认值策略也是类似将模块名字样之前的字符串作为方法名如sayHello和sayHelloMe 都会用say作为默认值。参数名如果没有指定@RestParam.name会自动采用代码的变量名。 完全标记Rest注解的HelloService源码如下
</p>
<div class="highlight"><pre><span></span><span class="kn">package</span> <span class="n">com.redkale.demo</span><span class="o">;</span>
<span class="kn">import</span> <span class="n">org.redkale.net.http.*</span><span class="o">;</span>
<span class="kn">import</span> <span class="n">org.redkale.service.Service</span><span class="o">;</span>
<span class="nd">@RestService</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"hello"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"say"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">sayHello</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Hello World"</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"hi"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">hi</span><span class="o">(</span><span class="nd">@RestParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"name"</span><span class="o">)</span> <span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Hi, "</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这段代码与上面那段是等价的。部署也很简单, 将项目目录中dist目录下的redkale-demo.jar复制到lib下运行bin/start.bat 即可启动HTTP服务。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/course01_hello.html" target="_blank">https://redkale.org/course01_hello.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,164 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 01 -- Hello Word(IntelliJ IDEA Maven版)</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 可以说是Java界最精简的框架不到1M的jar包可以替代Tomcat、Spring/Spring Boot、Hibernate/MyBatis、JackJson/fastjson、Netty的集合四两拨千斤。低调开源一年多经过两次大的改善后终于达到让自己满意的地步。Redkale不仅仅提供简易的API还附有很多不同于传统思维的设计思路。由于时间有限一年多也没写入门教程现在开始抽点时间写一些教程希望能给想学Redkale的同学一点帮助。 废话不多说,下面进入正题。<br/>
</p>
<p>创建工程</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;首先创建一个Maven项目。
</p>
<p style="text-align: center;"><img src="images/hello_21.png" alt=""/><img src="images/hello_22.png" alt=""/></p>
<p style="text-align: center;"><img src="images/hello_23.png" alt=""/><img src="images/hello_24.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;创建完项目后会自动打开pom.xml文件 按下Alt+Insert组合键添加redkale依赖。
</p>
<p style="text-align: center;"><img src="images/hello_25.png" alt=""/><img src="images/hello_26.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;然后将redkale下的bin和conf文件夹可以通过github或者maven里<a href="https://repo1.maven.org/maven2/org/redkale/redkale/1.9.5/redkale-1.9.5.tar.gz" target="_blank">redkale-1.9.5.tar.gz</a>解压得到)复制到工程的目录下。
</p>
<p style="text-align: center;"><img src="images/hello_27.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编写HelloService类。
</p>
<div class="highlight"><pre><span></span><span class="kn">package</span> <span class="n">com.redkale.examples.hello</span><span class="o">;</span>
<span class="kn">import</span> <span class="n">org.redkale.net.http.*</span><span class="o">;</span>
<span class="kn">import</span> <span class="n">org.redkale.service.Service</span><span class="o">;</span>
<span class="nd">@RestService</span><span class="o">(</span><span class="n">automapping</span> <span class="o">=</span> <span class="kc">true</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">sayHello</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Hello World"</span><span class="o">;</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">hi</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Hi, "</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p style="text-align: center;"><img src="images/hello_28.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;然后开始调试运行。
</p>
<p style="text-align: center;"><img src="images/hello_29.png" alt=""/></p>
<p style="text-align: center;"><img src="images/hello_30.png" alt=""/></p>
<p style="text-align: center;"><img src="images/hello_31.png" alt=""/></p>
<p style="text-align: center;"><img src="images/hello_32.png" alt=""/></p>
<p style="text-align: center;"><img src="images/hello_33.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在浏览器输入: http://127.0.0.1:6060/pipes/hello/say 可以看到结果:
</p>
<p style="text-align: center;"><img src="images/hello_34.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在浏览器输入: http://127.0.0.1:6060/pipes/hello/hi?name=Redkale 可以看到结果:
</p>
<p style="text-align: center;"><img src="images/hello_35.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;访问地址的端口6060和前缀pipes是通过conf/application.xml文件进行配置
</p>
<div class="highlight"><pre><span></span><span class="p">&lt;</span><span class="nt">application</span> <span class="na">port</span><span class="o">=</span><span class="s">"2121"</span><span class="p">&gt;</span>
<span class="c">&lt;!-- 详细配置说明见: http://redkale.org/redkale.html#redkale_confxml --&gt;</span>
<span class="p">&lt;</span><span class="nt">resources</span><span class="p">&gt;</span>
<span class="c">&lt;!-- </span>
<span class="c"> &lt;properties&gt;</span>
<span class="c"> &lt;property name="system.property.convert.json.tiny" value="true"/&gt;</span>
<span class="c"> &lt;/properties&gt;</span>
<span class="c"> --&gt;</span>
<span class="p">&lt;/</span><span class="nt">resources</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">server</span> <span class="na">protocol</span><span class="o">=</span><span class="s">"HTTP"</span> <span class="na">host</span><span class="o">=</span><span class="s">"0.0.0.0"</span> <span class="na">port</span><span class="o">=</span><span class="s">"6060"</span> <span class="na">root</span><span class="o">=</span><span class="s">"root"</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">services</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span><span class="p">/&gt;</span>
<span class="c">&lt;!-- base指定的自定义HttpServlet子类必须标记@HttpUserType, 不设置base则视为没有当前用户信息设置 --&gt;</span>
<span class="p">&lt;</span><span class="nt">rest</span> <span class="na">path</span><span class="o">=</span><span class="s">"/pipes"</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">servlets</span> <span class="na">path</span><span class="o">=</span><span class="s">"/pipes"</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">server</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">application</span><span class="p">&gt;</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;至此一个简单的Hello服务就开发和调试完成了。可以看出代码简单很多不需要太多配置、maven和其他依赖包。<br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;可能有人会疑惑: HelloServie为什么能分配到hello前缀 sayHello为什么会映射到/pipes/hello/say 请求? Redkale为了减少Annotation配置采取了一些默认值的策略 在Redkale里 一个Service视为一个模块或服务所以需要有模块(服务)名的概念,用于服务管理和鉴权,通常需要通过@RestServie.name来指定模块名没有指定则默认将Service类名的Service字样之前的字符串视为模块名如HelloService和HelloServiceImpl都会采用hello作为模块名。方法名的默认值策略也是类似将模块名字样之前的字符串作为方法名如sayHello和sayHelloMe 都会用say作为默认值。参数名如果没有指定@RestParam.name会自动采用代码的变量名。 完全标记Rest注解的HelloService源码如下
</p>
<div class="highlight"><pre><span></span><span class="kn">package</span> <span class="n">com.redkale.examples.hello</span><span class="o">;</span>
<span class="kn">import</span> <span class="n">org.redkale.net.http.*</span><span class="o">;</span>
<span class="kn">import</span> <span class="n">org.redkale.service.Service</span><span class="o">;</span>
<span class="nd">@RestService</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"hello"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"say"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">sayHello</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Hello World"</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"hi"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">hi</span><span class="o">(</span><span class="nd">@RestParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"name"</span><span class="o">)</span> <span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">"Hi, "</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;这段代码与上面那段是等价的。部署也很简单, 将项目编译后的jar和redkale-1.9.5.jar复制到lib下(也可通过修改pom.xml让maven来处理)运行bin/start.bat 即可启动HTTP服务。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本工程源码可以在 <a href="https://github.com/redkale/redkale-examples/tree/master/redkale-helloword" target="_blank">https://github.com/redkale/redkale-examples/tree/master/redkale-helloword</a> 下载。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/course01_helloidea.html" target="_blank">https://redkale.org/course01_helloidea.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 02 -- DataSource 连接</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,218 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 02 -- REST敏捷开发</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REST是 <a href="index.html" target="_blank">Redkale</a> 的主要功能之一REST提供的功能是根据Service自动生成HttpServlet需要注意的是 <b>Redkale里的REST与标准的RESTfull规范完全不同仅仅名称类似</b>。标准的REST规范比较死板只是在请求URL和Method上做文章功能单一。Redkale里的REST功能是很强大的 无论登陆、鉴权、文件上传下载、WebSocket都可以REST化几乎完全可以省去HttpServlet。<br/>
</p>
<table style="margin: auto;">
<tr><th>注解类名</th><th>功能描述</th></tr>
<tr><td style="text-align: left;">@RestService</td><td>标记Service需要REST化。</td></tr>
<tr><td style="text-align: left;">@RestMapping</td><td>标记请求的方法名,同一方法上可重复标记(需确保name值在Service中是唯一的)。<br><b>其标记的Service方法只能throws IOException或不抛异常</b></td></tr>
<tr><td style="text-align: left;">@RestConvert</td><td>标记请求的方法名上对返回值以JSON形式输出时进行字段的屏蔽或开启进行设置</b></td></tr>
<tr><td style="text-align: left;">@RestConvertCoder</td><td>标记请求的方法名上对返回值以JSON形式输出时对类指定的字段的进行设置</b></td></tr>
<tr><td style="text-align: left;">@RestParam</td><td>获取常规参数值, 字段类型可以是 基础数据类型/Flipper/CompletionHandler/String/JavaBean<br>name='&#38;'&nbsp;&nbsp;&nbsp;&nbsp;表示当前用户(@HttpUserType)<br>name='#'&nbsp;&nbsp;&nbsp;&nbsp;表示截取uri最后一段<br>name='#xxx:'&nbsp;&nbsp;&nbsp;&nbsp;表示从uri中/pipes/xxx:v/截取xxx:的值</td></tr>
<tr><td style="text-align: left;">@RestHeader</td><td>通过request.getHeader获取参数值, 字段类型只能是String</td></tr>
<tr><td style="text-align: left;">@RestCookie</td><td>通过request.getCookie获取Cookie值, 字段类型只能是String</td></tr>
<tr><td style="text-align: left;">@RestBody<td>通过request.getBody获取参数值, 字段类型只能是String/byte[]/JavaBean</td></tr>
<tr><td style="text-align: left;">@RestSessionid<td>获取sessionid, 字段类型只能是String</td></tr>
<tr><td style="text-align: left;">@RestAddress<td>获取客户端IP地址, 字段类型只能是String</td></tr>
<tr><td style="text-align: left;">@RestURI</td><td>获取请求URL, 字段类型只能是String</td></tr>
<tr><td style="text-align: left;">@RestUploadFile</td><td>获取上传文件, 字段类型只能是File/File[]/byte[]</td></tr>
<tr><td style="text-align: center;font-size: 0.9rem;" colspan="2"><b>WebSocket</b></td></tr>
<tr><td style="text-align: left;">@RestWebSocket</td><td>标记WebSocket需要REST化只能标记在WebSocket的子类上</td></tr>
<tr><td style="text-align: left;">@RestOnMessage</td><td>WebSocket的消息路由类似@RestMapping不同的请求映射到不同的方法</td></tr>
</table>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;标记@RestService的Service对象在服务启动时会自动生成原始的HttpServlet加载到当前的HttpServer中其HttpServlet的请求URL规则为path + "/" + @RestService.catalog() + "/" + @RestService.name() + "/*" 其中path为application.xml文件中&#60;rest&#62;节点的path属性值。节点rest和servlets设计一个path属性是为了所有动态请求加个前缀方便静动分离没有采取.jsp .do那种刷存在感的后缀方式也是处于安全考虑外界根据URL无法判断后台使用的是什么语言或框架开发。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REST会根据Service方法的返回类型不同做出不同的结果输出。
<table style="margin: auto;">
<tr><th>返回类型</th><th>功能描述</th></tr>
<tr><td style="text-align: left;">void</td><td>以RetResult.success()的JSON形式输出。</td></tr>
<tr><td style="text-align: left;">String</td><td>以字符串输出。</td></tr>
<tr><td style="text-align: left;">File</td><td>以下载文件形式输出。</td></tr>
<tr><td style="text-align: left;">HttpResult</td><td>将HttpHeader、HttpCookie、Result统一输出</td></tr>
<tr><td style="text-align: left;">CompletableFuture<td>异步输出根据CompletableFuture.get()结果类型进行不同形式输出</td></tr>
<tr><td style="text-align: left;">JavaBean/其他<td>以JSON形式输出</td></tr>
</table>
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;要开启REST功能需要在application.xml对应的HttpServer下加入rest节点:
</p>
<p style="text-align: center;"><img src="images/rest_01.png" alt=""/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果需要加入鉴权功能更需要自定义HttpServlet基类并重载preExecute、authenticate方法。详情见 <a href="http://redkale.org/net.html#baseservlet">BaseHttpServlet</a>
</p>
<p>用户登陆范例</p>
<div class="highlight"><pre><span></span><span class="nd">@RestService</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"user"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户服务"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserService</span> <span class="kd">extends</span> <span class="n">AbstractService</span> <span class="o">{</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"login"</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户登陆"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">RetResult</span> <span class="nf">login</span><span class="o">(</span><span class="n">String</span> <span class="n">account</span><span class="o">,</span> <span class="n">String</span> <span class="n">password</span><span class="o">,</span> <span class="nd">@RestHeader</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"User-Agent"</span><span class="o">)</span> <span class="n">String</span> <span class="n">agent</span><span class="o">,</span>
<span class="nd">@RestSessionid</span><span class="o">(</span><span class="n">create</span> <span class="o">=</span> <span class="kc">true</span><span class="o">)</span> <span class="n">String</span> <span class="n">sessionid</span><span class="o">,</span> <span class="nd">@RestAddress</span> <span class="n">String</span> <span class="n">clientAddr</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="s">"redkale"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">account</span><span class="o">))</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1001</span><span class="o">,</span> <span class="s">"账号不是redkale"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="s">"123456"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">password</span><span class="o">))</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1002</span><span class="o">,</span> <span class="s">"密码错误"</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"用户("</span> <span class="o">+</span> <span class="n">account</span> <span class="o">+</span> <span class="s">")的回话ID为: "</span> <span class="o">+</span> <span class="n">sessionid</span> <span class="o">+</span> <span class="s">", 通过客户端("</span> <span class="o">+</span> <span class="n">agent</span> <span class="o">+</span> <span class="s">")在"</span> <span class="o">+</span> <span class="n">clientAddr</span> <span class="o">+</span> <span class="s">"登陆。"</span><span class="o">);</span>
<span class="k">return</span> <span class="n">RetResult</span><span class="o">.</span><span class="na">success</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;浏览器输入: http://127.0.0.1:6060/pipes/user/login?account=redkale&password=123456 <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回结果: {"retcode":0,"success":true} <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;后台打印: 用户(redkale)的回话ID为: 6110627db03b2b4a2c45a2fcb2aa1403, 通过客户端(Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36)在127.0.0.1登陆。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REST的注解不仅可以注解在Service的方法参数上 还可以在Service的方法的JavaBean参数的类里的字段进行注解。
</p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">LoginBean</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">account</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">password</span><span class="o">;</span>
<span class="nd">@RestHeader</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"User-Agent"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">agent</span><span class="o">;</span>
<span class="nd">@RestSessionid</span><span class="o">(</span><span class="n">create</span> <span class="o">=</span> <span class="kc">true</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">sessionid</span><span class="o">;</span>
<span class="nd">@RestAddress</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">clientAddr</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">JsonConvert</span><span class="o">.</span><span class="na">root</span><span class="o">().</span><span class="na">convertTo</span><span class="o">(</span><span class="k">this</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="o">}</span>
<span class="nd">@RestService</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"user"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户服务"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserService</span> <span class="kd">extends</span> <span class="n">AbstractService</span> <span class="o">{</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"login"</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户登陆"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">RetResult</span> <span class="nf">login</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">bean</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1000</span><span class="o">,</span> <span class="s">"没有登陆信息"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="s">"redkale"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">bean</span><span class="o">.</span><span class="na">getAccount</span><span class="o">()))</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1001</span><span class="o">,</span> <span class="s">"账号不是redkale"</span><span class="o">);</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="s">"123456"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">bean</span><span class="o">.</span><span class="na">getPassword</span><span class="o">()))</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1002</span><span class="o">,</span> <span class="s">"密码错误"</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"用户("</span> <span class="o">+</span> <span class="n">bean</span><span class="o">.</span><span class="na">getAccount</span><span class="o">()</span> <span class="o">+</span> <span class="s">")通过客户端("</span> <span class="o">+</span> <span class="n">bean</span><span class="o">.</span><span class="na">getAgent</span><span class="o">()</span> <span class="o">+</span> <span class="s">")在"</span> <span class="o">+</span> <span class="n">bean</span><span class="o">.</span><span class="na">getClientAddr</span><span class="o">()</span> <span class="o">+</span> <span class="s">"登陆。"</span><span class="o">);</span>
<span class="k">return</span> <span class="n">RetResult</span><span class="o">.</span><span class="na">success</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;浏览器输入: http://127.0.0.1:6160/pipes/user/login?bean={account:redkale,password:123456} <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;返回结果: {"retcode":0,"success":true} <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;后台打印: 用户(redkale)通过客户端(Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36)在127.0.0.1登陆。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如果用户登陆成功后需要跳转到首页或者还可能需要输出一些Cookie值就需要使用HttpResult作为返回结果例如
</p>
<div class="highlight"><pre><span></span><span class="nd">@RestService</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"user"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户服务"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserService</span> <span class="kd">extends</span> <span class="n">AbstractService</span> <span class="o">{</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"login"</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户登陆"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">HttpResult</span> <span class="nf">login</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">bean</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">HttpResult</span><span class="o">&lt;&gt;(</span><span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1000</span><span class="o">,</span> <span class="s">"没有登陆信息"</span><span class="o">));</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="s">"redkale"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">bean</span><span class="o">.</span><span class="na">getAccount</span><span class="o">()))</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">HttpResult</span><span class="o">&lt;&gt;(</span><span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1001</span><span class="o">,</span> <span class="s">"账号不是redkale"</span><span class="o">));</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!</span><span class="s">"123456"</span><span class="o">.</span><span class="na">equals</span><span class="o">(</span><span class="n">bean</span><span class="o">.</span><span class="na">getPassword</span><span class="o">()))</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">HttpResult</span><span class="o">&lt;&gt;(</span><span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1002</span><span class="o">,</span> <span class="s">"密码错误"</span><span class="o">));</span>
<span class="o">}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"用户("</span> <span class="o">+</span> <span class="n">bean</span><span class="o">.</span><span class="na">getAccount</span><span class="o">()</span> <span class="o">+</span> <span class="s">")通过客户端("</span> <span class="o">+</span> <span class="n">bean</span><span class="o">.</span><span class="na">getAgent</span><span class="o">()</span> <span class="o">+</span> <span class="s">")在"</span> <span class="o">+</span> <span class="n">bean</span><span class="o">.</span><span class="na">getClientAddr</span><span class="o">()</span> <span class="o">+</span> <span class="s">"登陆。"</span><span class="o">);</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">HttpResult</span><span class="o">().</span><span class="na">header</span><span class="o">(</span><span class="s">"Location"</span><span class="o">,</span> <span class="s">"/index.html"</span><span class="o">).</span><span class="na">cookie</span><span class="o">(</span><span class="k">new</span> <span class="n">HttpCookie</span><span class="o">(</span><span class="s">"curraccount"</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getAccount</span><span class="o">()));</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>文件上传</p>
<div class="highlight"><pre><span></span><span class="nd">@RestService</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"file"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"文件服务"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">FileService</span> <span class="kd">extends</span> <span class="n">AbstractService</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">Logger</span> <span class="n">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="n">FileService</span><span class="o">.</span><span class="na">class</span><span class="o">.</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">format</span> <span class="o">=</span> <span class="s">"%1$tY%1$tm%1$td%1$tH%1$tM%1$tS"</span><span class="o">;</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"upload"</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"文件上传,不鉴权"</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">RetResult</span> <span class="nf">upload</span><span class="o">(</span><span class="nd">@RestUploadFile</span><span class="o">(</span><span class="n">maxLength</span> <span class="o">=</span> <span class="mi">1</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024</span><span class="o">,</span> <span class="n">fileNameReg</span> <span class="o">=</span> <span class="s">".*\\.doc$"</span><span class="o">)</span> <span class="n">File</span> <span class="n">tmpFile</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tmpFile</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">1001</span><span class="o">,</span> <span class="s">"没有上传文件或文件大小超过1M或文件不是.doc后缀"</span><span class="o">);</span>
<span class="c1">//按日期命名 如 file-20170601133520.doc</span>
<span class="k">try</span> <span class="o">{</span>
<span class="n">logger</span><span class="o">.</span><span class="na">finest</span><span class="o">(</span><span class="s">"用户上传的文件名为: "</span> <span class="o">+</span> <span class="n">MultiContext</span><span class="o">.</span><span class="na">getFileName</span><span class="o">(</span><span class="n">tmpFile</span><span class="o">));</span>
<span class="n">File</span> <span class="n">destFile</span> <span class="o">=</span> <span class="k">new</span> <span class="n">File</span><span class="o">(</span><span class="s">"D:/docs/file-"</span> <span class="o">+</span> <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="n">format</span><span class="o">,</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">())</span> <span class="o">+</span> <span class="s">".doc"</span><span class="o">);</span>
<span class="n">destFile</span><span class="o">.</span><span class="na">getParentFile</span><span class="o">().</span><span class="na">mkdirs</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">tmpFile</span><span class="o">.</span><span class="na">renameTo</span><span class="o">(</span><span class="n">destFile</span><span class="o">))</span> <span class="o">{</span> <span class="c1">//tmpFile与destFile不在同一盘符下会导致renameTo失败</span>
<span class="n">java</span><span class="o">.</span><span class="na">nio</span><span class="o">.</span><span class="na">file</span><span class="o">.</span><span class="na">Files</span><span class="o">.</span><span class="na">copy</span><span class="o">(</span><span class="n">tmpFile</span><span class="o">.</span><span class="na">toPath</span><span class="o">(),</span> <span class="n">destFile</span><span class="o">.</span><span class="na">toPath</span><span class="o">(),</span> <span class="n">StandardCopyOption</span><span class="o">.</span><span class="na">ATOMIC_MOVE</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span> <span class="k">finally</span> <span class="o">{</span> <span class="c1">//如果发生异常,将临时文件从{APP_HOME}/tmp 目录下删除</span>
<span class="n">tmpFile</span><span class="o">.</span><span class="na">delete</span><span class="o">();</span>
<span class="o">}</span>
<span class="k">return</span> <span class="n">RetResult</span><span class="o">.</span><span class="na">success</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebSocket与其REST化将在以后的章节详细介绍。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/course02_rest.html" target="_blank">https://redkale.org/course02_rest.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 03 -- 用户鉴权</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 04 -- CacheSource缓存数据源</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 05 -- DataSource 增删改查</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 06 -- DataSource 分库分表</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 07 -- Convert</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 08 -- HttpServlet</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 09 -- 文件上传下载</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 10 -- WebSocket</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,111 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3>Redkale 入门教程 11 -- SNCP分布式部署</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="index.html" target="_blank">Redkale</a> 里大量使用了双亲委托模型序列化的ConvertFactory、依赖注入的ResourceFactory、服务管理的WatchFactory均采用双亲委托模型。用于优先加载自定义的处理类同时也保证两个同级的子Factory不会相互干扰。<br/>
</p>
<p>ClassLoader类加载</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型最经典的例子就是JVM的类加载器ClassLoader。每个ClassLoader实例都有一个父类加载器的引用不是继承关系是包含关系虚拟机内置的类加载器Bootstrap ClassLoader本身没有父类加载器但可以用作其它ClassLoader实例的的父类加载器。当一个ClassLoader实例需要加载某个类时它会试图亲自搜索某个类之前先把这个任务委托给它的父类加载器这个过程是由上至下依次检查的首先由最顶层的类加载器Bootstrap ClassLoader试图加载如果没加载到则把任务转交给Extension ClassLoader试图加载如果也没加载到则转交给App ClassLoader 进行加载如果它也没有加载得到的话则返回给委托的发起者由它到指定的文件系统或网络等URL中加载该类。如果它们都没有加载到这个类时则抛出ClassNotFoundException异常。否则将这个找到的类生成一个类的定义并将它加载到内存当中最后返回这个类在内存中的Class实例对象。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader采用双亲委托有两个好处避免类的重复加载和保证类的安全性。由类加载的顺序可以看出父加载器加载过的类在子加载器中不会被重复加载同时也保证了安全性一些非系统的class是不可靠的若定义一个恶意的java.io.File类覆盖JDK自带的类会带来不安全性。而使用双亲委托机制的话该File类永远不会被调用因为委托BootStrapClassLoader加载后会加载JDK中的File类而不会加载自定义的这个。
</p>
<p>Redkale 双亲委托</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ConvertFactory、ResourceFactory、WatchFactory三者的双亲委托模型设计完全一样。下面以ConvertFactory为例说明ConvertFactory的搜索顺序与ClassLoader相反ClassLoader为了避免类的重复而先加载父加载器后加载子加载器ConvertFactory为了优先加载自定义的Encoder和Decoder先搜索自身的ConvertFactory找不到再从父ConvertFactory中搜索。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">findEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">rs</span> <span class="o">=</span> <span class="o">(</span><span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;)</span> <span class="n">encoders</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">rs</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">parent</span><span class="o">.</span><span class="na">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当搜索不到Encoder、Decoder时自身的ConvertFactory会自动创建一个ObjectEncoder、ObjectDecoder。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="o">&lt;</span><span class="n">E</span><span class="o">&gt;</span> <span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="nf">loadEncoder</span><span class="o">(</span><span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Encodeable</span><span class="o">&lt;</span><span class="n">W</span><span class="o">,</span> <span class="n">E</span><span class="o">&gt;</span> <span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">GenericArrayType</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="nf">ArrayEncoder</span><span class="o">(</span><span class="k">this</span><span class="o">,</span> <span class="n">type</span><span class="o">);</span>
<span class="n">Class</span> <span class="n">clazz</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">ParameterizedType</span><span class="o">)</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">ParameterizedType</span> <span class="n">pts</span> <span class="o">=</span> <span class="o">(</span><span class="n">ParameterizedType</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="o">(</span><span class="n">pts</span><span class="o">).</span><span class="na">getRawType</span><span class="o">();</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">TypeVariable</span><span class="o">)</span> <span class="o">{</span>
<span class="n">TypeVariable</span> <span class="n">tv</span> <span class="o">=</span> <span class="o">(</span><span class="n">TypeVariable</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="n">Type</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">().</span><span class="na">length</span> <span class="o">==</span> <span class="mi">1</span><span class="o">)</span> <span class="o">{</span>
<span class="n">t</span> <span class="o">=</span> <span class="n">tv</span><span class="o">.</span><span class="na">getBounds</span><span class="o">()[</span><span class="mi">0</span><span class="o">];</span>
<span class="o">}</span>
<span class="k">if</span> <span class="o">(!(</span><span class="n">t</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">))</span> <span class="n">t</span> <span class="o">=</span> <span class="n">Object</span><span class="o">.</span><span class="na">class</span><span class="o">;</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">t</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="nf">if</span> <span class="o">(</span><span class="n">type</span> <span class="k">instanceof</span> <span class="n">Class</span><span class="o">)</span> <span class="o">{</span>
<span class="n">clazz</span> <span class="o">=</span> <span class="o">(</span><span class="n">Class</span><span class="o">)</span> <span class="n">type</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="k">throw</span> <span class="k">new</span> <span class="nf">ConvertException</span><span class="o">(</span><span class="s">&quot;not support the type (&quot;</span> <span class="o">+</span> <span class="n">type</span> <span class="o">+</span> <span class="s">&quot;)&quot;</span><span class="o">);</span>
<span class="o">}</span>
<span class="n">encoder</span> <span class="o">=</span> <span class="n">findEncoder</span><span class="o">(</span><span class="n">clazz</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">encoder</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">encoder</span><span class="o">;</span>
<span class="k">return</span> <span class="nf">createEncoder</span><span class="o">(</span><span class="n">type</span><span class="o">,</span> <span class="n">clazz</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;大部分情况下Convert的处理对象会根据JavaBean类自定生成而有些场景需要覆盖处理类这样需要子ConvertFactory<a href="convert.html#convert_base" target="_blank">Convert基本用法</a> 例子中使用JsonFactory.root().createChild()重定义。且与JsonFactory.root()中的定义可以并存,也不会产出冲突。
</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale可以启动多个协议Server服务(配置文件中含多个server节点)为避免冲突每个非SNCP的Server的ResourceFactory也是独立的。
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nf">NodeServer</span><span class="o">(</span><span class="n">Application</span> <span class="n">application</span><span class="o">,</span> <span class="n">Server</span> <span class="n">server</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">application</span> <span class="o">=</span> <span class="n">application</span><span class="o">;</span>
<b><span class="k">this</span><span class="o">.</span><span class="na">resourceFactory</span> <span class="o">=</span> <span class="n">application</span><span class="o">.</span><span class="na">getResourceFactory</span><span class="o">().</span><span class="na">createChild</span><span class="o">();</span></b>
<span class="k">this</span><span class="o">.</span><span class="na">server</span> <span class="o">=</span> <span class="n">server</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;双亲委托模型既可让同级子Factory保持独立也可重用父Factory内的配置因此在Redkale这种支持多Server、多种配置的场景下很是适合。
</p>
<br/>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;转载请注明出处:<a href="https://redkale.org/article_parents.html" target="_blank">https://redkale.org/article_parents.html</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 282 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 197 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,101 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="redkale_intro" class="anchor" href="#" aria-hidden="true"></a>Redkale 介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale(中文名: 红菜苔,湖北特产蔬菜)是基于Java 8全新的微服务开源框架 包含HTTP、WebSocket、TCP/UDP、数据序列化、数据缓存、依赖注入等功能。
本框架致力于简化集中式和微服务架构的开发,在增强开发敏捷性的同时保持高性能。<br/>
Redkale 有如下主要特点: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、大量使用Java 8新特性接口默认值、Stream、Lambda、JDk8内置的ASM等 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、提供HTTP服务同时内置JSON功能与限时缓存功能 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、TCP层完全使用NIO.2并统一TCP与UDP的接口 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4、提供分布式与集中式部署的无缝切换 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5、提供类似JPA功能包含数据缓存自动同步、分表分库与简洁的数据层操作接口 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6、支持依赖注入的资源的动态修改 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7、Servlet、Service、Source组件均支持异步接口 <br/>
</p>
<h3><a id="redkale_think" class="anchor" href="#" aria-hidden="true"></a>设计理念</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;作为一个全新的微服务框架Redkale在接口定义上使用了Java 8大量的新语法接口有默认实现、接口带静态方法、重复注解等特性同时在设计上与主流框架有很大不同。Redkale是按组件形式设计的而非以容器为主几乎每个子包都是能提供独立功能的组件。如Tomcat是按容器设计的所有web资源/配置由Tomcat控制开发者很能难控制到Tomcat内部而Redkale的HTTP服务只是个组件开发者既可以自己启动和配置HttpServer也可以把Redkale当成容器通过Redkale进程来初始化服务。Spring的Ioc容器也是如此Redkale提供的依赖注入仅通过ResouceFactory一个类来控制非常轻量并且可动态更改已注入的资源。Spring提倡控制反转思想而自身的容器却让开发者很难控制。Redkale是一个既能以组件形式也能以容器形式存在的框架。从整体上看Redkale的架构分两层接口和默认实现。开发者若想替换掉Redkale内置的HTTP服务而使用符合JavaEE规范的HttpServlet, 可以采用自定义协议基于JSR 340(Servlet 3.1)来实现自己的HTTP服务若想使用Hibernate作为数据库操作可以写一个自己的DataSource实现类JSON的序列化和反序列化也可以使用第三方的实现Memcached或Redis也可以作为另一个CacheSource的实现替换Redkale的默认实现。这其实包含了控制反转的思想让框架里的各个组件均可让开发者控制。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与主流框架比功能上Redkale显得很简单这体现了Redkale的简易性而并非是不足从一个良好的设计习惯或架构上来看有些常用功能是不需要提供的如Redkale的HTTP服务不支持HTTPS和JSPHTTPS比HTTP多了一层加密解密这种密集型的计算不是Java的专长通常提供HTTP服务的架构不会将Java动态服务器放在最前端而是在前方会放nginx或apache除了负载均衡还能静动分离因此HTTPS的加解密应交给nginx这样的高性能服务器处理。Redkale再提供HTTPS服务就显得鸡肋。JSP其实算是一个落后的技术现在是一个多样化终端的时代终端不只局限于桌面程序和PC浏览器还有原生App、混合式App、微信端、移动H5、提供第三方接口等各种形式的终端这些都不是JSP能方便兼顾的而HTTP+JSON作为通用性接口可以避免重复开发模版引擎的功能加上各种强大的JS框架足以取代JSP。Redkale在功能上做了筛选不会为了迎合主流而提供而是以良好的设计思想为指导。这是Redkale的主导思维。</p>
<h3><a class="anchor" href="convert.html" target="_blank" aria-hidden="true">亮点一. 序列化与反序列化</a></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert包是Redkale内一个独立的组件 用于数据的序列化与反序列化。包分三块基本包、JSON包、BSON(Binary Stream Object Notation)包。基本包可以用于扩展其他序列化格式(如: XML)其JSON性能是其他任何JSON框架不能媲美的对于非常规的POJO类也提供了方便的自定义接口。BSON用于数据的二进制序列化与反序列化支持很复杂的泛型数据是SNCP协议的基础。</p>
<h3><a class="anchor" href="source.html#source_datasource" target="_blank" aria-hidden="true">亮点二. DataSource</a></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale提供DataSource类对数据层进行操作其功能类似JPA。最大程度的简化数据层的操作免去SQL/JPQL语句的编写。同时提供过滤查询与JavaBean的结合、读写分离、数据库热切换、本地/远程部署、数据分表分库、进程间缓存自动同步等功能。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CacheSource是缓存的统一接口像JDBC接口定义不管是内存模式还是Memcached、Redis或其他缓存系统 只要提供对应的实现就可使用,每个接口都提供同步和异步两种方式。</p>
<h3><a class="anchor" href="net.html#net_http" target="_blank" aria-hidden="true">亮点三. HTTP协议</a></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HTTP组件是基于异步NIO.2实现的HttpRequest的输入与HttpResponse的输出均是异步操作HttpRequest内置JSON参数的获取和文件上传功能HttpResponse提供数据对象和文件的数据同时集成了REST 因此并不遵循JSR 340规范(Servlet 3.1)且也没有实现JSP规范。 HTTP Server只提供四个对象HttpContext、HttpRequest、HttpResponse、HttpServlet。 传统Session则由数据层实现。Redkale提倡HTTP+JSON接口(网站、PC客户端、APP移动端、第三方接口均可统一接口) 故内置了JSON序列化与反序列化接口同时内置HTTP缓存机制。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale 的<a href="net.html#net_ws" target="_blank">WebSocket服务</a>接口不同于JSR 340(Servlet 3.1) 除了提供基本的WebSocket功能 还提供分布式与集中式部署, 当部署多个WebSocket进程时通过配置文件可以实现WebSocket之间连接信息的数据同步。</p>
<h3><a class="anchor" href="net.html#net_sncp" target="_blank" aria-hidden="true">亮点四. SNCP协议</a></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SNCP(Service Node Communicate Protocol)是Redkale独有的RPC协议 主要用于进程间的数据传输支持泛型和子类的数据转换。开发人员通过配置文件可以轻易的将Service由<a href="service.html#service_local" target="_blank">本地模式</a>变成<a href="service.html#service_remote" target="_blank">远程模式</a><a href="service.html#service_remote" target="_blank">远程模式Service</a>使用SNCP协议与其他进程的Service通信。开发人员无需对远程通信接口使用类似Mina的第三方包进行开发。SNCP是Redkale的核心功能其微服务架构都是基于<a href="service.html#service_local" target="_blank">本地模式Service</a><a href="service.html#service_remote" target="_blank">远程模式Service</a></p>
<h3><a class="anchor" href="net.html#net_sncp" target="_blank" aria-hidden="true">亮点五. WATCH协议</a></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WATCH协议其实就是HTTP协议主要用于进程的微服务和监控管理。接口以HTTP形式提供 Redkale自带部分常规的Watch功能如动态更新DataSource配置动态加载Service、Servlet、Filter查看Server基本信息等。开发者也可自定义WatchService进行监控或管理操作。</p>
<h3><a class="anchor" href="net.html#net_sncp" target="_blank" aria-hidden="true">亮点六. 异步接口</a></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Net、Service、DataSource、CacheSource都支持异步接口<a href="service.html#service_local" target="_blank">本地模式</a><a href="service.html#service_remote" target="_blank">远程模式</a>的Service均支持。</p>
<h3><a id="redkale_code" class="anchor" href="#" aria-hidden="true"></a>Java 源码</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://gitee.com/redkale" target="_blank" ><b>&nbsp;&nbsp;&nbsp;码云 源码 &nbsp;&nbsp; https://gitee.com/redkale</b></a><br/><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/redkale" target="_blank" >Github 源码 &nbsp;&nbsp; https://github.com/redkale</a><br/>
&nbsp;&nbsp;<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="javadoc/index.html" target="_blank" >在线 Javadoc API</a></p>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale官网:&nbsp;&nbsp;<a href="https://redkale.org" target="_blank"><b>https://redkale.org</b></a></p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 185 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

960
net.html
View File

@@ -1,960 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="net_intro" class="anchor" href="#" aria-hidden="true"></a>Net 组件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Net 组件是基于AIO(NIO.2)的一套TCP/UDP的网络框架且只提供异步接口。org.redkale.net 是所有网络协议服务的基础包。Redkale内置HTTP和远程模式Service依赖的SNCP(Service Node Communicate Protocol)协议的实现包。Redkale启动的<b>&lt;server&gt;</b>节点服务都是基于Net组件实现的协议。下面详细介绍 <a href="#net_http">HTTP服务</a><a href="#net_sncp">SNCP协议</a></p>
<h3><a id="net_http" class="anchor" href="#" aria-hidden="true"></a>HTTP 服务</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale自实现的HTTP服务接口并不遵循Java EE规范JSR 340(Servlet 3.1)Redkale提倡的是HTTP+JSON的服务接口方式因此没有实现JSP规范HTTP+JSON服务接口几乎适合所有类型的客户端(PC应用程序、PC Web、微信H5、移动APP、移动Web)开发。其与JSR 340(Servlet 3.1)的主要区别如下:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、内置参数的JSON反序列化和响应结果的序列化接口。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、对数值型的参数和header值提供简易接口。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、不支持JSP提倡的是HTTP+JSON接口方式。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4、无HttpSession对象session可通过配置CacheSource实现。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5、内置文件上传接口且可自实现断点续传。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6、对响应结果内容可以进行短期缓存从而减少数据源操作的压力。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;7、内置WebSocket的集群与组功能且提供伪WebSocket连接功能。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;8、HttpResponse只能异步输出。<br/>
</p>
<p id="baseservlet">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编写Redkale的HttpServlet与 JSR 340中的javax.servlet.http.HttpServlet 基本相同,只需继承 org.redkale.net.http.HttpServlet, 比较好的习惯是一个项目先定义一个项目级的BaseServlet类。 <br/> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个典型的BaseSerlvet实现:
</p>
<div class="highlight"><pre><span></span><span class="nd">@HttpUserType</span><span class="o">(</span><span class="n">UserInfo</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">BaseSerlvet</span> <span class="kd">extends</span> <span class="n">HttpServlet</span> <span class="o">{</span>
<span class="kd">protected</span> <span class="kd">final</span> <span class="n">Logger</span> <span class="n">logger</span> <span class="o">=</span> <span class="n">Logger</span><span class="o">.</span><span class="na">getLogger</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">getClass</span><span class="o">().</span><span class="na">getSimpleName</span><span class="o">());</span>
<span class="kd">protected</span> <span class="kd">final</span> <span class="kt">boolean</span> <span class="n">fine</span> <span class="o">=</span> <span class="n">logger</span><span class="o">.</span><span class="na">isLoggable</span><span class="o">(</span><span class="n">Level</span><span class="o">.</span><span class="na">FINE</span><span class="o">);</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"APP_TIME"</span><span class="o">)</span> <span class="c1">//[Redkale内置资源] 进程的启动时间</span>
<span class="kd">protected</span> <span class="kt">long</span> <span class="n">serverCreateTime</span><span class="o">;</span>
<span class="nd">@Resource</span> <span class="c1">//[Redkale内置资源]</span>
<span class="kd">protected</span> <span class="n">JsonConvert</span> <span class="n">jsonConvert</span><span class="o">;</span>
<span class="nd">@Resource</span> <span class="c1">//[Redkale内置资源]</span>
<span class="kd">protected</span> <span class="n">JsonFactory</span> <span class="n">jsonFactory</span><span class="o">;</span>
<span class="c1">//[Redkale内置资源], 当前进程的根目录,字段类型可以是 String、java.io.File、java.nio.file.Path</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"APP_HOME"</span><span class="o">)</span>
<span class="kd">protected</span> <span class="n">File</span> <span class="n">home</span><span class="o">;</span>
<span class="c1">//[Redkale内置资源], 当前Http Server的web页面的根目录字段类型可以是 String、java.io.File、java.nio.file.Path</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"SERVER_ROOT"</span><span class="o">)</span>
<span class="kd">protected</span> <span class="n">File</span> <span class="n">webroot</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">service</span><span class="o">;</span>
<span class="c1">//在调用authenticate之前调用, 必须在此处设置currentUser用户信息</span>
<span class="c1">//该方法可以用于判断请求源是否合法或加入一些全局的拦截操作</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">preExecute</span><span class="o">(</span><span class="kd">final</span> <span class="n">HttpRequest</span> <span class="n">request</span><span class="o">,</span> <span class="kd">final</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(!</span><span class="n">request</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="s">"User-Agent"</span><span class="o">,</span> <span class="s">""</span><span class="o">).</span><span class="na">contains</span><span class="o">(</span><span class="s">"Redkale-Agent"</span><span class="o">))</span> <span class="o">{</span> <span class="c1">//只用移动APP的接口可以判断User-Agent是否正确</span>
<span class="n">response</span><span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">"retcode"</span><span class="o">,</span> <span class="s">"10001"</span><span class="o">);</span>
<span class="n">response</span><span class="o">.</span><span class="na">addHeader</span><span class="o">(</span><span class="s">"retmessage"</span><span class="o">,</span> <span class="s">"User-Agent error"</span><span class="o">);</span>
<span class="n">response</span><span class="o">.</span><span class="na">finish</span><span class="o">(</span><span class="mi">201</span><span class="o">,</span> <span class="s">"{'success':false, 'message':'User-Agent error, must be Redkale-Agent'}"</span><span class="o">);</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//可以加上一些统计操作</span>
<span class="k">if</span> <span class="o">(</span><span class="n">fine</span><span class="o">)</span> <span class="n">response</span><span class="o">.</span><span class="na">recycleListener</span><span class="o">((</span><span class="n">req</span><span class="o">,</span> <span class="n">resp</span><span class="o">)</span> <span class="o">-&gt;</span> <span class="o">{</span> <span class="c1">//记录处理时间太长的请求操作</span>
<span class="kt">long</span> <span class="n">e</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">()</span> <span class="o">-</span> <span class="n">request</span><span class="o">.</span><span class="na">getCreatetime</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">e</span> <span class="o">&gt;</span> <span class="mi">500</span><span class="o">)</span> <span class="n">logger</span><span class="o">.</span><span class="na">fine</span><span class="o">(</span><span class="s">"耗时居然用了 "</span> <span class="o">+</span> <span class="n">e</span> <span class="o">+</span> <span class="s">" 毫秒. 请求为: "</span> <span class="o">+</span> <span class="n">req</span><span class="o">);</span>
<span class="o">});</span>
<span class="kd">final</span> <span class="n">String</span> <span class="n">sessionid</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">sessionid</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="n">request</span><span class="o">.</span><span class="na">setCurrentUser</span><span class="o">(</span><span class="n">userService</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">sessionid</span><span class="o">));</span>
<span class="n">response</span><span class="o">.</span><span class="na">nextEvent</span><span class="o">();</span>
<span class="o">}</span>
<span class="c1">//一般用于判断用户的登录态, 返回false表示鉴权失败</span>
<span class="c1">//moduleid值来自 @WebServlet.moduleid()用于定义模块ID; actionid值自来@HttpMapping.actionid()用于定义操作ID; 需要系统化的鉴权需要定义这两个值</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">authenticate</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">request</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">info</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="na">currentUser</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">info</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">response</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">retResult</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">RET_USER_UNLOGIN</span><span class="o">));</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(!</span><span class="n">info</span><span class="o">.</span><span class="na">checkAuth</span><span class="o">(</span><span class="n">request</span><span class="o">.</span><span class="na">getModuleid</span><span class="o">(),</span> <span class="n">request</span><span class="o">.</span><span class="na">getActionid</span><span class="o">()))</span> <span class="o">{</span>
<span class="n">response</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">retResult</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">RET_USER_AUTH_ILLEGAL</span><span class="o">));</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">response</span><span class="o">.</span><span class="na">nextEvent</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;继承HttpServlet的子类可以使用其自带的鉴权、请求分支、缓存等功能 一个典型的操作<span id="userservlet">用户HttpServlet</span>: </p>
<div class="highlight"><pre><span></span><span class="nd">@WebServlet</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="o">{</span><span class="s">"/user/*"</span><span class="o">},</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户模块服务"</span><span class="o">)</span> <span class="c1">//拦截所有 /user/ 开头的请求</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserServlet</span> <span class="kd">extends</span> <span class="n">BaseSerlvet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">service</span><span class="o">;</span>
<span class="c1">//登录操作 </span>
<span class="c1">//因为HttpMapping的判断规则用的是String.startsWith所以HttpMapping.url不能用正则表达式只能是getRequestURI的前缀</span>
<span class="c1">//且同一个HttpServlet类内的所有HttpMapping不能存在包含关系, 如 /user/myinfo 和 /user/myinforecord 不能存在同一HttpServlet中。</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">"/user/login"</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户登录"</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"bean"</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">LoginBean</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"登录参数对象"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">login</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">LoginBean</span> <span class="n">bean</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getJsonParameter</span><span class="o">(</span><span class="n">LoginBean</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="s">"bean"</span><span class="o">);</span> <span class="c1">//获取参数</span>
<span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">login</span><span class="o">(</span><span class="n">bean</span><span class="o">);</span> <span class="c1">//登录操作, service内部判断bean的合法性</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">result</span><span class="o">);</span> <span class="c1">//输出结果</span>
<span class="o">}</span>
<span class="c1">//获取当前用户信息</span>
<span class="c1">//未登录的请求会被BaseSerlvet.authenticate方法拦截因此能进入该方法说明用户态存在</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">"/user/myinfo"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"获取当前用户信息"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">myinfo</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span>
<span class="c1">//或者使用 user = req.getAttribute("_current_userinfo"); 因为BaseSerlvet.authenticate方法已经将UserInfo注入到_current_userinfo属性中</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">user</span><span class="o">);</span> <span class="c1">//输出用户信息</span>
<span class="o">}</span>
<span class="c1">//获取指定用户ID的用户信息, 请求如: /user/username/43565443</span>
<span class="c1">// 翻页查询想缓存就需要将翻页信息带进url: /user/query/page:2/size:50 。</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">"/user/userinfo/"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"获取指定用户ID的用户信息"</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">"#"</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="kt">int</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"用户ID"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">userinfo</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">findUserInfo</span><span class="o">(</span><span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRequstURILastPath</span><span class="o">()));</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">user</span><span class="o">);</span> <span class="c1">//输出用户信息</span>
<span class="o">}</span>
<span class="c1">//更新个人头像</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">"/user/updateface"</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"更新用户头像"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">updateface</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span>
<span class="k">for</span> <span class="o">(</span><span class="n">MultiPart</span> <span class="n">part</span> <span class="o">:</span> <span class="n">req</span><span class="o">.</span><span class="na">multiParts</span><span class="o">())</span> <span class="o">{</span> <span class="c1">//遍历上传文件列表 </span>
<span class="kt">byte</span><span class="o">[]</span> <span class="n">byts</span> <span class="o">=</span> <span class="n">part</span><span class="o">.</span><span class="na">getContentBytes</span><span class="o">(</span><span class="mi">5</span> <span class="o">*</span> <span class="mi">1024</span> <span class="o">*</span> <span class="mi">1024L</span><span class="o">);</span> <span class="c1">//图片大小不能超过5M超过5M返回null</span>
<span class="k">if</span> <span class="o">(</span><span class="n">byts</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">102</span><span class="o">,</span> <span class="s">"上传的文件过大"</span><span class="o">));</span>
<span class="o">}</span> <span class="k">else</span> <span class="o">{</span>
<span class="n">BufferedImage</span> <span class="n">img</span> <span class="o">=</span> <span class="n">ImageIO</span><span class="o">.</span><span class="na">read</span><span class="o">(</span><span class="k">new</span> <span class="n">ByteArrayInputStream</span><span class="o">(</span><span class="n">byts</span><span class="o">));</span>
<span class="c1">//... 此处处理并存储头像图片</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetResult</span><span class="o">.</span><span class="na">SUCCESS</span><span class="o">);</span> <span class="c1">//输出成功信息</span>
<span class="o">}</span>
<span class="k">return</span><span class="o">;</span> <span class="c1">//头像图片仅会传一个, 只需要读取一个即可返回</span>
<span class="o">}</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="k">new</span> <span class="n">RetResult</span><span class="o">(</span><span class="mi">103</span><span class="o">,</span> <span class="s">"没有上传图片"</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上,所有/user/前缀的请求都会进入UserServlet若没匹配的则返回505错误为了方便以后编写前方静动分离服务器转发规则比较好的习惯是将项目中所有动态Servlet加一个固定前缀<a href="redkale.html#redkale_confxml" target="_blank">application.xml</a> 里设置path即可。</p>
<div class="highlight"><pre><span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;HTTP&quot;</span> <span class="na">port=</span><span class="s">&quot;6060&quot;</span> <span class="na">root=</span><span class="s">&quot;root&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;servlets</span> <b><span class="na">path=</span><span class="s">&quot;/pipes&quot;</span></b> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/server&gt;</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上, 配置了/pipes 前缀后客户端发送Servlet请求需带上前缀请求当前用户信息的url就变成/pipes/user/myinfo 。</p>
<br/>
<p id="net_apidoc">&nbsp;&nbsp;<b> API Doc</b> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在小型互联网公司里基本是追求敏捷开发很少先花时间设计接口文档再进行开发通常都是直接进行数据库设计和开发开发完后需要开发人员需要编写接口文档提供给前端人员开发。为了减少文档的编写工作量和强制开发人员对接口进行注释Redkale提供了apidoc命令apidoc遍历当前进程中所有标记@WebServlet的可用HttpServlet根据Servlet中@HttpMapping、@HttpParam生成json对象并输出文件。在<b>系统运行</b>时执行apidoc命令会在进程根目录下生成apidoc.json、apidoc.html文件。apidoc.html的模板可以定制 只需在conf/目录下存放一个 <b>apidoc-template.html</b> 文件,且文件中必须包含关键字 <b>${content}</b> 即可实现接口文档的自定义。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了能正确显示接口文档开发人员需要在编写HttpServlet时在每个@HttpMapping方法上添加comment属性和@HttpParam注解, 一个方法上可以注解多个@HttpParam, 如上面的 <a href="#userservlet">UserServlet</a> 。RestServlet是由RestService自动生成@HttpMapping、@HttpParam在REST组件中存在对应的注解@RestMapping、@RestParam因此在编写RestService时需要加上@RestMapping、@RestParam且加上comment属性。如范例: <a href="service.html#helloservice" target="_blank">HelloService</a><br/>
</p>
<p id="net_ws">&nbsp;&nbsp;<b> WebSokcet 服务</b> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;WebSokcet协议遵循<a href="http://tools.ietf.org/html/rfc645" target="_blank">IETF RFC 6455</a>其接口并不符合Java EE中的WebSocket的接口规范。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;一个WebSocket连接对应一个WebSocket实体即一个WebSocket会绑定一个TCP连接。且有两种模式:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;协议上符合HTML5规范, 其流程顺序如下:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.1 onOpen &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断登录态。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.2 createUserid &nbsp;&nbsp;&nbsp; 若返回null视为WebSocket的连接不合法强制关闭WebSocket连接通常用于判断用户权限是否符合。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.3 onConnected &nbsp;&nbsp;&nbsp;&nbsp; WebSocket成功连接后在准备接收数据前回调此方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.4 onMessage/onFragment+ &nbsp;&nbsp; WebSocket接收到消息后回调此消息类方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1.5 onClose &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; WebSocket被关闭后回调此方法。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;此模式下 以上方法都应该被重载。<br/>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;实现一个WebSocket服务需要继承 org.redkale.net.http.WebSocketServlet以下是一个简单的聊天范例</p>
<div class="highlight"><pre><span></span><span class="nd">@WebServlet</span><span class="o">(</span><span class="s">"/ws/chat"</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">ChatWebSocketServlet</span> <span class="kd">extends</span> <span class="n">WebSocketServlet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">userService</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">init</span><span class="o">(</span><span class="n">HttpContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">AnyValue</span> <span class="n">conf</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"本实例的WebSocketNode: "</span> <span class="o">+</span> <span class="kd">super</span><span class="o">.</span><span class="na">node</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">destroy</span><span class="o">(</span><span class="n">HttpContext</span> <span class="n">context</span><span class="o">,</span> <span class="n">AnyValue</span> <span class="n">conf</span><span class="o">)</span> <span class="o">{</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="s">"关闭了ChatWebSocketServlet"</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">protected</span> <span class="n">WebSocket</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">ChatMessage</span><span class="o">&gt;</span> <span class="nf">createWebSocket</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">WebSocket</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">ChatMessage</span><span class="o">&gt;()</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">UserInfo</span> <span class="n">user</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="n">ChatMessage</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//text 接收的格式:{"receiveid":2000001,"content":"Hi Redkale!"}</span>
<span class="n">message</span><span class="o">.</span><span class="na">sendid</span> <span class="o">=</span> <span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">();</span> <span class="c1">//将当前用户设为消息的发送方</span>
<span class="n">message</span><span class="o">.</span><span class="na">sendtime</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span> <span class="c1">//设置消息发送时间</span>
<span class="c1">//给接收方发送消息, 即使接收方在其他WebSocket进程节点上有链接Redkale也会自动发送到其他链接进程节点上。</span>
<span class="kd">super</span><span class="o">.</span><span class="na">sendMessage</span><span class="o">(</span><span class="n">message</span><span class="o">,</span> <span class="n">message</span><span class="o">.</span><span class="na">receiveid</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">protected</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">createUserid</span><span class="o">()</span> <span class="o">{</span> <span class="c1">//创建用户ID</span>
<span class="k">this</span><span class="o">.</span><span class="na">user</span> <span class="o">=</span> <span class="n">userService</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="kd">super</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">()));</span>
<span class="k">return</span> <span class="n">CompletableFuture</span><span class="o">.</span><span class="na">completedFuture</span><span class="o">(</span><span class="k">this</span><span class="o">.</span><span class="na">user</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="k">this</span><span class="o">.</span><span class="na">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="nf">onOpen</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">request</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">//以request中的sessionid字符串作为WebSocket的sessionid</span>
<span class="k">return</span> <span class="n">CompletableFuture</span><span class="o">.</span><span class="na">completedFuture</span><span class="o">(</span><span class="n">request</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">};</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">ChatMessage</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">sendid</span><span class="o">;</span> <span class="c1">//发送方用户ID</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="n">receiveid</span><span class="o">;</span> <span class="c1">//接收方用户ID </span>
<span class="kd">public</span> <span class="n">String</span> <span class="n">content</span><span class="o">;</span> <span class="c1">//文本消息内容</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="n">sendtime</span><span class="o">;</span> <span class="c1">//消息发送时间</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p id="net_httprequest">&nbsp;&nbsp;<b>. HttpRequest 对象</b> </p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HttpRequest</span> <span class="o">{</span>
<span class="c1">//获取客户端地址IP</span>
<span class="kd">public</span> <span class="n">SocketAddress</span> <span class="nf">getRemoteAddress</span><span class="o">();</span>
<span class="c1">//获取客户端地址IP, 与getRemoteAddres() 的区别在于:</span>
<span class="c1">//本方法优先取header中指定为RemoteAddress名的值没有则返回getRemoteAddres()的getHostAddress()。</span>
<span class="c1">//本方法适用于服务前端有如nginx的代理服务器进行中转通过getRemoteAddres()是获取不到客户端的真实IP。</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRemoteAddr</span><span class="o">();</span>
<span class="c1">//获取请求内容指定的编码字符串</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getBody</span><span class="o">(</span><span class="n">Charset</span> <span class="n">charset</span><span class="o">);</span>
<span class="c1">//获取请求内容的UTF-8编码字符串</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getBodyUTF8</span><span class="o">();</span>
<span class="c1">//获取请求内容的byte[]</span>
<span class="kd">public</span> <span class="kt">byte</span><span class="o">[]</span> <span class="nf">getBody</span><span class="o">();</span>
<span class="c1">//获取请求内容的JavaBean对象</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getBodyJson</span><span class="o">(</span><span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">reflect</span><span class="o">.</span><span class="na">Type</span> <span class="n">type</span><span class="o">);</span>
<span class="c1">//获取请求内容的JavaBean对象</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getBodyJson</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">java</span><span class="o">.</span><span class="na">lang</span><span class="o">.</span><span class="na">reflect</span><span class="o">.</span><span class="na">Type</span> <span class="n">type</span><span class="o">);</span>
<span class="c1">//获取文件上传对象</span>
<span class="kd">public</span> <span class="n">MultiContext</span> <span class="nf">getMultiContext</span><span class="o">();</span>
<span class="c1">//获取文件上传信息列表 等价于 getMultiContext().parts();</span>
<span class="kd">public</span> <span class="n">Iterable</span><span class="o">&lt;</span><span class="n">MultiPart</span><span class="o">&gt;</span> <span class="nf">multiParts</span><span class="o">()</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">;</span>
<span class="c1">//设置当前用户信息, 通常在HttpServlet.preExecute方法里设置currentUser</span>
<span class="c1">//数据类型由@HttpUserType指定</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">HttpRequest</span> <span class="nf">setCurrentUser</span><span class="o">(</span><span class="n">T</span> <span class="n">user</span><span class="o">);</span>
<span class="c1">//获取当前用户信息 数据类型由@HttpUserType指定</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">currentUser</span><span class="o">();</span>
<span class="c1">//获取模块ID来自@HttpServlet.moduleid()</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getModuleid</span><span class="o">();</span>
<span class="c1">//获取操作ID来自@HttpMapping.actionid()</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getActionid</span><span class="o">();</span>
<span class="c1">//获取sessionid</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getSessionid</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">autoCreate</span><span class="o">);</span>
<span class="c1">//更新sessionid</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">changeSessionid</span><span class="o">();</span>
<span class="c1">//指定值更新sessionid</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">changeSessionid</span><span class="o">(</span><span class="n">String</span> <span class="n">newsessionid</span><span class="o">);</span>
<span class="c1">//使sessionid失效</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">invalidateSession</span><span class="o">();</span>
<span class="c1">//获取所有Cookie对象</span>
<span class="kd">public</span> <span class="n">java</span><span class="o">.</span><span class="na">net</span><span class="o">.</span><span class="na">HttpCookie</span><span class="o">[]</span> <span class="nf">getCookies</span><span class="o">();</span>
<span class="c1">//获取Cookie值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getCookie</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取Cookie值 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getCookie</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取协议名 http、https、ws、wss等</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getProtocol</span><span class="o">();</span>
<span class="c1">//获取请求方法 GET、POST等</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getMethod</span><span class="o">();</span>
<span class="c1">//获取Content-Type的header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getContentType</span><span class="o">();</span>
<span class="c1">//获取请求内容的长度, 为-1表示内容长度不确定</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getContentLength</span><span class="o">();</span>
<span class="c1">//获取Connection的Header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getConnection</span><span class="o">();</span>
<span class="c1">//获取Host的Header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHost</span><span class="o">();</span>
<span class="c1">//获取请求的URL</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequestURI</span><span class="o">();</span>
<span class="c1">//截取getRequestURI最后的一个/后面的部分</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequstURILastPath</span><span class="o">();</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的short值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">short</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的short值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: short type = request.getRequstURILastPath((short)0); //type = 2</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的int值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: int type = request.getRequstURILastPath(0); //type = 2</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的int值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: int type = request.getRequstURILastPath(0); //type = 2</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的float值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: float type = request.getRequstURILastPath(0.f); //type = 2.f</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">float</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的long值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">long</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的long值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: long type = request.getRequstURILastPath(0L); //type = 2</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL最后的一个/后面的部分的double值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/2 &lt;br&gt;</span>
<span class="c1">// 获取type参数: double type = request.getRequstURILastPath(0.0); //type = 2.0</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getRequstURILastPath</span><span class="o">(</span><span class="kt">double</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">//从prefix之后截取getRequestURI再对"/"进行分隔</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getRequstURIPaths</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的值</span>
<span class="c1">// 例如请求URL /pipes/record/query/name:hello</span>
<span class="c1">// 获取name参数: String name = request.getRequstURIPath("name:", "none");</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的short值</span>
<span class="c1">// 例如请求URL /pipes/record/query/type:10</span>
<span class="c1">// 获取type参数: short type = request.getRequstURIPath("type:", (short)0);</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的short值</span>
<span class="c1">// 例如请求URL /pipes/record/query/type:a</span>
<span class="c1">// 获取type参数: short type = request.getRequstURIPath(16, "type:", (short)0); type = 10</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的int值</span>
<span class="c1">// 例如请求URL /pipes/record/query/offset:2/limit:50</span>
<span class="c1">// 获取offset参数: int offset = request.getRequstURIPath("offset:", 1);</span>
<span class="c1">// 获取limit参数: int limit = request.getRequstURIPath("limit:", 20);</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的int值</span>
<span class="c1">// 例如请求URL /pipes/record/query/offset:2/limit:10</span>
<span class="c1">// 获取offset参数: int offset = request.getRequstURIPath("offset:", 1);</span>
<span class="c1">// 获取limit参数: int limit = request.getRequstURIPath(16, "limit:", 20); // limit = 16</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的float值 </span>
<span class="c1">// 例如请求URL /pipes/record/query/point:40.0 </span>
<span class="c1">// 获取time参数: float point = request.getRequstURIPath("point:", 0.0f);</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">float</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的long值</span>
<span class="c1">// 例如请求URL /pipes/record/query/time:1453104341363/id:40</span>
<span class="c1">// 获取time参数: long time = request.getRequstURIPath("time:", 0L);</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的long值</span>
<span class="c1">// 例如请求URL /pipes/record/query/time:1453104341363/id:40</span>
<span class="c1">// 获取time参数: long time = request.getRequstURIPath("time:", 0L);</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">// 获取请求URL分段中含prefix段的double值 &lt;br&gt;</span>
<span class="c1">// 例如请求URL /pipes/record/query/point:40.0 &lt;br&gt;</span>
<span class="c1">// 获取time参数: double point = request.getRequstURIPath("point:", 0.0);</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getRequstURIPath</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">,</span> <span class="kt">double</span> <span class="n">defvalue</span><span class="o">);</span>
<span class="c1">//获取所有的header名</span>
<span class="kd">public</span> <span class="n">AnyValue</span> <span class="nf">getHeaders</span><span class="o">();</span>
<span class="c1">//将请求Header转换成Map</span>
<span class="kd">public</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">String</span><span class="o">&gt;</span> <span class="nf">getHeadersToMap</span><span class="o">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">String</span><span class="o">&gt;</span> <span class="n">map</span><span class="o">);</span>
<span class="c1">//获取所有的header名</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getHeaderNames</span><span class="o">();</span>
<span class="c1">// 获取指定的header值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header值, 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonHeader</span><span class="o">(</span><span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header的json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonHeader</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的header的boolean值, 没有返回默认boolean值</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">getBooleanHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortHeader</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntHeader</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongHeader</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">// 获取指定的header的float值, 没有返回默认float值</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getFloatHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">float</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的header的double值, 没有返回默认double值</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getDoubleHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">double</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取请求参数总对象</span>
<span class="kd">public</span> <span class="n">AnyValue</span> <span class="nf">getParameters</span><span class="o">();</span>
<span class="c1">//将请求参数转换成Map</span>
<span class="kd">public</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">String</span><span class="o">&gt;</span> <span class="nf">getParametersToMap</span><span class="o">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">String</span><span class="o">&gt;</span> <span class="n">map</span><span class="o">);</span>
<span class="c1">//将请求参数转换成String, 字符串格式为: bean1={}&amp;amp;id=13&amp;amp;name=xxx</span>
<span class="c1">//不会返回null没有参数返回空字符串</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getParametersToString</span><span class="o">();</span>
<span class="c1">//将请求参数转换成String, 字符串格式为: prefix + bean1={}&amp;amp;id=13&amp;amp;name=xxx</span>
<span class="c1">//拼接前缀, 如果无参数,返回的字符串不会含有拼接前缀</span>
<span class="c1">//不会返回null没有参数返回空字符串</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getParametersToString</span><span class="o">(</span><span class="n">String</span> <span class="n">prefix</span><span class="o">);</span>
<span class="c1">//获取所有参数名</span>
<span class="kd">public</span> <span class="n">String</span><span class="o">[]</span> <span class="nf">getParameterNames</span><span class="o">();</span>
<span class="c1">//获取指定的参数值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数值, 没有返回默认值</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">String</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonParameter</span><span class="o">(</span><span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数json值</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getJsonParameter</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//获取指定的参数boolean值, 没有返回默认boolean值</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">getBooleanParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortParameter</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">short</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数short值, 没有返回默认short值</span>
<span class="kd">public</span> <span class="kt">short</span> <span class="nf">getShortParameter</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数int值, 没有返回默认int值</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getIntParameter</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">int</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数long值, 没有返回默认long值</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLongParameter</span><span class="o">(</span><span class="kt">int</span> <span class="n">radix</span><span class="o">,</span> <span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">long</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数float值, 没有返回默认float值</span>
<span class="kd">public</span> <span class="kt">float</span> <span class="nf">getFloatParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">float</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取指定的参数double值, 没有返回默认double值</span>
<span class="kd">public</span> <span class="kt">double</span> <span class="nf">getDoubleParameter</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">double</span> <span class="n">defaultValue</span><span class="o">);</span>
<span class="c1">//获取翻页对象 同 getFlipper("flipper", false, 0);</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">();</span>
<span class="c1">//获取翻页对象 同 getFlipper("flipper", needcreate, 0);</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">needcreate</span><span class="o">);</span>
<span class="c1">//获取翻页对象 同 getFlipper("flipper", false, maxLimit);</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">(</span><span class="kt">int</span> <span class="n">maxLimit</span><span class="o">);</span>
<span class="c1">//获取翻页对象 同 getFlipper("flipper", needcreate, maxLimit)</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">needcreate</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxLimit</span><span class="o">);</span>
<span class="c1">//获取翻页对象 http://redkale.org/pipes/records/list/offset:0/limit:20/sort:createtime%20ASC</span>
<span class="c1">//http://redkale.org/pipes/records/list?flipper={'offset':0,'limit':20, 'sort':'createtime ASC'}</span>
<span class="c1">//以上两种接口都可以获取到翻页对象</span>
<span class="kd">public</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">source</span><span class="o">.</span><span class="na">Flipper</span> <span class="nf">getFlipper</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">needcreate</span><span class="o">,</span> <span class="kt">int</span> <span class="n">maxLimit</span><span class="o">);</span>
<span class="c1">//获取HTTP上下文对象</span>
<span class="kd">public</span> <span class="n">HttpContext</span> <span class="nf">getContext</span><span class="o">();</span>
<span class="c1">//获取所有属性值, servlet执行完后会被清空</span>
<span class="kd">public</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">Object</span><span class="o">&gt;</span> <span class="nf">getAttributes</span><span class="o">();</span>
<span class="c1">//获取指定属性值, servlet执行完后会被清空</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="n">T</span> <span class="nf">getAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//删除指定属性</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">removeAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//设置属性值, servlet执行完后会被清空</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//获取request创建时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getCreatetime</span><span class="o">();</span>
<span class="o">}</span>
</pre></div>
<p id="net_httpresponse">&nbsp;&nbsp;<b>. HttpResponse 对象</b> </p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HttpResponse</span> <span class="o">{</span>
<span class="c1">//增加Cookie值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">addCookie</span><span class="o">(</span><span class="n">HttpCookie</span><span class="o">...</span> <span class="n">cookies</span><span class="o">);</span>
<span class="c1">//增加Cookie值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">addCookie</span><span class="o">(</span><span class="n">Collection</span><span class="o">&lt;</span><span class="n">HttpCookie</span><span class="o">&gt;</span> <span class="n">cookies</span><span class="o">);</span>
<span class="c1">//创建CompletionHandler实例将非字符串对象以JSON格式输出字符串以文本输出</span>
<span class="kd">public</span> <span class="n">CompletionHandler</span> <span class="nf">createAsyncHandler</span><span class="o">();</span>
<span class="c1">//传入的CompletionHandler子类必须是public且保证其子类可被继承且completed、failed可被重载且包含空参数的构造函数</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">H</span> <span class="kd">extends</span> <span class="n">CompletionHandler</span><span class="o">&gt;</span> <span class="n">H</span> <span class="nf">createAsyncHandler</span><span class="o">(</span><span class="n">Class</span><span class="o">&lt;</span><span class="n">H</span><span class="o">&gt;</span> <span class="n">handlerClass</span><span class="o">);</span>
<span class="c1">//获取ByteBuffer生成器</span>
<span class="kd">public</span> <span class="n">Supplier</span><span class="o">&lt;</span><span class="n">ByteBuffer</span><span class="o">&gt;</span> <span class="nf">getBufferSupplier</span><span class="o">();</span>
<span class="c1">//设置状态码</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setStatus</span><span class="o">(</span><span class="kt">int</span> <span class="n">status</span><span class="o">);</span>
<span class="c1">//获取状态码</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">getStatus</span><span class="o">();</span>
<span class="c1">//获取 ContentType</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getContentType</span><span class="o">();</span>
<span class="c1">//设置 ContentType</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">setContentType</span><span class="o">(</span><span class="n">String</span> <span class="n">contentType</span><span class="o">);</span>
<span class="c1">//获取内容长度</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getContentLength</span><span class="o">();</span>
<span class="c1">//设置内容长度</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">setContentLength</span><span class="o">(</span><span class="kt">long</span> <span class="n">contentLength</span><span class="o">);</span>
<span class="c1">//设置Header值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">setHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//添加Header值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">addHeader</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//添加Header值</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">addHeader</span><span class="o">(</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="o">?&gt;</span> <span class="n">map</span><span class="o">);</span>
<span class="c1">//跳过header的输出</span>
<span class="c1">//通常应用场景是调用者的输出内容里已经包含了HTTP的响应头信息因此需要调用此方法避免重复输出HTTP响应头信息。</span>
<span class="kd">public</span> <span class="n">HttpResponse</span> <span class="nf">skipHeader</span><span class="o">();</span>
<span class="c1">//异步输出指定内容</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">sendBody</span><span class="o">(</span><span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">,</span> <span class="n">A</span> <span class="n">attachment</span><span class="o">,</span> <span class="n">CompletionHandler</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">A</span><span class="o">&gt;</span> <span class="n">handler</span><span class="o">);</span>
<span class="c1">//异步输出指定内容</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">A</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">sendBody</span><span class="o">(</span><span class="n">ByteBuffer</span><span class="o">[]</span> <span class="n">buffers</span><span class="o">,</span> <span class="n">A</span> <span class="n">attachment</span><span class="o">,</span> <span class="n">CompletionHandler</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">A</span><span class="o">&gt;</span> <span class="n">handler</span><span class="o">);</span>
<span class="c1">//关闭HTTP连接如果是keep-alive则不强制关闭</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">();</span>
<span class="c1">//强制关闭HTTP连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象数组用Map的形式以JSON格式输出</span>
<span class="c1">//例如: finishMap("a",2,"b",3) 输出结果为 {"a":2,"b":3}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishMapJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span><span class="o">...</span> <span class="n">objs</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象数组用Map的形式以JSON格式输出</span>
<span class="c1">//例如: finishMap("a",2,"b",3) 输出结果为 {"a":2,"b":3}</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishMapJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span><span class="o">...</span> <span class="n">objs</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span><span class="o">...</span> <span class="n">objs</span><span class="o">);</span>
<span class="c1">//将RetResult对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">service</span><span class="o">.</span><span class="na">RetResult</span> <span class="n">ret</span><span class="o">);</span>
<span class="c1">//将RetResult对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">service</span><span class="o">.</span><span class="na">RetResult</span> <span class="n">ret</span><span class="o">);</span>
<span class="c1">//将CompletableFuture的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">CompletableFuture</span> <span class="n">future</span><span class="o">);</span>
<span class="c1">//将CompletableFuture的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">CompletableFuture</span> <span class="n">future</span><span class="o">);</span>
<span class="c1">//将CompletableFuture的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">CompletableFuture</span> <span class="n">future</span><span class="o">);</span>
<span class="c1">//将HttpResult的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">HttpResult</span> <span class="n">result</span><span class="o">);</span>
<span class="c1">//将HttpResult的结果对象以JSON格式输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finishJson</span><span class="o">(</span><span class="kd">final</span> <span class="n">JsonConvert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">HttpResult</span> <span class="n">result</span><span class="o">);</span>
<span class="c1">//将指定字符串以响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">String</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//以指定响应码附带内容输出, message 可以为null</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">int</span> <span class="n">status</span><span class="o">,</span> <span class="n">String</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//将结果对象输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将结果对象输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kd">final</span> <span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//将结果对象输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kd">final</span> <span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Type</span> <span class="n">type</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">obj</span><span class="o">);</span>
<span class="c1">//以304状态码输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish304</span><span class="o">();</span>
<span class="c1">//以404状态码输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish404</span><span class="o">();</span>
<span class="c1">//将指定byte[]按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kd">final</span> <span class="kt">byte</span><span class="o">[]</span> <span class="n">bs</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer按响应结果输出</span>
<span class="c1">//kill 输出后是否强制关闭连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">,</span> <span class="n">ByteBuffer</span> <span class="n">buffer</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer数组按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">ByteBuffer</span><span class="o">...</span> <span class="n">buffers</span><span class="o">);</span>
<span class="c1">//将指定ByteBuffer数组按响应结果输出</span>
<span class="c1">//kill 输出后是否强制关闭连接</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">kill</span><span class="o">,</span> <span class="n">ByteBuffer</span><span class="o">...</span> <span class="n">buffers</span><span class="o">);</span>
<span class="c1">//将指定文件按响应结果输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="n">File</span> <span class="n">file</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">;</span>
<span class="c1">//将文件按指定文件名输出</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">finish</span><span class="o">(</span><span class="kd">final</span> <span class="n">String</span> <span class="n">filename</span><span class="o">,</span> <span class="n">File</span> <span class="n">file</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span><span class="o">;</span>
<span class="c1">//HttpResponse回收时回调的监听方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">recycleListener</span><span class="o">(</span><span class="n">BiConsumer</span><span class="o">&lt;</span><span class="n">HttpRequest</span><span class="o">,</span> <span class="n">HttpResponse</span><span class="o">&gt;</span> <span class="n">recycleListener</span><span class="o">);</span>
<span class="o">}</span>
</pre></div>
<p id="net_websocket">&nbsp;&nbsp;<b>. WebSocket 对象</b> </p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">abstract</span> <span class="kd">class</span> <span class="nc">WebSocket</span><span class="o">&lt;</span><span class="n">G</span><span class="o">,</span> <span class="n">T</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="c1">//给自身发送消息, 消息类型是String或byte[]或可JavaBean对象 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">send</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给自身发送消息, 消息类型是key-value键值对 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMap</span><span class="o">(</span><span class="n">Object</span><span class="o">...</span> <span class="n">messages</span><span class="o">);</span>
<span class="c1">//给自身发送消息, 消息类型是String或byte[]或可JavaBean对象 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">send</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给自身发送消息, 消息类型是key-value键值对 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMap</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">last</span><span class="o">,</span> <span class="n">Object</span><span class="o">...</span> <span class="n">messages</span><span class="o">);</span>
<span class="c1">//给自身发送消息, 消息类型是JavaBean对象 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">send</span><span class="o">(</span><span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给自身发送消息, 消息类型是JavaBean对象 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">send</span><span class="o">(</span><span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="n">G</span><span class="o">...</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="n">Stream</span><span class="o">&lt;</span><span class="n">G</span><span class="o">&gt;</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="n">G</span><span class="o">...</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="n">Stream</span><span class="o">&lt;</span><span class="n">G</span><span class="o">&gt;</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">,</span> <span class="n">G</span><span class="o">...</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">,</span> <span class="n">Stream</span><span class="o">&lt;</span><span class="n">G</span><span class="o">&gt;</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">,</span> <span class="n">G</span><span class="o">...</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送 二进制消息/文本消息/JavaBean对象消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendMessage</span><span class="o">(</span><span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">,</span> <span class="n">Stream</span><span class="o">&lt;</span><span class="n">G</span><span class="o">&gt;</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//给所有人广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给所有人广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给符合条件的人群广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">WebSocketRange</span> <span class="n">wsrange</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给符合条件的人群广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">WebSocketRange</span> <span class="n">wsrange</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">);</span>
<span class="c1">//给所有人广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给所有人广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给符合条件的人群广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="kd">final</span> <span class="n">WebSocketRange</span> <span class="n">wsrange</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给符合条件的人群广播消息, 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastMessage</span><span class="o">(</span><span class="n">WebSocketRange</span> <span class="n">wsrange</span><span class="o">,</span> <span class="n">Convert</span> <span class="n">convert</span><span class="o">,</span> <span class="kd">final</span> <span class="n">Object</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//给指定userid的WebSocket节点发送操作</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendAction</span><span class="o">(</span><span class="kd">final</span> <span class="n">WebSocketAction</span> <span class="n">action</span><span class="o">,</span> <span class="n">Serializable</span><span class="o">...</span> <span class="n">userids</span><span class="o">);</span>
<span class="c1">//广播操作, 给所有人发操作指令</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">broadcastAction</span><span class="o">(</span><span class="kd">final</span> <span class="n">WebSocketAction</span> <span class="n">action</span><span class="o">);</span>
<span class="c1">//获取用户在线的SNCP节点地址列表不是分布式则返回元素数量为1且元素值为null的列表</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Collection</span><span class="o">&lt;</span><span class="n">InetSocketAddress</span><span class="o">&gt;&gt;</span> <span class="nf">getRpcNodeAddresses</span><span class="o">(</span><span class="kd">final</span> <span class="n">Serializable</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//获取在线用户的详细连接信息</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Map</span><span class="o">&lt;</span><span class="n">InetSocketAddress</span><span class="o">,</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;&gt;&gt;</span> <span class="nf">getRpcNodeWebSocketAddresses</span><span class="o">(</span><span class="kd">final</span> <span class="n">Serializable</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//发送PING消息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendPing</span><span class="o">();</span>
<span class="c1">//发送PING消息附带其他信息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendPing</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//发送PONG消息附带其他信息 返回结果0表示成功非0表示错误码</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">sendPong</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">data</span><span class="o">);</span>
<span class="c1">//强制关闭用户的所有WebSocket</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">&gt;</span> <span class="nf">forceCloseWebSocket</span><span class="o">(</span><span class="n">Serializable</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//更改本WebSocket的userid</span>
<span class="kd">public</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">&gt;</span> <span class="nf">changeUserid</span><span class="o">(</span><span class="kd">final</span> <span class="n">G</span> <span class="n">newuserid</span><span class="o">);</span>
<span class="c1">//获取指定userid的WebSocket数组, 没有返回null 此方法用于单用户多连接模式</span>
<span class="kd">protected</span> <span class="n">Stream</span><span class="o">&lt;</span><span class="n">WebSocket</span><span class="o">&gt;</span> <span class="nf">getLocalWebSockets</span><span class="o">(</span><span class="n">G</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//获取指定userid的WebSocket数组, 没有返回null 此方法用于单用户单连接模式</span>
<span class="kd">protected</span> <span class="n">WebSocket</span> <span class="nf">findLocalWebSocket</span><span class="o">(</span><span class="n">G</span> <span class="n">userid</span><span class="o">);</span>
<span class="c1">//获取当前进程节点所有在线的WebSocket</span>
<span class="kd">protected</span> <span class="n">Collection</span><span class="o">&lt;</span><span class="n">WebSocket</span><span class="o">&gt;</span> <span class="nf">getLocalWebSockets</span><span class="o">();</span>
<span class="c1">//获取ByteBuffer资源池</span>
<span class="kd">protected</span> <span class="n">Supplier</span><span class="o">&lt;</span><span class="n">ByteBuffer</span><span class="o">&gt;</span> <span class="nf">getByteBufferSupplier</span><span class="o">();</span>
<span class="c1">//返回sessionid, null表示连接不合法或异常,默认实现是request.sessionid(true),通常需要重写该方法</span>
<span class="kd">protected</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">String</span><span class="o">&gt;</span> <span class="nf">onOpen</span><span class="o">(</span><span class="kd">final</span> <span class="n">HttpRequest</span> <span class="n">request</span><span class="o">);</span>
<span class="c1">//创建userid null表示异常 必须实现该方法</span>
<span class="kd">protected</span> <span class="kd">abstract</span> <span class="n">CompletableFuture</span><span class="o">&lt;</span><span class="n">G</span><span class="o">&gt;</span> <span class="nf">createUserid</span><span class="o">();</span>
<span class="c1">//WebSocket.broadcastMessage时的过滤条件</span>
<span class="kd">protected</span> <span class="kt">boolean</span> <span class="nf">predicate</span><span class="o">(</span><span class="n">WebSocketRange</span> <span class="n">wsrange</span><span class="o">);</span>
<span class="c1">//WebSokcet连接成功后的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onConnected</span><span class="o">();</span>
<span class="c1">//ping后的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPing</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">);</span>
<span class="c1">//pong后的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onPong</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">);</span>
<span class="c1">//接收到消息的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="n">T</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//接收到文本消息的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="n">String</span> <span class="n">message</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//接收到二进制消息的回调方法</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onMessage</span><span class="o">(</span><span class="kt">byte</span><span class="o">[]</span> <span class="n">bytes</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">last</span><span class="o">);</span>
<span class="c1">//关闭的回调方法调用此方法时WebSocket已经被关闭</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">onClose</span><span class="o">(</span><span class="kt">int</span> <span class="n">code</span><span class="o">,</span> <span class="n">String</span> <span class="n">reason</span><span class="o">);</span>
<span class="c1">//获取当前WebSocket下的属性</span>
<span class="kd">public</span> <span class="n">T</span> <span class="nf">getAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//移出当前WebSocket下的属性</span>
<span class="kd">public</span> <span class="n">T</span> <span class="nf">removeAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">);</span>
<span class="c1">//给当前WebSocket下的增加属性</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">setAttribute</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">,</span> <span class="n">Object</span> <span class="n">value</span><span class="o">);</span>
<span class="c1">//获取当前WebSocket所属的userid</span>
<span class="kd">public</span> <span class="n">G</span> <span class="nf">getUserid</span><span class="o">();</span>
<span class="c1">//获取当前WebSocket的会话ID 不会为null</span>
<span class="kd">public</span> <span class="n">Serializable</span> <span class="nf">getSessionid</span><span class="o">();</span>
<span class="c1">//获取客户端直接地址, 当WebSocket连接是由代理服务器转发的则该值固定为代理服务器的IP地址</span>
<span class="kd">public</span> <span class="n">SocketAddress</span> <span class="nf">getRemoteAddress</span><span class="o">();</span>
<span class="c1">//获取客户端真实地址 同 HttpRequest.getRemoteAddr()</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getRemoteAddr</span><span class="o">();</span>
<span class="c1">//获取WebSocket创建时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getCreatetime</span><span class="o">();</span>
<span class="c1">//获取最后一次发送消息的时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLastSendTime</span><span class="o">();</span>
<span class="c1">//获取最后一次读取消息的时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLastReadTime</span><span class="o">();</span>
<span class="c1">//获取最后一次ping的时间</span>
<span class="kd">public</span> <span class="kt">long</span> <span class="nf">getLastPingTime</span><span class="o">();</span>
<span class="c1">//显式地关闭WebSocket</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">close</span><span class="o">();</span>
<span class="c1">//WebSocket是否已关闭</span>
<span class="kd">public</span> <span class="kt">boolean</span> <span class="nf">isClosed</span><span class="o">();</span>
<span class="o">}</span>
</pre></div>
<h3><a id="net_sncp" class="anchor" href="#" aria-hidden="true"></a>SNCP 协议</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SNCP(Service Node Communicate Protocol)协议是Redkale独有的一种传输协议用于进程之间的通信即请求方的<a href="service.html#service_remote" target="_blank">远程模式Service</a>与响应方的Service之间的通信。是RPC(远程过程调用协议)的同类型协议主要区别在于Redkale里SNCP几乎是透明的写一个普通的Service通过配置即可实现远程调用而不需要专门针对远程写接口。SNCP服务的配置与HTTP差不多只是SNCP不需要ServletSncpServlet是通过Service动态生成的。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SNCP的数据包分包头和包体。包头描述请求的Service信息请求包的包体描述参数的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>,响应包的包体描述回调的参数对象和结果对象的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a><br/>
&nbsp;&nbsp;&nbsp;&nbsp;包头长度固定,其结构如下:
</p>
<table style="margin: auto;">
<tr><th>字 段</th><th>占用字节数</th><th>描 述</th></tr>
<tr><td>序列号</td><td style="text-align: center;">8</td><td>请求的唯一序列号</td></tr>
<tr><td>包头长度</td><td style="text-align: center;">2</td><td>值固定为60</td></tr>
<tr><td>Service版本号</td><td style="text-align: center;">4</td><td>值为Service.version()</td></tr>
<tr><td>Service资源hash值</td><td style="text-align: center;">16</td><td>Service资源名class.getName():@Resource.name()的MD5值</td></tr>
<tr><td>Service方法hash值</td><td style="text-align: center;">16</td><td>Service方法method.toString()的MD5值</td></tr>
<tr><td>发送方地址</td><td style="text-align: center;">6</td><td>前4字节为地址后2字节为端口号</td></tr>
<tr><td>包体长度</td><td style="text-align: center;">4</td><td>整个包体的长度</td></tr>
<tr><td>结果码</td><td style="text-align: center;">4</td><td>请求方的值固定为0响应方的值视为错误码为0表示成功非0为失败。</td></tr>
</table>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;包体数据结构为 ([参数序号][参数BSON值])* N + [0][结果对象BSON]。 其中参数序号从1开始只有当Service的方法存在<a href="service.html#service_dyncall" target="_blank">@RpcCall回调</a>才会有参数<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>序号为0表示为结果对象的<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>。若方法为<font color="blue">void</font>返回类型,则不存在结果对象<a href="convert.html#convert_bson_struct" target="_blank">BSON值</a>
</p>
<h3><a id="net_diy" class="anchor" href="#" aria-hidden="true"></a>自定义协议</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;协议的网络框架包含五种对象: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Context &nbsp;&nbsp;&nbsp;&nbsp;: 协议上下文对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Request &nbsp;&nbsp;&nbsp;: 服务请求对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Response : 服务响应对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Servlet &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 服务逻辑处理对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Server &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;: 服务监听对象 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常自定义协议需要继承上面五种对象类同时为了让Redkale能识别和加载自定义协议服务需要继承 <b>org.redkale.boot.NodeServer</b> 并指明 <b>@NodeProtocol</b>,实现可以参考 <a href="https://github.com/redkale/redkale-plugins/tree/master/src/org/redkalex/socks" target="_blank" >基于SOCKS5协议的反向代理服务器</a>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,52 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="plugins_intro" class="anchor" href="#" aria-hidden="true"></a>Redkale 插件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="https://github.com/redkale/redkale-plugins/releases" target="_blank">org.redkalex</a> 是官方插件的根包名。 <a href="https://github.com/redkale/redkale-plugins" target="_blank">redkale-plugins</a> 提供了一些常用的插件。<br/></p>
<h3><a href="plugin_pay.html" target="_blank" class="anchor">支付插件</a></h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/redkale/redkale-plugins/tree/master/src/org/redkalex/pay" target="_blank">org.redkalex.pay</a>
包提供微信、支付宝、银联等支付实现,<a href="plugin_pay.html" target="_blank">详情点击这里</a></p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,887 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="redkale_start" class="anchor" href="#" aria-hidden="true"></a>Redkale 功能</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale虽然只有1M左右大小但是麻雀虽小五脏俱全。既可作为服务器使用也可当工具包使用。作为独立的工具包提供以下功能<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、convert包提供JSON的序列化和反序列化功能类似Gson、Jackson。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、convert包提供Java对象二进制的序列化和反序列化功能类似Protobuf。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、source包提供很简便的数据库操作功能类似JPA、Hibernate。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4、net包提供TCP/UDP服务功能 类似Mina。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5、net.http提供HTTP服务 类似Tomcat、Netty。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6、ResourceFactory提供轻量级的依赖注入功能 类似Google Guice。 <br/>
</p>
<h3><a id="redkale_code" class="anchor" href="#" aria-hidden="true"></a>Java 源码</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a href="https://github.com/redkale" target="_blank" >Github 源码 &nbsp;&nbsp; https://github.com/redkale</a></p>
<h3><a id="redkale_server" class="anchor" href="#" aria-hidden="true"></a>Redkale 服务器</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale作为服务器的目录如下: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>bin</b>&nbsp;&nbsp;&nbsp; 存放启动/关闭/apidoc脚本(start.sh、shutdown.sh、apidoc.sh、start.bat、shutdown.bat、apidoc.bat) <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>conf</b>&nbsp; 存放服务器所需配置文件:<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="#redkale_confxml">application.xml</a> 服务配置文件 (必需)<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; logging.properties日志配置文件 (可选) <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <a href="source.html#source_confxml" target="_blank">persistence.xml</a>:数据库配置文件 (可选)<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>lib</b>&nbsp;&nbsp;&nbsp;&nbsp; 存放服务所依赖且不需要热更新的第三方包redkale.jar 放在此处。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>libs</b>&nbsp;&nbsp; 存放自己的业务jar或需要热更新的jar。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>logs</b> logging.properties 配置中默认的日志存放目录。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>root</b>&nbsp; <a href="#redkale_confxml">application.xml</a> 配置中HTTP服务所需页面的默认根目录。 <br/>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale启动的流程如下<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、加载 <a href="#redkale_confxml">application.xml</a> 并解析。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、初始化 <b>&lt;resources&gt;</b> 节点中的资源。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、解析所有的 <b>&lt;server&gt;</b> 节点。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4、初始化并启动所有<b>&lt;server&gt;</b> 节点的Server服务 (优先加载SNCP协议的Server最后加载WATCH协议的Server)。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5、初始化单个Server <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.1、扫描classpath加载所有可用的Service实现类(没有标记为@AutoLoad(<span style="color: #0000FF;">false</span>)的类)并实例化,然后相互依赖注入。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.2、Service实例在依赖注入过程中加载所需的DataSource、CacheSource资源。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.3、调用所有本地模式Service的init方法。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.4、扫描classpath加载所有可用的Servlet实现类(没有标记为@AutoLoad(<span style="color: #0000FF;">false</span>)的类)并实例化 (WebSocketServlet优先)。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.5、给所有Servlet依赖注入所需的Service。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.6、调用所有Servlet的init方法。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5.7、启动Server的服务监听。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6、启动进程本身的监听服务。 <br/>
</p>
<h3><a id="redkale_dev" class="anchor" href="#" aria-hidden="true"></a>基于Redkale的开发与调试</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;基于Redkale创建一个Java应用程序工程(即使是Web项目也不要创建Java-Web工程)引用redkale.jar 并创建Redkale所需的几个目录和文件。一个普通的Web项目只需要编写业务层的Service和接入层的HttpServlet的代码。数据库DataSource通过配置文件进行设置。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;编写完代码可以通过启动脚本进行调试, 也可以在IDE设置项目的主类为 org.redkale.boot.Application 或者工程内定义主类进行启动调试:
</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">Bootstrap</span> <span class="o">{</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">org</span><span class="o">.</span><span class="na">redkale</span><span class="o">.</span><span class="na">boot</span><span class="o">.</span><span class="na">Application</span><span class="o">.</span><span class="na">main</span><span class="o">(</span><span class="n">args</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;若需要调试单个Service可以通过 <b>Application.singleton</b> 方法进行调试: </p>
<div class="highlight"><pre> <span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">UserService</span> <span class="n">service</span> <span class="o">=</span> <b><span class="n">Application</span><span class="o">.</span><span class="na">singleton</span></b><span class="o">(</span><span class="n">UserService</span><span class="o">.</span><span class="na">class</span><span class="o">);</span>
<span class="n">LoginBean</span> <span class="n">bean</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">LoginBean</span><span class="o">();</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setAccount</span><span class="o">(</span><span class="s">&quot;myaccount&quot;</span><span class="o">);</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setPassword</span><span class="o">(</span><span class="s">&quot;123456&quot;</span><span class="o">);</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">service</span><span class="o">.</span><span class="na">login</span><span class="o">(</span><span class="n">bean</span><span class="o">));</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Application.singleton 运行流程与通过bin脚本启动的流程基本一致区别在于singleton运行时不会启动Server和Application自身的服务监听。Redkale提倡接入层(Servlet)与业务层(Service)分开Service在代码上不能依赖于Servlet因此调试Service自身逻辑时不需要启动接入层服务(类似WebSocket依赖Servlet的功能除外)。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>注:</b> Application.singleton的参数Service类不能是抽象类、接口或不存在非final的public方法。</p>
<h3><a id="redkale_inject" class="anchor" href="#" aria-hidden="true"></a>Redkale的依赖注入</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale内置的依赖注入实现很简单只有三个注解和一个类: javax.annotation.Resource、org.redkale.util.ResourceType、org.redkale.util.ResourceListener、org.redkale.util.ResourceFactory采用反射技术依赖注入通常不会在频繁的操作中进行因此性能要求不会很高。其中前两个是注解ResourceFactory是主要操作类主要提供注册和注入两个接口。ResourceFactory的依赖注入不仅提供其他依赖注入框架的常规功能还能动态的自动更新通过inject注入的资源。</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">AService</span> <span class="o">{</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;property.id&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">id</span><span class="o">;</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;property.id&quot;</span><span class="o">)</span> <span class="c1">//property.开头的资源名允许String自动转换成primitive数值类型</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">intid</span><span class="o">;</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;bigint&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">BigInteger</span> <span class="n">bigint</span><span class="o">;</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;seqid&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">seqid</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="na">BService</span> <span class="n">bservice</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">&quot;{id:\&quot;&quot;</span> <span class="o">+</span> <span class="n">id</span> <span class="o">+</span> <span class="s">&quot;\&quot;, intid: &quot;</span> <span class="o">+</span> <span class="n">intid</span> <span class="o">+</span> <span class="s">&quot;, bigint:&quot;</span> <span class="o">+</span> <span class="n">bigint</span> <span class="o">+</span> <span class="s">&quot;}&quot;</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">BService</span> <span class="o">{</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;property.id&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">id</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">AService</span> <span class="n">aservice</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">name</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="nd">@java.beans.ConstructorProperties</span><span class="o">({</span><span class="s">&quot;name&quot;</span><span class="o">})</span>
<span class="kd">public</span> <span class="nf">BService</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">name</span> <span class="o">=</span> <span class="n">name</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">toString</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">&quot;{name:\&quot;&quot;</span> <span class="o">+</span> <span class="n">name</span> <span class="o">+</span> <span class="s">&quot;\&quot;, id: &quot;</span> <span class="o">+</span> <span class="n">id</span> <span class="o">+</span> <span class="s">&quot;, aserivce:&quot;</span> <span class="o">+</span> <span class="n">aservice</span> <span class="o">+</span> <span class="s">&quot;}&quot;</span><span class="o">;</span>
<span class="o">}</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">Exception</span> <span class="o">{</span>
<span class="n">ResourceFactory</span> <span class="n">factory</span> <span class="o">=</span> <span class="n">ResourceFactory</span><span class="o">.</span><span class="na">root</span><span class="o">();</span>
<span class="n">factory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="s">&quot;property.id&quot;</span><span class="o">,</span> <span class="s">&quot;2345&quot;</span><span class="o">);</span> <span class="c1">//注入String类型的property.id</span>
<span class="n">AService</span> <span class="n">aservice</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">AService</span><span class="o">();</span>
<span class="n">BService</span> <span class="n">bservice</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">BService</span><span class="o">(</span><span class="s">&quot;eee&quot;</span><span class="o">);</span>
<span class="n">factory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">aservice</span><span class="o">);</span> <span class="c1">//放进Resource池内默认的资源名name为&quot;&quot;</span>
<span class="n">factory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">bservice</span><span class="o">);</span> <span class="c1">//放进Resource池内默认的资源名name为&quot;&quot;</span>
<span class="n">factory</span><span class="o">.</span><span class="na">inject</span><span class="o">(</span><span class="n">aservice</span><span class="o">);</span> <span class="c1">//给aservice注入id、bservicebigint没有资源所以为null</span>
<span class="n">factory</span><span class="o">.</span><span class="na">inject</span><span class="o">(</span><span class="n">bservice</span><span class="o">);</span> <span class="c1">//给bservice注入id、aservice</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">aservice</span><span class="o">);</span> <span class="c1">//输出结果为:{id:&quot;2345&quot;, intid:2345, bigint:null, bservice:{name:eee}}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">bservice</span><span class="o">);</span> <span class="c1">//输出结果为:{name:&quot;eee&quot;, id:2345, aserivce:{id:&quot;2345&quot;, intid:2345, bigint:null, bservice:{name:eee}}}</span>
<span class="n">factory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="s">&quot;seqid&quot;</span><span class="o">,</span> <span class="mi">200</span><span class="o">);</span> <span class="c1">//放进Resource池内, 同时ResourceFactory会自动更新aservice的seqid值</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">factory</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="s">&quot;seqid&quot;</span><span class="o">,</span> <span class="kt">int</span><span class="o">.</span><span class="na">class</span><span class="o">));</span> <span class="c1">//输出结果为200</span>
<span class="n">factory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="s">&quot;bigint&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">BigInteger</span><span class="o">(</span><span class="s">&quot;66666&quot;</span><span class="o">));</span> <span class="c1">//放进Resource池内, 同时ResourceFactory会自动更新aservice对象的bigint值 </span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">aservice</span><span class="o">);</span> <span class="c1">//输出结果为:{id:&quot;2345&quot;, intid:2345, bigint:66666, bservice:{name:eee}}可以看出seqid与bigint值都已自动更新</span>
<span class="n">factory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="s">&quot;property.id&quot;</span><span class="o">,</span> <span class="s">&quot;6789&quot;</span><span class="o">);</span> <span class="c1">//更新Resource池内的id资源值, 同时ResourceFactory会自动更新aservice、bservice的id值</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">aservice</span><span class="o">);</span> <span class="c1">//输出结果为:{id:&quot;6789&quot;, intid:6789, bigint:66666, bservice:{name:eee}}</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">bservice</span><span class="o">);</span> <span class="c1">//输出结果为:{name:&quot;eee&quot;, id:6789, aserivce:{id:&quot;6789&quot;, intid:6789, bigint:66666, bservice:{name:eee}}}</span>
<span class="n">bservice</span> <span class="o">=</span> <span class="k">new</span> <span class="nf">BService</span><span class="o">(</span><span class="s">&quot;ffff&quot;</span><span class="o">);</span>
<span class="n">factory</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">bservice</span><span class="o">);</span> <span class="c1">//更新Resource池内name=&quot;&quot;的BService资源, 同时ResourceFactory会自动更新aservice的bservice对象</span>
<span class="n">factory</span><span class="o">.</span><span class="na">inject</span><span class="o">(</span><span class="n">bservice</span><span class="o">);</span>
<span class="n">System</span><span class="o">.</span><span class="na">out</span><span class="o">.</span><span class="na">println</span><span class="o">(</span><span class="n">aservice</span><span class="o">);</span> <span class="c1">//输出结果为:{id:&quot;6789&quot;, intid: 6789, bigint:66666, bservice:{name:ffff}}</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上例通过ResourceFactory.inject注入的对象都会自动更新资源的变化若不想自动更新可以使用带boolean autoSync参数的register系列方法(autoSync传false)注册新资源。</p>
<h3><a id="redkale_deploy" class="anchor" href="#" aria-hidden="true"></a>Redkale 架构部署</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常一个系统会分为三层接入层、业务层、数据层。对应到Redkale的组件是 Servlet、Service、Source。大部分系统提供的是HTTP服务为了方便演示Redkale从集中式到分布式的变化以一个简单的HTTP服务作为范例。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;开发一个极简单的小论坛系统。包含三个模块: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用户模块 &nbsp;&nbsp;&nbsp;UserSerivice: &nbsp;&nbsp;&nbsp;&nbsp;提供用户注册、登录、更新资料等功能, UserServlet作为接入层。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;帖子模块 ForumSerivice: &nbsp;&nbsp;&nbsp;&nbsp;提供看帖、发帖、删帖等功能, ForumServlet作为接入层。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通知模块 &nbsp;NotifySerivice: &nbsp;&nbsp;&nbsp;&nbsp;提供用户操作、回帖等消息通知功能, NotifyWebSocket是WebSocket的Servlet, 且name为 <b>ws_notify</b>,作为接入层。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;其中数据源有: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DataSource: &nbsp;&nbsp; 在persistence.xml里配置的数据库Source的name为demodb ,三个模块都需要使用demodb。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CacheSource: &nbsp;&nbsp; 仅供UserSerivice用于存放session的缓存Servicename为 usersessions, 且session只存放用户ID( int 类型)。<br/>
</p>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>1、单点部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在早期用户量很少或者开发、调试环境中只需部署一个进程就可满足需求。 </p>
<p style="text-align: center;"><img src="images/distributeimg_1.png" alt=""/></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上图所有模块的HttpServlet、Service与Source数据库操作全部署在一起。 application.xml作简单的配置即可:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;HTTP&quot;</span> <span class="na">port=</span><span class="s">&quot;6060&quot;</span> <span class="na">root=</span><span class="s">&quot;root&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;servlets</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>2、多点部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在生产环境需要避免单点问题一个服务一般会部署多套。在此做个简单的容灾部署最前端部署一个nginx作反向代理和负载均衡服务器后面部署两套系统。 </p>
<p style="text-align: center;"><img src="images/distributeimg_2.png" alt=""/></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上图两个进程间的Serivce都是本地模式两者会通过SNCP服务保持数据同步若DataSource开启了数据缓存也会自动同步。两套的配置文件相同配置如下:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;ALL&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.120&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- HTTP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;HTTP&quot;</span> <span class="na">port=</span><span class="s">&quot;6060&quot;</span> <span class="na">root=</span><span class="s">&quot;root&quot;</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- 前端配置了nginx需要配置才能获取客户端真实的IP地址 --&gt;</span>
<span class="nt">&lt;request&gt;</span>
<span class="nt">&lt;remoteaddr</span> <span class="na">value=</span><span class="s">&quot;request.headers.X-RemoteAddress&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/request&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="na">groups=</span><span class="s">&quot;ALL&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;servlets</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="c">&lt;!-- SNCP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;SNCP&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="na">groups=</span><span class="s">&quot;ALL&quot;</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- 有WebSocketServlet的服务必须配置WebSocketNodeService且Redkale同时会自动创建一个同名(ws_notify)的 CacheSource --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;ws_notify&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.WebSocketNodeService</b>&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 存在DataSource必须配置DataSourceService --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;demodb&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.DataSourceService</b>&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 存放用户HTTP session信息的CacheSource --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;usersessions&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.CacheSourceService</b>&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;key-type&quot;</span> <span class="na">value=</span><span class="s">&quot;java.lang.String&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;value-type&quot;</span> <span class="na">value=</span><span class="s">&quot;java.lang.Integer&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/service&gt;</span>
<span class="nt">&lt;/services&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>3、分层部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;随着业务的复杂度增加,接入层与业务层混在一起会越来越难部署和维护,因此需要进行分层部署。 </p>
<p style="text-align: center;"><img src="images/distributeimg_3.png" alt=""/></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上图对HttpServlet与Service进行了分离。每个接入层的Service都是远程模式业务层只需提供SNCP供远程调用。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接入层中每个进程的配置相同,配置如下:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;ALL&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.120&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- HTTP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;HTTP&quot;</span> <span class="na">port=</span><span class="s">&quot;6060&quot;</span> <span class="na">root=</span><span class="s">&quot;root&quot;</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- 前端配置了nginx需要配置才能获取客户端真实的IP地址 --&gt;</span>
<span class="nt">&lt;request&gt;</span>
<span class="nt">&lt;remoteaddr</span> <span class="na">value=</span><span class="s">&quot;request.headers.X-RemoteAddress&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/request&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="na">groups=</span><span class="s">&quot;ALL&quot;</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- 有WebSocketServlet的服务必须配置WebSocketNodeService且Redkale同时会自动创建一个同名(ws_notify)的 CacheSource --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;ws_notify&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.WebSocketNodeService</b>&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/services&gt;</span>
<span class="nt">&lt;servlets</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;业务层中每个进程的配置相同,配置如下:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;ALL&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.120&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- SNCP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;SNCP&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="na">groups=</span><span class="s">&quot;ALL&quot;</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- 有WebSocketServlet的服务必须配置WebSocketNodeService且Redkale同时会自动创建一个同名(ws_notify)的 CacheSource --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;ws_notify&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.WebSocketNodeService</b>&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 存在DataSource必须配置DataSourceService --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;demodb&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.DataSourceService</b>&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 存放用户HTTP session信息的CacheSource --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;usersessions&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.CacheSourceService</b>&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;key-type&quot;</span> <span class="na">value=</span><span class="s">&quot;java.lang.String&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;value-type&quot;</span> <span class="na">value=</span><span class="s">&quot;java.lang.Integer&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/service&gt;</span>
<span class="nt">&lt;/services&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>4、微服务部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当用户量和发帖量增加到上百万的时候,明显地将所有模块的服务部署到一个进程里是不行的。 因此需要将Service服务都独立部署形成微服务架构。</p>
<p style="text-align: center;"><img src="images/distributeimg_4.png" alt=""/></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上图将Serivice都独立部署并进行容灾部署当然如果有需要Servlet之间、Source都可以各自分离独立部署。不同类型的Service之间都是远程模式调用。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接入层中每个进程的配置相同,配置如下:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.111&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.120&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.121&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;FORUM_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.130&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.131&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- HTTP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;HTTP&quot;</span> <span class="na">port=</span><span class="s">&quot;6060&quot;</span> <span class="na">root=</span><span class="s">&quot;root&quot;</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- 前端配置了nginx需要配置才能获取客户端真实的IP地址 --&gt;</span>
<span class="nt">&lt;request&gt;</span>
<span class="nt">&lt;remoteaddr</span> <span class="na">value=</span><span class="s">&quot;request.headers.X-RemoteAddress&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/request&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.NotifyService&quot;</span> <span class="na">groups=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.ForumService&quot;</span> <span class="na">groups=</span><span class="s">&quot;FORUM_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 有WebSocketServlet的服务必须配置WebSocketNodeService且Redkale同时会自动创建一个同名(ws_notify)的 CacheSource --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;ws_notify&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.WebSocketNodeService</b>&quot;</span> <span class="na">groups=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/services&gt;</span>
<span class="nt">&lt;servlets</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span> <span class="nt">/&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;用户模块UserService服务群中各个进程的配置相同配置如下:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.111&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.120&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.121&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;FORUM_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.130&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.131&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- SNCP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;SNCP&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.NotifyService&quot;</span> <span class="na">groups=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.ForumService&quot;</span> <span class="na">groups=</span><span class="s">&quot;FORUM_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 存在DataSource必须配置DataSourceService --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;demodb&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.DataSourceService</b>&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 存放用户HTTP session信息的CacheSource --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;usersessions&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.CacheSourceService</b>&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;key-type&quot;</span> <span class="na">value=</span><span class="s">&quot;java.lang.String&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;property</span> <span class="na">name=</span><span class="s">&quot;value-type&quot;</span> <span class="na">value=</span><span class="s">&quot;java.lang.Integer&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/service&gt;</span>
<span class="nt">&lt;/services&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通知模块NotifyService服务群中各个进程的配置相同配置如下:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.111&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.120&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.121&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;FORUM_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.130&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.131&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- SNCP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;SNCP&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.ForumService&quot;</span> <span class="na">groups=</span><span class="s">&quot;FORUM_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 有WebSocketServlet的服务必须配置WebSocketNodeService且Redkale同时会自动创建一个同名(ws_notify)的 CacheSource --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;ws_notify&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.WebSocketNodeService</b>&quot;</span> <span class="na">groups=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 存在DataSource必须配置DataSourceService --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;demodb&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.DataSourceService</b>&quot;</span> <span class="na">groups=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/services&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;帖子模块ForumService服务群中各个进程的配置相同配置如下:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.111&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.120&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.121&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;FORUM_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.130&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.131&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- SNCP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;SNCP&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.NotifyService&quot;</span> <span class="na">groups=</span><span class="s">&quot;NOTIFY_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 存在DataSource必须配置DataSourceService --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;demodb&quot;</span> <span class="na">value=</span><span class="s">&quot;<b>org.redkale.service.DataSourceService</b>&quot;</span> <span class="na">groups=</span><span class="s">&quot;FORUM_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/services&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>5、API网关式部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;随着用户量到了上千万时一个UserService的服务进程是无法提供全部用户服务。 因此可以考虑按用户段进行分布式部署。将192.168.50.110、192.168.50.111上的UserService服务改成网关式的服务。下面是以 <a href="service.html#service_local" target="_blank">Service本地模式介绍中的UserService</a> 为范例进行编写:</p>
<div class="highlight"><pre><span class="nd">@ResourceType</span><span class="o">({</span><span class="n">UserService</span><span class="o">.</span><span class="kd">class</span><span class="o">})</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserServiceGateWay</span> <span class="kd">extends</span> <span class="n">UserService</span> <span class="o">{</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;userservice_reg&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">regUserService</span><span class="o">;</span> <span class="c1">//只用于注册的服务节点</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;userservice_mob&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">mobUserService</span><span class="o">;</span> <span class="c1">//只用于查询手机号码对应的userid的服务节点</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;userservice_node01&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">userService01</span><span class="o">;</span> <span class="c1">//userid小于2000000的用户的服务节点</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;userservice_node02&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">userService02</span><span class="o">;</span> <span class="c1">//userid小于4000000的用户的服务节点</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;userservice_node03&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">userService03</span><span class="o">;</span> <span class="c1">//userid小于6000000的用户的服务节点</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;userservice_node04&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">userService04</span><span class="o">;</span> <span class="c1">//userid大于6000000的用户的服务节点</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="nf">getService</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">userid</span> <span class="o">&lt;=</span> <span class="mi">200_0000</span><span class="o">)</span> <span class="k">return</span> <span class="n">userService01</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">userid</span> <span class="o">&lt;=</span> <span class="mi">400_0000</span><span class="o">)</span> <span class="k">return</span> <span class="n">userService02</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">userid</span> <span class="o">&lt;=</span> <span class="mi">600_0000</span><span class="o">)</span> <span class="k">return</span> <span class="n">userService03</span><span class="o">;</span>
<span class="k">return</span> <span class="n">userService04</span><span class="o">;</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">findUserInfo</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">getService</span><span class="o">(</span><span class="n">userid</span><span class="o">).</span><span class="na">findUserInfo</span><span class="o">(</span><span class="n">userid</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="nf">login</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//手机号码用long存储0表示无手机号码</span>
<span class="kt">int</span> <span class="n">userid</span> <span class="o">=</span> <span class="n">mobUserService</span><span class="o">.</span><span class="na">findUserid</span><span class="o">(</span><span class="n">bean</span><span class="o">.</span><span class="na">getMobile</span><span class="o">());</span>
<span class="k">if</span> <span class="o">(</span><span class="n">userid</span> <span class="o">&lt;</span> <span class="mi">1</span><span class="o">)</span> <span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">&lt;&gt;(</span><span class="mi">10001</span><span class="o">,</span> <span class="s">&quot;not found mobile &quot;</span> <span class="o">+</span> <span class="n">bean</span><span class="o">.</span><span class="na">getMobile</span><span class="o">());</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">getService</span><span class="o">(</span><span class="n">userid</span><span class="o">).</span><span class="na">login</span><span class="o">(</span><span class="n">bean</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">register</span><span class="o">(</span><span class="n">UserInfo</span> <span class="n">user</span><span class="o">)</span> <span class="o">{</span>
<span class="n">regUserService</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">user</span><span class="o">);</span> <span class="c1">//会生成userid</span>
<span class="k">this</span><span class="o">.</span><span class="na">getService</span><span class="o">(</span><span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">()).</span><span class="na">putUserInfo</span><span class="o">(</span><span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">updateUsername</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">username</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">getService</span><span class="o">(</span><span class="n">userid</span><span class="o">).</span><span class="na">updateUsername</span><span class="o">(</span><span class="n">userid</span><span class="o">,</span> <span class="n">username</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从代码看出UserServiceGateWay继承了UserService 确保了UserService对外的服务接口不变上面代码是用户量在600-800万之间的写法通过简单的用户ID分段根据不同用户ID调不同的服务节点。</p>
<p style="text-align: center;"><img src="images/distributeimg_5.png" alt=""/></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上图网关下的UserService部署分三类 userservice_reg只用于注册用户userservice_mob提供查询手机号码与用户ID间的关系的服务userservice_node按用户段提供已有用户的服务。且每个UserService的实例在UserServiceGateWay都是远程模式。每种类型可以部署多个节点为了结构图简单上图每个类型只部署一个节点。UserServiceGateWay192.168.50.110、192.168.50.111)的配置如下:</p>
<div class="highlight"><pre><span class="nt">&lt;application</span> <span class="na">port=</span><span class="s">&quot;5050&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE_REG&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.70.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE_MOB&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.70.150&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE_NODE01&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.70.201&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE_NODE02&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.70.202&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE_NODE03&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.70.203&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE_NODE04&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.70.204&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.110&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.50.111&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- SNCP 监听 Server --&gt;</span>
<span class="nt">&lt;server</span> <span class="na">protocol=</span><span class="s">&quot;SNCP&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;services</span> <span class="na">autoload=</span><span class="s">&quot;true&quot;</span><span class="nt">&gt;</span>
<span class="c">&lt;!-- 配置UserService网关 --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;&quot;</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserServiceGateWay&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE&quot;</span><span class="nt">/&gt;</span>
<span class="c">&lt;!-- 配置UserService分段节点 --&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;userservice_reg&quot;</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE_REG&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;userservice_mob&quot;</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE_MOB&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;userservice_node01&quot;</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE_NODE01&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;userservice_node02&quot;</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE_NODE02&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;userservice_node03&quot;</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE_NODE03&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;userservice_node04&quot;</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;USER_SERVICE_NODE03&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/services&gt;</span>
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上几种部署方式的范例可以看出Redkale提供了非常强大的架构集中式到微服务架构不需要增加修改一行代码即可随意切换即使网关式部署也只是新增很少的代码就可切换且不影响其他服务。真正可以做到敏捷开发复杂的系统都可如小系统般快速地开发出来。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了降低接入层与业务层代码的耦合, 可以将Service分接口与实现两个类接入层只加载接口包、业务层使用实现包。
</p>
<br/>
<h3><a id="redkale_confxml" href="#" aria-hidden="true"></a>application.xml 配置说明</h3>
<div class="highlight"><pre><span></span><span class="cp">&lt;?xml version="1.0" encoding="UTF-8"?&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 文件说明:</span>
<span class="cm"> ${APP_HOME} 指当前程序的根目录APP_HOME</span>
<span class="cm"> 没注明唯一的节点可多个存在</span>
<span class="cm"> required 被声明required的属性值不能为空</span>
<span class="cm"> </span>
<span class="cm"> group</span>
<span class="cm"> / / \ \ </span>
<span class="cm"> / / \ \ </span>
<span class="cm"> / / \ \ </span>
<span class="cm"> node1 node2 node3 node4</span>
<span class="cm"> / \ </span>
<span class="cm"> / \</span>
<span class="cm"> / \</span>
<span class="cm"> / \</span>
<span class="cm"> serviceid1 serviceid2</span>
<span class="cm"> / \ / \</span>
<span class="cm"> serviceid1_name1 serviceid1_name2 serviceid2_name1 serviceid2_name2 </span>
<span class="cm">--&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> nodeid: int 进程的节点ID用于分布式环境一个系统中节点ID必须全局唯一使用cluster时框架会进行唯一性校验</span>
<span class="cm"> name: 进程的名称,用于监控识别,命名规则: 字母、数字、下划线、短横、点</span>
<span class="cm"> address: 本地局域网的IP地址 默认值为默认网卡的ip当不使用默认值需要指定值如192.168.1.22</span>
<span class="cm"> port: required 程序的管理Server的端口用于关闭或者与监管系统进行数据交互</span>
<span class="cm"> lib: 加上额外的lib路径,多个路径用分号;隔开; 默认为空。 例如: ${APP_HOME}/lib/a.jar;${APP_HOME}/lib2/b.jar;</span>
<span class="cm">--&gt;</span>
<span class="p">&lt;</span><span class="nt">application</span> <span class="na">nodeid</span><span class="o">=</span><span class="s">"1000"</span> <span class="na">port</span><span class="o">=</span><span class="s">"6560"</span> <span class="na">lib</span><span class="o">=</span><span class="s">""</span><span class="p">&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> 【节点全局唯一】 @since 2.3.0</span>
<span class="cm"> 全局Serivce执行的线程池 Application.workExecutor, 没配置该节点将自动创建一个。</span>
<span class="cm"> threads 线程数为0表示不启用workExecutor只用IO线程。默认: CPU核数, 核数=1的情况下默认值为2</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">executor</span> <span class="na">threads</span><span class="o">=</span><span class="s">"4"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> 【节点全局唯一】</span>
<span class="cm"> 第三方服务发现管理接口</span>
<span class="cm"> type 类名必须是org.redkale.cluster.ClusterAgent的子类</span>
<span class="cm"> waits: 注销服务后是否需要等待检查周期时间后再进行Service销毁默认值为false</span>
<span class="cm"> 当一个Service进行服务注销后不能立刻销毁Service因为健康检测是有间隔时间差的</span>
<span class="cm"> 需要等待一个健康检测周期时间,让其他进程都更新完服务列表。</span>
<span class="cm"> 如果使用MQ可以设置为false如果对服务健壮性要求高建议设置为true</span>
<span class="cm"> protocols: 服务发现可以处理的协议, 默认值为: SNCP, 多个协议用分号;隔开</span>
<span class="cm"> ports: 服务发现可以处理的端口, 多个端口用分号;隔开</span>
<span class="cm"> ttls: 心跳频率,多少秒一次</span>
<span class="cm"> xxxx: 自定义的字段属性例如CacheClusterAgent有source字段; ConsulClusterAgent有apiurl字段;</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">cluster</span> <span class="na">type</span><span class="o">=</span><span class="s">"org.redkalex.cluster.consul.ConsulClusterAgent"</span> <span class="na">waits</span><span class="o">=</span><span class="s">"false"</span> <span class="na">protocols</span><span class="o">=</span><span class="s">"SNCP"</span> <span class="na">ports</span><span class="o">=</span><span class="s">"7070;7071"</span> <span class="na">xxx</span><span class="o">=</span><span class="s">"xxx"</span> <span class="p">/&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> MQ管理接口配置</span>
<span class="cm"> 不同MQ节点所配置的MQ集群不能重复。</span>
<span class="cm"> MQ跟着协议走所以mq的属性值需要被赋值在rest节点上, 由于SncpServlet是自动生成的故SNCP协议下mq属性值被赋值在service/services节点上</span>
<span class="cm"> name: 服务的名称用于监控识别多个mq节点时只能有一个name为空的节点mq.name不能重复,命名规则: 字母、数字、下划线</span>
<span class="cm"> type 实现类名必须是org.redkale.mq.MessageAgent的子类</span>
<span class="cm"> threads线程数为0表示使用workExecutor。默认: CPU核数, 核数=1的情况下默认值为2JDK 21以上版本默认使用虚拟线程池</span>
<span class="cm"> rpcfirstcluster和mq同名组件时HttpRpcClient优先使用MQ默认不优先走MQ。</span>
<span class="cm"> coder: MessageRecord的解析器类必须是org.redkale.mq.MessageCoder&lt;MessageRecord&gt;的实现类, </span>
<span class="cm"> 可对数据包进行加密解密默认值org.redkale.mq.MessageRecordCoder</span>
<span class="cm"> MQ节点下的子节点配置没有固定格式, 根据MessageAgent实现方的定义来配置</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">mq</span> <span class="na">name</span><span class="o">=</span><span class="s">""</span> <span class="na">type</span><span class="o">=</span><span class="s">"org.redkalex.mq.kafka.KafkaMessageAgent"</span> <span class="na">rpcfirst</span><span class="o">=</span><span class="s">"false"</span> <span class="na">threads</span><span class="o">=</span><span class="s">"4"</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">servers</span> <span class="na">value</span><span class="o">=</span><span class="s">"127.0.0.1:9101"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 加载所有的MessageConsumer实例;</span>
<span class="cm"> autoload="true" 默认值. 自动加载classpath下所有的MessageConsumer类 </span>
<span class="cm"> autoload="false" 需要显著的指定MessageConsumer类</span>
<span class="cm"> includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="cm"> excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 </span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">consumer</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="na">includes</span><span class="o">=</span><span class="s">""</span> <span class="na">excludes</span><span class="o">=</span><span class="s">""</span><span class="p">/&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> MQ实现方的配置项</span>
<span class="cm"> type: 配置项类型值只能是consumer或producer</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">config</span> <span class="na">type</span><span class="o">=</span><span class="s">"consumer"</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">config</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">config</span> <span class="na">type</span><span class="o">=</span><span class="s">"producer"</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">config</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">mq</span><span class="p">&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> 一个组包含多个node 同一Service服务可以由多个进程提供这些进程称为一个GROUP且同一GROUP内的进程必须在同一机房或局域网内</span>
<span class="cm"> name: 服务组ID长度不能超过11个字节. 默认为空字符串。 注意: name不能包含$符号。</span>
<span class="cm"> protocol 值范围UDP TCP 默认TCP</span>
<span class="cm"> 注意: 一个node只能所属一个group。只要存在protocol=SNCP的Server节点信息 就必须有group节点信息。</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">group</span> <span class="na">name</span><span class="o">=</span><span class="s">""</span> <span class="na">protocol</span><span class="o">=</span><span class="s">"TCP"</span><span class="p">&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> 需要将本地node的addr与port列在此处。</span>
<span class="cm"> 同一个&lt;node&gt;节点值只能存在一个&lt;group&gt;节点内即同一个addr+port只能属于一个group。</span>
<span class="cm"> addr: required IP地址</span>
<span class="cm"> port: required 端口</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">node</span> <span class="na">addr</span><span class="o">=</span><span class="s">"127.0.0.1"</span> <span class="na">port</span><span class="o">=</span><span class="s">"7070"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">group</span><span class="p">&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> Application启动的监听事件,可配置多个节点</span>
<span class="cm"> value: 类名必须是ApplicationListener的子类</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">listener</span> <span class="na">value</span><span class="o">=</span><span class="s">"org.redkalex.xxx.XXXApplicationListener"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 【节点全局唯一】</span>
<span class="cm"> 全局的参数配置, 可以通过@Resource(name="property.xxxxxx") 进行注入&lt;property&gt;的信息, 被注解的字段类型只能是String、primitive class</span>
<span class="cm"> 如果name是system.property.开头的值将会在进程启动时进行System.setProperty("yyyy", "YYYYYY")操作。</span>
<span class="cm"> 如果name是mimetype.property.开头的值将会在进程启动时进行MimeType.add("yyyy", "YYYYYY")操作。</span>
<span class="cm"> 先加载子节点property再加载load文件 最后加载agent的实现子类。</span>
<span class="cm"> load: 加载文件,多个用;隔开。</span>
<span class="cm"> 其他属性: 供org.redkale.boot.PropertiesAgentProvider使用判断</span>
<span class="cm"> 默认置入的system.property.的有:</span>
<span class="cm"> System.setProperty("redkale.convert.pool.size", "128");</span>
<span class="cm"> System.setProperty("redkale.convert.writer.buffer.defsize", "4096");</span>
<span class="cm"> </span>
<span class="cm"> &lt;properties&gt;节点下也可包含非&lt;property&gt;节点.</span>
<span class="cm">&lt;property&gt;其节点可以通过@Resource(name="properties.xxxxxx")进行注入, 被注解的字段类型只能是AnyValue、AnyValue[]</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">properties</span> <span class="na">load</span><span class="o">=</span><span class="s">"config.properties"</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"system.property.yyyy"</span> <span class="na">value</span><span class="o">=</span><span class="s">"YYYYYY"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">properties</span><span class="p">&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> protocol: required server所启动的协议Redkale内置的有HTTP、SNCP、WATCH。协议均使用TCP实现; WATCH服务只能存在一个。</span>
<span class="cm"> name: 服务的名称用于监控识别一个配置文件中的server.name不能重复,命名规则: 字母、数字、下划线</span>
<span class="cm"> host: 服务所占address 默认: 0.0.0.0</span>
<span class="cm"> port: required 服务所占端口 </span>
<span class="cm"> root: 如果是web类型服务则包含页面 默认:{APP_HOME}/root</span>
<span class="cm"> lib: server额外的class目录 默认为${APP_HOME}/libs/*; </span>
<span class="cm"> excludelibs: 排除lib.path与excludes中的正则表达式匹配的路径, 多个正则表达式用分号;隔开</span>
<span class="cm"> charset: 文本编码, 默认: UTF-8</span>
<span class="cm"> backlog: 默认10K</span>
<span class="cm"> maxconns 最大连接数, 小于1表示无限制 默认: 0</span>
<span class="cm"> maxbody: request.body最大值 默认: 256K</span>
<span class="cm"> bufferCapacity: ByteBuffer的初始化大小 TCP默认: 32K; (HTTP 2.0、WebSocket必须要16k以上); UDP默认: 8K</span>
<span class="cm"> bufferPoolSize ByteBuffer池的大小默认: 线程数*4</span>
<span class="cm"> responsePoolSize Response池的大小默认: 1024</span>
<span class="cm"> aliveTimeoutSeconds: KeepAlive读操作超时秒数 默认30 0表示永久不超时; -1表示禁止KeepAlive</span>
<span class="cm"> readTimeoutSeconds: 读操作超时秒数, 默认0 0表示永久不超时</span>
<span class="cm"> writeTimeoutSeconds: 写操作超时秒数, 默认0 0表示永久不超时</span>
<span class="cm"> interceptor: 启动/关闭NodeServer时被调用的拦截器实现类必须是org.redkale.boot.NodeInterceptor的子类默认为null</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">server</span> <span class="na">protocol</span><span class="o">=</span><span class="s">"HTTP"</span> <span class="na">host</span><span class="o">=</span><span class="s">"127.0.0.1"</span> <span class="na">port</span><span class="o">=</span><span class="s">"6060"</span> <span class="na">root</span><span class="o">=</span><span class="s">"root"</span> <span class="na">lib</span><span class="o">=</span><span class="s">""</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 【节点在&lt;server&gt;中唯一】</span>
<span class="cm"> builder: 创建SSLContext的实现类, 可自定义必须是org.redkale.net.SSLBuilder的子类</span>
<span class="cm"> sslProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.OpenSSLProvider、org.bouncycastle.jce.provider.BouncyCastleProvider</span>
<span class="cm"> jsseProvider: java.security.Provider自定义的实现类如第三方: org.conscrypt.JSSEProvider、 org.bouncycastle.jce.provider.BouncyCastleJsseProvider</span>
<span class="cm"> protocol: TLS版本默认值: TLS</span>
<span class="cm"> protocols: 设置setEnabledProtocols, 多个用,隔开 如: TLSv1.2,TLSv1.3</span>
<span class="cm"> clientAuth: WANT/NEED/NONE, 默认值: NONE</span>
<span class="cm"> ciphers: 设置setEnabledCipherSuites, 多个用,隔开 如: TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256</span>
<span class="cm"> keystorePass: KEY密码</span>
<span class="cm"> keystoreFile: KEY文件 .jks</span>
<span class="cm"> keystoreType: KEY类型 默认值为JKS</span>
<span class="cm"> keystoreAlgorithm: KEY文件的algorithm 默认值为SunX509</span>
<span class="cm"> truststorePass: TRUST密码</span>
<span class="cm"> truststoreFile: TRUST文件</span>
<span class="cm"> truststoreType: TRUST类型 默认值为JKS</span>
<span class="cm"> truststoreAlgorithm: TRUST文件的algorithm 默认值为SunX509</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">ssl</span> <span class="na">builder</span><span class="o">=</span><span class="s">""</span><span class="p">/&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 加载所有的Service服务;</span>
<span class="cm"> 在同一个进程中同一个name同一类型的Service将共用同一个实例</span>
<span class="cm"> autoload="true" 默认值. 自动加载classpath下所有的Service类 </span>
<span class="cm"> autoload="false" 需要显著的指定Service类</span>
<span class="cm"> mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式</span>
<span class="cm"> includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="cm"> excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 </span>
<span class="cm"> group: 所属组的节点, 不能指定多个group, 如果配置文件中存在多个SNCP协议的Server节点需要显式指定group属性.</span>
<span class="cm"> 当 protocol == SNCP 时 group表示当前Server与哪些节点组关联。</span>
<span class="cm"> 当 protocol != SNCP 时 group只能是空或者一个group的节点值。</span>
<span class="cm"> 特殊值"$remote", 视为通过第三方服务注册发现管理工具来获取远程模式的ip端口信息</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">services</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="na">includes</span><span class="o">=</span><span class="s">""</span> <span class="na">excludes</span><span class="o">=</span><span class="s">""</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- 显著加载指定的Service的接口类 --&gt;</span>
<span class="p">&lt;</span><span class="nt">service</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXX1Service"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> name: 显式指定name覆盖默认的空字符串值。 注意: name不能包含$符号。</span>
<span class="cm"> mq: 所属的MQ管理器当 protocol == SNCP 时该值才有效, 存在该属性表示Service的SNCP协议采用消息总线代理模式</span>
<span class="cm"> group: 显式指定group覆盖&lt;services&gt;节点的group默认值。</span>
<span class="cm"> ignore: 是否禁用, 默认为false。</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">service</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXX2Service"</span> <span class="na">name</span><span class="o">=</span><span class="s">""</span> <span class="na">group</span><span class="o">=</span><span class="s">"xxx"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!-- 给Service增加配置属性 --&gt;</span>
<span class="p">&lt;</span><span class="nt">service</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXX1Service"</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 --&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">service</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">services</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 加载所有的Filter服务;</span>
<span class="cm"> autoload="true" 默认值. </span>
<span class="cm"> autoload="false" 需要显著的指定Filter类</span>
<span class="cm"> includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="cm"> excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开 </span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">filters</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="na">includes</span><span class="o">=</span><span class="s">""</span> <span class="na">excludes</span><span class="o">=</span><span class="s">""</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 显著加载指定的Filter类</span>
<span class="cm"> value=: Filter类名。必须与Server的协议层相同HTTP必须是HttpFilter</span>
<span class="cm"> ignore: 是否禁用, 默认为false。</span>
<span class="cm"> --&gt;</span>
<span class="cm">&lt;!-- 显著加载指定的Filter类 --&gt;</span>
<span class="p">&lt;</span><span class="nt">filter</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXX1Filter"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!-- 给Filter增加配置属性 --&gt;</span>
<span class="p">&lt;</span><span class="nt">filter</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXX12Filter"</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- property值在public void init(AnyValue conf)方法中可以通过AnyValue properties=conf.getAnyValue("properties")获取 --&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">filter</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">filters</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> REST的核心配置项</span>
<span class="cm"> 当Server为HTTP协议时, rest节点才有效。存在[rest]节点则Server启动时会加载REST服务, 节点可以多个,(WATCH协议不需要设置系统会自动生成)</span>
<span class="cm"> path: servlet的ContextPath前缀 默认为空 【注: 开启MQ时,该字段失效】</span>
<span class="cm"> base: REST服务的BaseServlet必须是 org.redkale.net.http.HttpServlet 的子类,且子类必须标记@HttpUserType。</span>
<span class="cm"> mq: 所属的MQ管理器, 存在该属性表示RestService的请求来自于消息总线 【注: 开启MQ时,path字段失效】</span>
<span class="cm"> autoload默认值"true" 默认值. 加载当前server所能使用的Servce对象; </span>
<span class="cm"> includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="cm"> excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">rest</span> <span class="na">path</span><span class="o">=</span><span class="s">"/pipes"</span> <span class="na">base</span><span class="o">=</span><span class="s">"org.redkale.net.http.HttpServlet"</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="na">includes</span><span class="o">=</span><span class="s">""</span> <span class="na">excludes</span><span class="o">=</span><span class="s">""</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> value: Service类名列出的表示必须被加载的Service对象</span>
<span class="cm"> ignore: 是否忽略设置为true则不会加载该Service对象默认值为false</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">service</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXXXService"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> value: WebSocket类名列出的表示必须被加载且标记为@RestWebSocket的WebSocket对象</span>
<span class="cm"> ignore: 是否忽略设置为true则不会加载该RestWebSocket对象默认值为false</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">websocket</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXXXRestWebSocket"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">rest</span><span class="p">&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> 【节点在&lt;server&gt;中唯一】</span>
<span class="cm"> 当Server为HTTP协议时, request节点才有效。</span>
<span class="cm"> remoteaddr 节点: 替换请求方节点的IP地址 通常请求方是由nginx等web静态服务器转发过的则需要配置该节点。</span>
<span class="cm"> 且value值只能是以request.headers.开头表示从request.headers中获取对应的header值。</span>
<span class="cm"> locale value值必须是request.headers.或request.parameters.开头。</span>
<span class="cm"> 例如下面例子获取request.getRemoteAddr()值如果header存在X-RemoteAddress值则返回X-RemoteAddress值不存在返回getRemoteAddress()。</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">request</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">remoteaddr</span> <span class="na">value</span><span class="o">=</span><span class="s">"request.headers.X-RemoteAddress"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">locale</span> <span class="na">value</span><span class="o">=</span><span class="s">"request.headers.locale"</span> <span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">rpc</span> <span class="na">authenticator</span><span class="o">=</span><span class="s">"org.redkale.net.http.HttpRpcAuthenticator的实现类"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">request</span><span class="p">&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> 【节点在&lt;server&gt;中唯一】</span>
<span class="cm"> 当Server为HTTP协议时, response节点才有效。</span>
<span class="cm"> contenttype: plain值为调用finish时的ContentType; 默认值: text/plain; charset=utf-8</span>
<span class="cm"> json值为调用finishJson时的ContentType; 默认值: application/json; charset=utf-8</span>
<span class="cm"> defcookie 节点: 当response里输出的cookie没有指定domain 和path时使用该节点的默认值。</span>
<span class="cm"> addheader、setheader 的value值以request.parameters.开头则表示从request.parameters中获取对应的parameter值</span>
<span class="cm"> addheader、setheader 的value值以request.headers.开头则表示从request.headers中获取对应的header值</span>
<span class="cm"> 例如下面例子是在Response输出header时添加两个header一个addHeader 一个setHeader</span>
<span class="cm"> options 节点: 设置了该节点且auto=true当request的method=OPTIONS自动设置addheader、setheader并返回200状态码</span>
<span class="cm"> date 节点: 设置了该节点且period有值(单位:毫秒);返回response会包含Date头信息默认为period=0</span>
<span class="cm"> period=0表示实时获取当前时间;</span>
<span class="cm"> period&lt;0表示不设置date;</span>
<span class="cm"> period&gt;0表示定时获取时间; 设置1000表示每秒刷新Date时间</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">response</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">content-type</span> <span class="na">plain</span><span class="o">=</span><span class="s">"text/plain; charset=utf-8"</span> <span class="na">json</span><span class="o">=</span><span class="s">"application/json; charset=utf-8"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">defcookie</span> <span class="na">domain</span><span class="o">=</span><span class="s">""</span> <span class="na">path</span><span class="o">=</span><span class="s">""</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">addheader</span> <span class="na">name</span><span class="o">=</span><span class="s">"Access-Control-Allow-Origin"</span> <span class="na">value</span><span class="o">=</span><span class="s">"request.headers.Origin"</span> <span class="p">/&gt;</span> <span class="cm">&lt;!-- 可多节点 --&gt;</span>
<span class="p">&lt;</span><span class="nt">setheader</span> <span class="na">name</span><span class="o">=</span><span class="s">"Access-Control-Allow-Headers"</span> <span class="na">value</span><span class="o">=</span><span class="s">"request.headers.Access-Control-Request-Headers"</span><span class="p">/&gt;</span> <span class="cm">&lt;!-- 可多节点 --&gt;</span>
<span class="p">&lt;</span><span class="nt">setheader</span> <span class="na">name</span><span class="o">=</span><span class="s">"Access-Control-Allow-Credentials"</span> <span class="na">value</span><span class="o">=</span><span class="s">"true"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">options</span> <span class="na">auto</span><span class="o">=</span><span class="s">"true"</span> <span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">date</span> <span class="na">period</span><span class="o">=</span><span class="s">"0"</span> <span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">response</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 【节点在&lt;server&gt;中唯一】</span>
<span class="cm"> 当Server为HTTP协议时render才有效. 指定输出引擎的实现类</span>
<span class="cm"> value: 输出引擎的实现类, 必须是org.redkale.net.http.HttpRender的子类</span>
<span class="cm"> suffixs: 引擎文件名后缀,多个用;隔开,默认值为: .htel</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">render</span> <span class="na">value</span><span class="o">=</span><span class="s">"org.redkalex.htel.HttpTemplateRender"</span> <span class="na">suffixs</span><span class="o">=</span><span class="s">".htel"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 【节点在&lt;server&gt;中唯一】</span>
<span class="cm"> 当Server为HTTP协议时ResourceServlet才有效. 默认存在一个有默认属性的resource-servlet节点</span>
<span class="cm"> webroot: web资源的根目录, 默认取server节点中的root值</span>
<span class="cm"> servlet: 静态资源HttpServlet的实现默认使用HttpResourceServlet</span>
<span class="cm"> index : 启始页默认值index.html</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">resource-servlet</span> <span class="na">webroot</span><span class="o">=</span><span class="s">"root"</span> <span class="na">index</span><span class="o">=</span><span class="s">"index.html"</span><span class="p">&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> 【节点在&lt;resource-servlet&gt;中唯一】</span>
<span class="cm"> 资源缓存的配置, 默认存在一个含默认属性的caches节点</span>
<span class="cm"> limit: 资源缓存最大容量, 默认: 0, 为0表示不缓存 单位可以是B、K、M、G不区分大小写</span>
<span class="cm"> lengthmax: 可缓存的文件大小上限, 默认: 1M超过1M的文件不会被缓存</span>
<span class="cm"> watch: 是否监控缓存文件的变化, 默认为false不监控</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">cache</span> <span class="na">limit</span><span class="o">=</span><span class="s">"0M"</span> <span class="na">lengthmax</span><span class="o">=</span><span class="s">"1M"</span> <span class="na">watch</span><span class="o">=</span><span class="s">"false"</span><span class="p">/&gt;</span>
<span class="cm">&lt;!--</span>
<span class="cm"> 支持类似nginx中的rewrite 目前只支持静态资源对静态资源的跳转。</span>
<span class="cm"> type: 匹配的类型, 目前只支持location(匹配requestURI), 默认: location</span>
<span class="cm"> match: 匹配的正则表达式</span>
<span class="cm"> forward: 需跳转后的资源链接</span>
<span class="cm"> 例如下面例子是将/xxx-yyy.html的页面全部跳转到/xxx.html</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">rewrite</span> <span class="na">type</span><span class="o">=</span><span class="s">"location"</span> <span class="na">match</span><span class="o">=</span><span class="s">"^/([^-]+)-[^-\.]+\.html(.*)"</span> <span class="na">forward</span><span class="o">=</span><span class="s">"/$1.html"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">resource-servlet</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 加载所有的Servlet服务;</span>
<span class="cm"> path: servlet的ContextPath前缀 默认为空</span>
<span class="cm"> autoload="true" 默认值. 自动加载classpath下所有的Servlet类 </span>
<span class="cm"> autoload="false" 需要显著的指定Service类</span>
<span class="cm"> includes 当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="cm"> excludes 当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">servlets</span> <span class="na">path</span><span class="o">=</span><span class="s">"/pipes"</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="na">includes</span><span class="o">=</span><span class="s">""</span> <span class="na">excludes</span><span class="o">=</span><span class="s">""</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- </span>
<span class="cm"> 显著加载指定的Servlet类</span>
<span class="cm"> value=: Servlet类名。必须与Server的协议层相同HTTP必须是HttpServlet</span>
<span class="cm"> ignore: 是否禁用, 默认为false。</span>
<span class="cm"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">servlet</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXX1Servlet"</span> <span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">servlet</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXX2Servlet"</span> <span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">servlet</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXX3Servlet"</span> <span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"xxxxxx"</span> <span class="na">value</span><span class="o">=</span><span class="s">"XXXXXXXX"</span><span class="p">/&gt;</span>
<span class="p">&lt;</span><span class="nt">property</span> <span class="na">name</span><span class="o">=</span><span class="s">"yyyyyy"</span> <span class="na">value</span><span class="o">=</span><span class="s">"YYYYYYYY"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">servlet</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">servlets</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">server</span><span class="p">&gt;</span>
<span class="p">&lt;</span><span class="nt">server</span> <span class="na">protocol</span><span class="o">=</span><span class="s">"SNCP"</span> <span class="na">host</span><span class="o">=</span><span class="s">"127.0.0.1"</span> <span class="na">port</span><span class="o">=</span><span class="s">"7070"</span> <span class="na">root</span><span class="o">=</span><span class="s">"root"</span> <span class="na">lib</span><span class="o">=</span><span class="s">""</span><span class="p">&gt;</span>
<span class="cm">&lt;!-- 参数完全同上 --&gt;</span>
<span class="p">&lt;</span><span class="nt">services</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="na">includes</span><span class="o">=</span><span class="s">""</span> <span class="na">excludes</span><span class="o">=</span><span class="s">""</span> <span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">server</span><span class="p">&gt;</span>
<span class="p">&lt;/</span><span class="nt">application</span><span class="p">&gt;</span>
</pre></div>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,642 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="service_intro" class="anchor" href="#" aria-hidden="true"></a>Service 组件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Service 是Redkale最核心的组件依赖于Convert、SNCP协议、Resource依赖注入。Service主要处理业务逻辑和操作数据层是微服务架构中的单一原子服务。每一个Service实例分两种模式: <b>本地模式</b><b>远程模式</b>。其模式由 conf/application.xml 文件来配置。开发人员在调用过程中通常不需要区分当前Service实例是哪种模式。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为了能确保本地模式与远程模式自由切换对Service的实现类有一定的约束: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、Service实现类会被继承不能修饰为 <b>final</b> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、带@RpcMultiRun注解的方法会被重载不能修饰为 <b>final</b> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Redkale进程启动时扫描可加载的Service实现类根据配置文件配置的模式采用ASM技术动态生成相应的Service临时类进行实例化并注册到ResourceFactory同其他Service、Servlet依赖注入。
</p>
<h3><a id="service_local" class="anchor" href="#" aria-hidden="true"></a>Service 本地模式</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以一个简单的UserService类范例来说明动态生成的两种模式临时类。UserService提供查询用户、注册、登陆、修改用户名功能:</br></p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="c1">//用户简单信息缓存</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">UserInfo</span><span class="o">&gt;</span> <span class="n">users</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ConcurrentHashMap</span><span class="o">&lt;&gt;();</span>
<span class="c1">//存放手机号码与userid的对应关系</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">Long</span><span class="o">,</span> <span class="n">Integer</span><span class="o">&gt;</span> <span class="n">mobileToUserids</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ConcurrentHashMap</span><span class="o">&lt;&gt;();</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="n">String</span> <span class="nf">testLocalNodeName</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">&quot;本地节点名&quot;</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//查询用户信息</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">findUserInfo</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">users</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">userid</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//根据手机号码查询用户ID没有返回0</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">findUserid</span><span class="o">(</span><span class="kt">long</span> <span class="n">mobile</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Integer</span> <span class="n">rs</span> <span class="o">=</span> <span class="n">mobileToUserids</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">mobile</span><span class="o">);</span>
<span class="k">return</span> <span class="n">rs</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="mi">0</span> <span class="o">:</span> <span class="n">rs</span><span class="o">;</span>
<span class="o">}</span>
<span class="c1">//缓存用户信息</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">putUserInfo</span><span class="o">(</span><span class="n">UserInfo</span> <span class="n">user</span><span class="o">)</span> <span class="o">{</span>
<span class="n">users</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">(),</span> <span class="n">user</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">user</span><span class="o">.</span><span class="na">getMobile</span><span class="o">()</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="o">)</span> <span class="n">mobileToUserids</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">user</span><span class="o">.</span><span class="na">getMobile</span><span class="o">(),</span> <span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">//登录</span>
<span class="kd">public</span> <span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="nf">login</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="c1">// 登陆逻辑</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">&lt;&gt;(</span><span class="mi">100</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//注册</span>
<span class="nd">@RpcMultiRun</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">register</span><span class="o">(</span><span class="n">UserInfo</span> <span class="n">user</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">users</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">(),</span> <span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//更新用户名</span>
<span class="nd">@RpcMultiRun</span><span class="o">(</span><span class="n">diffrun</span> <span class="o">=</span> <span class="kc">false</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">updateUsername</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">username</span><span class="o">)</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="k">this</span><span class="o">.</span><span class="na">users</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">userid</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">user</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="n">user</span><span class="o">.</span><span class="na">setUsername</span><span class="o">(</span><span class="n">username</span><span class="o">);</span>
<span class="k">return</span> <span class="n">user</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态生成的本地模式UserService</p>
<div class="highlight"><pre><span></span><span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">""</span><span class="o">)</span>
<span class="nd">@SncpDyn</span><span class="o">(</span><span class="n">remote</span> <span class="o">=</span> <span class="kc">false</span><span class="o">)</span>
<span class="nd">@ResourceType</span><span class="o">(</span><span class="n">UserService</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">_DynLocalUserService</span> <span class="kd">extends</span> <span class="n">UserService</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">SncpClient</span> <span class="n">_redkale_client</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">register</span><span class="o">(</span><span class="n">UserInfo</span> <span class="n">user</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">_redkale_register</span><span class="o">(</span><span class="kc">true</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@SncpDyn</span><span class="o">(</span><span class="n">remote</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">_redkale_register</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">selfrunnable</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">samerunnable</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">diffrunnable</span><span class="o">,</span> <span class="n">UserInfo</span> <span class="n">user</span><span class="o">)</span> <span class="o">{</span>
<span class="k">if</span> <span class="o">(</span><span class="n">selfrunnable</span><span class="o">)</span> <span class="kd">super</span><span class="o">.</span><span class="na">register</span><span class="o">(</span><span class="n">user</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">_redkale_client</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">samerunnable</span><span class="o">)</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remoteSameGroup</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="n">user</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">diffrunnable</span><span class="o">)</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remoteDiffGroup</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">updateUsername</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">username</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">this</span><span class="o">.</span><span class="na">_redkale_updateUsername</span><span class="o">(</span><span class="kc">true</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="n">userid</span><span class="o">,</span> <span class="n">username</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@SncpDyn</span><span class="o">(</span><span class="n">remote</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">1</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">_redkale_updateUsername</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">selfrunnable</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">samerunnable</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">diffrunnable</span><span class="o">,</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">username</span><span class="o">)</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">rs</span> <span class="o">=</span> <span class="kd">super</span><span class="o">.</span><span class="na">updateUsername</span><span class="o">(</span><span class="n">userid</span><span class="o">,</span> <span class="n">username</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">_redkale_client</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
<span class="k">if</span> <span class="o">(</span><span class="n">samerunnable</span><span class="o">)</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remoteSameGroup</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="n">userid</span><span class="o">,</span> <span class="n">username</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">diffrunnable</span><span class="o">)</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remoteDiffGroup</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">true</span><span class="o">,</span> <span class="kc">false</span><span class="o">,</span> <span class="n">userid</span><span class="o">,</span> <span class="n">username</span><span class="o">);</span>
<span class="k">return</span> <span class="n">rs</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上等价的代码可以看出来本地模式Service会重载被@RpcMultiRun注解的方法。@RpcMultiRun有以下几个参数: </p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nd">@interface</span> <span class="n">RpcMultiRun</span> <span class="o">{</span>
<span class="kt">boolean</span> <span class="nf">selfrun</span><span class="o">()</span> <span class="k">default</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">//当前本地实例是否运行指定操作只有当指定操作的方法的返回值为void时该值才能为true否则忽略。</span>
<span class="kt">boolean</span> <span class="nf">samerun</span><span class="o">()</span> <span class="k">default</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">//是否同组节点运行指定操作</span>
<span class="kt">boolean</span> <span class="nf">diffrun</span><span class="o">()</span> <span class="k">default</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">//是否不同组节点运行指定操作</span>
<span class="kt">boolean</span> <span class="nf">async</span><span class="o">()</span> <span class="k">default</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">//分布式运行是否采用异步模式</span>
<span class="o">}</span> </pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在动态生成的远程模式UserService时会根据不同参数生成相应的方法。若一个Service类没有含@RpcMultiRun注解的方法那么动态类只会重载toString方法。当UserService服务仅需要部署一个进程由于没有其他等同服务的进程因此在UserService实例化时_redkale_client会赋值为null。</p>
<div class="highlight"><pre><span class="nt">&lt;resources&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;GROUP-A&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.10.111&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.10.112&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.10.113&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;GROUP-B&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.20.121&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.20.122&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;group</span> <span class="na">name=</span><span class="s">&quot;GROUP-C&quot;</span><span class="nt">&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.30.131&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;node</span> <span class="na">addr=</span><span class="s">&quot;192.168.30.132&quot;</span> <span class="na">port=</span><span class="s">&quot;7070&quot;</span><span class="nt">/&gt;</span>
<span class="nt">&lt;/group&gt;</span>
<span class="nt">&lt;/resources&gt;</span>
<span class="c">&lt;!-- 配置UserService的节点组 ---&gt;</span>
<span class="nt">&lt;service</span> <span class="na">name=</span><span class="s">&quot;&quot;</span> <span class="na">value=</span><span class="s">&quot;org.redkale.demo.user.UserService&quot;</span> <span class="na">groups=</span><span class="s">&quot;GROUP-A;GROUP-B;GROUP-C&quot;</span><span class="nt">/&gt;</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上配置若当前进程所在IP是192.168.10.111则UserService采用本地模式加载。执行register方法时 先本地执行超类的register然后远程执行同组的进程(192.168.10.112、192.168.10.113),最后远程执行异组的进程(192.168.20.121、192.168.20.122、192.168.30.131、192.168.30.132)。若当前进程所在IP是192.168.10.100则UserService采用远程模式加载。需要注意的一点是每个IP所在的服务必须开通SNCP协议服务以便能接收远程的调用请求。</p>
<h3><a id="service_remote" class="anchor" href="#" aria-hidden="true"></a>Service 远程模式</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态生成的远程模式UserService</p>
<div class="highlight"><pre><span></span><span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">""</span><span class="o">)</span>
<span class="nd">@SncpDyn</span><span class="o">(</span><span class="n">remote</span> <span class="o">=</span> <span class="kc">true</span><span class="o">)</span>
<span class="nd">@ResourceType</span><span class="o">(</span><span class="n">UserService</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">final</span> <span class="kd">class</span> <span class="nc">_DynRemoteUserService</span> <span class="kd">extends</span> <span class="n">UserService</span> <span class="o">{</span>
<span class="kd">private</span> <span class="n">SncpClient</span> <span class="n">_redkale_client</span><span class="o">;</span>
<span class="nd">@SncpDyn</span><span class="o">(</span><span class="n">remote</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">0</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">_redkale_register</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">selfrunnable</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">samerunnable</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">diffrunnable</span><span class="o">,</span> <span class="n">UserInfo</span> <span class="n">user</span><span class="o">)</span> <span class="o">{</span>
<span class="n">_redkale_client</span><span class="o">.</span><span class="na">remote</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">selfrunnable</span><span class="o">,</span> <span class="n">samerunnable</span><span class="o">,</span> <span class="n">diffrunnable</span><span class="o">,</span> <span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@SncpDyn</span><span class="o">(</span><span class="n">remote</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">index</span> <span class="o">=</span> <span class="mi">1</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">_redkale_updateUsername</span><span class="o">(</span><span class="kt">boolean</span> <span class="n">selfrunnable</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">samerunnable</span><span class="o">,</span> <span class="kt">boolean</span> <span class="n">diffrunnable</span><span class="o">,</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">username</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remote</span><span class="o">(</span><span class="mi">1</span><span class="o">,</span> <span class="n">selfrunnable</span><span class="o">,</span> <span class="n">samerunnable</span><span class="o">,</span> <span class="n">diffrunnable</span><span class="o">,</span> <span class="n">userid</span><span class="o">,</span> <span class="n">username</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">findUserInfo</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remote</span><span class="o">(</span><span class="mi">2</span><span class="o">,</span> <span class="n">userid</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">int</span> <span class="nf">findUserid</span><span class="o">(</span><span class="kt">long</span> <span class="n">mobile</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remote</span><span class="o">(</span><span class="mi">3</span><span class="o">,</span> <span class="n">mobile</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="nf">login</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remote</span><span class="o">(</span><span class="mi">4</span><span class="o">,</span> <span class="n">bean</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">putUserInfo</span><span class="o">(</span><span class="n">UserInfo</span> <span class="n">user</span><span class="o">)</span> <span class="o">{</span>
<span class="n">_redkale_client</span><span class="o">.</span><span class="na">remote</span><span class="o">(</span><span class="mi">5</span><span class="o">,</span> <span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">register</span><span class="o">(</span><span class="n">UserInfo</span> <span class="n">user</span><span class="o">)</span> <span class="o">{</span>
<span class="n">_redkale_client</span><span class="o">.</span><span class="na">remote</span><span class="o">(</span><span class="mi">6</span><span class="o">,</span> <span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">updateUsername</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">username</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">_redkale_client</span><span class="o">.</span><span class="na">remote</span><span class="o">(</span><span class="mi">7</span><span class="o">,</span> <span class="n">userid</span><span class="o">,</span> <span class="n">username</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上代码可以看出来远程模式Service是根据本地模式Service临时类动态生成的。远程类执行方法时通过SNCP协议将参数序列化并带上当前方法信息传输到远程服务器上执行完后将结果流反序列化并返回, 其流程与WebService类似。</p>
<p id="service_dyncall">&nbsp;&nbsp;<b>远程模式的@RpcCall回调</b> </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与WebService的区别除了更具性能的二进制的数据格式更差异的是远程模式的Service允许修改参数本身的内容。范例如下</p>
<div class="highlight"><pre><span class="cm">/**</span>
<span class="cm"> * 由于该方法在处理过程中修改了参数bean的内容为了保证本地模式与远程模式的一致性需要提供@RpcCall回调接口</span>
<span class="cm"> *</span>
<span class="cm"> * @param bean</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">public</span> <span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="nf">login</span><span class="o">(</span><span class="nd">@RpcCall</span><span class="o">(</span><span class="n">RpcCallLoginBeanAttribute</span><span class="o">.</span><span class="k">class</span><span class="o">)</span> <span class="n">LoginBean</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setLogintime</span><span class="o">(</span><span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">());</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setSessionid</span><span class="o">(</span><span class="s">&quot;SID&quot;</span> <span class="o">+</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">());</span>
<span class="c1">// 登陆逻辑</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">&lt;&gt;(</span><span class="mi">100</span><span class="o">);</span>
<span class="o">}</span>
<span class="cm">/** RpcCallLoginBeanAttribute 的实现 **/</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">RpcCallLoginBeanAttribute</span> <span class="kd">implements</span> <span class="n">Attribute</span><span class="o">&lt;</span><span class="n">LoginBean</span><span class="o">,</span> <span class="n">Object</span><span class="o">[]&gt;</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">Object</span><span class="o">[]</span> <span class="nf">get</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">obj</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">Object</span><span class="o">[]{</span><span class="n">obj</span><span class="o">.</span><span class="na">getLogintime</span><span class="o">(),</span> <span class="n">obj</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">()};</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">set</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">obj</span><span class="o">,</span> <span class="n">Object</span><span class="o">[]</span> <span class="n">value</span><span class="o">)</span> <span class="o">{</span>
<span class="n">obj</span><span class="o">.</span><span class="na">setLogintime</span><span class="o">((</span><span class="n">Long</span><span class="o">)</span> <span class="n">value</span><span class="o">[</span><span class="mi">0</span><span class="o">]);</span>
<span class="n">obj</span><span class="o">.</span><span class="na">setSessionid</span><span class="o">((</span><span class="n">String</span><span class="o">)</span> <span class="n">value</span><span class="o">[</span><span class="mi">1</span><span class="o">]);</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">Class</span><span class="o">&lt;?</span> <span class="kd">extends</span> <span class="n">Object</span><span class="o">[]&gt;</span> <span class="nf">type</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">Object</span><span class="o">[].</span><span class="k">class</span><span class="o">;</span> <span class="c1">//</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">Class</span><span class="o">&lt;</span><span class="n">LoginBean</span><span class="o">&gt;</span> <span class="nf">declaringClass</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">LoginBean</span><span class="o">.</span><span class="k">class</span><span class="o">;</span> <span class="c1">//</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">field</span><span class="o">()</span> <span class="o">{</span>
<span class="k">return</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//可以随意值</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;生成远程模式Service时发现参数带有@RpcCall注解的方法在远程调用返回结果时会进行回调处理。</p>
<h3><a id="service_rest" class="anchor" href="#" aria-hidden="true"></a>Service REST</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RestService提供类似Spring Boot的功能。开启REST功能的HTTP Server在实例化标记为@RestService的Service后自动生成对应的HttpServlet免去开发人员编写HttpServlet的工作量。主要通过<a href="/javadoc/org/redkale/net/http/RestService.html" target="_blank">@RestService</a><a href="/javadoc/org/redkale/net/http/RestMapping.html" target="_blank">@RestMapping</a><a href="/javadoc/org/redkale/net/http/RestParam.html" target="_blank">@RestParam</a>这三个注解来实现,同时为了获取其他类型的参数也有<a href="/javadoc/org/redkale/net/http/RestAddress.html" target="_blank">@RestAddress</a><a href="/javadoc/org/redkale/net/http/RestCookie.html" target="_blank">@RestCookie</a><a href="/javadoc/org/redkale/net/http/RestHeader.html" target="_blank">@RestHeader</a><a href="/javadoc/org/redkale/net/http/RestSessionid.html" target="_blank">@RestSessionid</a><a href="/javadoc/org/redkale/net/http/RestBody.html" target="_blank">@RestBody</a> 提供其扩展功能。<br/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;@RestService <br>
</p>
<div class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * 只能依附在Service类上name默认为Service的类名小写并去掉Service字样及后面的字符串 (如HelloService/HelloServiceImpl的默认路径为 hello)。</span>
<span class="cm"> */</span>
<span class="nd">@Target</span><span class="o">({</span><span class="n">TYPE</span><span class="o">})</span>
<span class="nd">@Retention</span><span class="o">(</span><span class="n">RUNTIME</span><span class="o">)</span>
<span class="kd">public</span> <span class="nd">@interface</span> <span class="n">RestService</span> <span class="o">{</span>
<span class="cm">/**</span>
<span class="cm"> * 模块名, 只能是模块名,不能含特殊字符, 只能小写字母+数字,且不能以数字开头</span>
<span class="cm"> *</span>
<span class="cm"> * @return 模块名</span>
<span class="cm"> */</span>
<span class="n">String</span> <span class="nf">name</span><span class="o">()</span> <span class="k">default</span> <span class="s">""</span><span class="o">;</span>
<span class="cm">/**</span>
<span class="cm"> * 目录名, 不能含特殊字符, 只能小写字母+数字,且不能以数字开头</span>
<span class="cm"> *</span>
<span class="cm"> * @return 目录名</span>
<span class="cm"> */</span>
<span class="n">String</span> <span class="nf">catalog</span><span class="o">()</span> <span class="k">default</span> <span class="s">""</span><span class="o">;</span>
<span class="cm">/**</span>
<span class="cm"> * 模块ID值鉴权时用到, 对应&amp;#64;WebServlet.moduleid</span>
<span class="cm"> *</span>
<span class="cm"> * @return 模块ID值</span>
<span class="cm"> */</span>
<span class="kt">int</span> <span class="nf">moduleid</span><span class="o">()</span> <span class="k">default</span> <span class="mi">0</span><span class="o">;</span>
<span class="cm">/**</span>
<span class="cm"> * 没有标记&amp;#64;RestMapping的方法是否转换 默认为false</span>
<span class="cm"> *</span>
<span class="cm"> * @return 默认false</span>
<span class="cm"> */</span>
<span class="kt">boolean</span> <span class="nf">automapping</span><span class="o">()</span> <span class="k">default</span> <span class="kc">false</span><span class="o">;</span>
<span class="cm">/**</span>
<span class="cm"> * 是否屏蔽该类的转换</span>
<span class="cm"> *</span>
<span class="cm"> * @return 默认false</span>
<span class="cm"> */</span>
<span class="kt">boolean</span> <span class="nf">ignore</span><span class="o">()</span> <span class="k">default</span> <span class="kc">false</span><span class="o">;</span>
<span class="cm">/**</span>
<span class="cm"> * 同&amp;#64;WebServlet的repair属性</span>
<span class="cm"> *</span>
<span class="cm"> * @return 默认true</span>
<span class="cm"> */</span>
<span class="kt">boolean</span> <span class="nf">repair</span><span class="o">()</span> <span class="k">default</span> <span class="kc">true</span><span class="o">;</span>
<span class="cm">/**</span>
<span class="cm"> * 备注描述</span>
<span class="cm"> *</span>
<span class="cm"> * @return 备注描述</span>
<span class="cm"> */</span>
<span class="n">String</span> <span class="nf">comment</span><span class="o">()</span> <span class="k">default</span> <span class="s">""</span><span class="o">;</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;@RestMapping <br>
</p>
<div class="highlight"><pre><span class="cm">/**</span>
<span class="cm"> * 只能依附在Service实现类的public方法上</span>
<span class="cm"> * value默认为&quot;/&quot; + Service的类名去掉Service及后面字样的小写字符串 (如HelloService的默认路径为/hello)。</span>
<span class="cm"> */</span>
<span class="nd">@Target</span><span class="o">({</span><span class="n">METHOD</span><span class="o">})</span>
<span class="kd">public</span> <span class="nd">@interface</span> <span class="n">RestMapping</span> <span class="o">{</span>
<span class="kt">boolean</span> <span class="nf">ignore</span><span class="o">()</span> <span class="k">default</span> <span class="kc">false</span><span class="o">;</span> <span class="c1">//是否屏蔽该方法的转换</span>
<span class="c1">//请求的方法名, 不能含特殊字符</span>
<span class="c1">//默认为方法名的小写(若方法名以createXXX、updateXXX、deleteXXX、queryXXX、findXXX且XXXService为Service的类名将只截取XXX之前)</span>
<span class="n">String</span> <span class="nf">name</span><span class="o">()</span> <span class="k">default</span> <span class="s">&quot;&quot;</span><span class="o">;</span>
<span class="n">String</span> <span class="nf">comment</span><span class="o">()</span> <span class="k">default</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//备注描述, 对应&#64;HttpMapping.comment </span>
<span class="kt">boolean</span> <span class="nf">auth</span><span class="o">()</span> <span class="k">default</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">//是否鉴权,默认需要鉴权, 对应&#64;HttpMapping.auth </span>
<span class="kt">int</span> <span class="nf">cacheseconds</span><span class="o">()</span> <span class="k">default</span> <span class="mi">0</span><span class="o">;</span> <span class="c1">//结果缓存的秒数, 为0表示不缓存, 对应&#64;HttpMapping.cacheseconds</span>
<span class="kt">int</span> <span class="nf">actionid</span><span class="o">()</span> <span class="k">default</span> <span class="mi">0</span><span class="o">;</span> <span class="c1">//操作ID值鉴权时用到, 对应&#64;HttpMapping.actionid</span>
<span class="n">String[]</span> <span class="nf">methods</span><span class="o">()</span> <span class="k">default</span> <span class="mi">{}</span><span class="o">;</span> <span class="c1">//允许方法(不区分大小写),如:GET/POST/PUT,为空表示允许所有方法, 对应&#64;HttpMapping.methods</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;@RestParam <br>
</p>
<div class="highlight"><pre><span class="cm">/**</span>
<span class="cm"> * 只能依附在Service类的方法的参数上</span>
<span class="cm"> */</span>
<span class="nd">@Target</span><span class="o">({</span><span class="n">PARAMETER</span><span class="o">})</span>
<span class="kd">public</span> <span class="nd">@interface</span> <span class="n">RestParam</span> <span class="o">{</span>
<span class="c1">//参数名 name='&'表示当前用户;</span>
<span class="c1">//参数名 name='#'表示截取uri最后一段; </span>
<span class="c1">//参数名 name='#xxx:'表示从uri中/pipes/xxx:v/截取xxx:的值; </span>
<span class="n">String</span> <span class="nf">name</span><span class="o">();</span>
<span class="kt">int</span> <span class="nf">radix</span><span class="o">()</span> <span class="k">default</span> <span class="mi">10</span><span class="o">;</span> <span class="c1">//转换数字byte/short/int/long时所用的进制数 默认10进制</span>
<span class="kt">boolean</span> <span class="nf">required</span><span class="o">()</span> <span class="k">default</span> <span class="kc">true</span><span class="o">;</span> <span class="c1">//参数是否必传 </span>
<span class="n">String</span> <span class="nf">comment</span><span class="o">()</span> <span class="k">default</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//备注描述, 对应&#64;HttpMapping.comment </span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;开启REST功能的步骤很简单<a href="redkale.html#redkale_confxml" target="_blank">application.xml</a><b>&lt;server&gt;</b> 节点下增加<b>&lt;rest&gt;</b>指明RestServlet的子类。<br/></p>
<div class="highlight"><pre><span></span><span class="c">&lt;!-- </span>
<span class="c"> REST的核心配置项, 存在[rest]节点则Server启动时会加载REST服务, 当Server为SNCP协议时,则SncpServer会变成REST的HttpServer, 节点可以多个</span>
<span class="c"> path: servlet的ContextPath前缀 默认为空</span>
<span class="c"> base: REST服务的BaseServlet必须是org.redkale.net.http.HttpServlet的子类且子类必须标记 @HttpUserType。</span>
<span class="c"> autoload默认值"true" 默认值. 加载当前server所能使用的Servce对象; </span>
<span class="c"> includes当autoload="true" 拉取类名与includes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="c"> excludes当autoload="true" 排除类名与excludes中的正则表达式匹配的类, 多个正则表达式用分号;隔开</span>
<span class="c">--&gt;</span>
<span class="p">&lt;</span><span class="nt">rest</span> <span class="na">path</span><span class="o">=</span><span class="s">"/pipes"</span> <span class="na">base</span><span class="o">=</span><span class="s">"org.redkale.net.http.HttpServlet"</span> <span class="na">autoload</span><span class="o">=</span><span class="s">"true"</span> <span class="na">includes</span><span class="o">=</span><span class="s">""</span> <span class="na">excludes</span><span class="o">=</span><span class="s">""</span><span class="p">&gt;</span>
<span class="c">&lt;!-- </span>
<span class="c"> value: Service类名列出的表示必须被加载的Service对象</span>
<span class="c"> ignore: 是否忽略设置为true则不会加载该Service对象默认值为false</span>
<span class="c"> --&gt;</span>
<span class="p">&lt;</span><span class="nt">service</span> <span class="na">value</span><span class="o">=</span><span class="s">"com.xxx.XXXXService"</span><span class="p">/&gt;</span>
<span class="p">&lt;/</span><span class="nt">rest</span><span class="p">&gt;</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Redkale中的REST并非严格遵循标准的REST规范在尽量满足规范的同时也考虑到开发的灵活性和简易性。以下通过简单的实例来说明其特性。<br/></p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常配置都需要编写一个 <b>org.redkale.net.http.HttpServlet</b> 子类主要用于获取当前用户信息和鉴权且必须指定具体的User对象类。开发者的实现类可以参考 <a href="https://github.com/redkale/redkale-demo/tree/master/src/org/redkale/demo/base" target="_blank">redkale-demo</a> 中的BaseServlet类以下是一个简单的范例: <br>
</p>
<div class="highlight"><pre><span></span><span class="nd">@HttpUserType</span><span class="o">(</span><span class="n">UserInfo</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">SimpleRestServlet</span> <span class="kd">extends</span> <span class="n">HttpServlet</span> <span class="o">{</span>
<span class="kd">protected</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">RetResult</span> <span class="n">RET_UNLOGIN</span> <span class="o">=</span> <span class="n">RetCodes</span><span class="o">.</span><span class="na">retResult</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">RET_USER_UNLOGIN</span><span class="o">);</span>
<span class="kd">protected</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">RetResult</span> <span class="n">RET_AUTHILLEGAL</span> <span class="o">=</span> <span class="n">RetCodes</span><span class="o">.</span><span class="na">retResult</span><span class="o">(</span><span class="n">RetCodes</span><span class="o">.</span><span class="na">RET_USER_AUTH_ILLEGAL</span><span class="o">);</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">UserService</span> <span class="n">userService</span><span class="o">;</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">preExecute</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">request</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="kd">final</span> <span class="n">String</span> <span class="n">sessionid</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">sessionid</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="n">request</span><span class="o">.</span><span class="na">setCurrentUser</span><span class="o">(</span><span class="n">userService</span><span class="o">.</span><span class="na">current</span><span class="o">(</span><span class="n">sessionid</span><span class="o">));</span>
<span class="n">response</span><span class="o">.</span><span class="na">nextEvent</span><span class="o">();</span>
<span class="o">}</span>
<span class="c1">//普通鉴权</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">authenticate</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">request</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">response</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">UserInfo</span> <span class="n">info</span> <span class="o">=</span> <span class="n">request</span><span class="o">.</span><span class="na">currentUser</span><span class="o">();</span>
<span class="k">if</span> <span class="o">(</span><span class="n">info</span> <span class="o">==</span> <span class="kc">null</span><span class="o">)</span> <span class="o">{</span>
<span class="n">response</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RET_UNLOGIN</span><span class="o">);</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span> <span class="k">else</span> <span class="k">if</span> <span class="o">(!</span><span class="n">info</span><span class="o">.</span><span class="na">checkAuth</span><span class="o">(</span><span class="n">request</span><span class="o">.</span><span class="na">getModuleid</span><span class="o">(),</span> <span class="n">request</span><span class="o">.</span><span class="na">getActionid</span><span class="o">()))</span> <span class="o">{</span>
<span class="n">response</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RET_AUTHILLEGAL</span><span class="o">);</span>
<span class="k">return</span><span class="o">;</span>
<span class="o">}</span>
<span class="n">response</span><span class="o">.</span><span class="na">nextEvent</span><span class="o">();</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REST的设置方式有两种: 一种采用默认REST注解一种是显式的设置。 <br>
</p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloBean</span> <span class="kd">implements</span> <span class="n">FilterBean</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">helloid</span><span class="o">;</span>
<span class="nd">@RestHeader</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;User-Agent&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">useragent</span><span class="o">;</span> <span class="c1">//从Http Header中获取浏览器信息</span>
<span class="nd">@RestCookie</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;hello-cookie&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">rescookie</span><span class="o">;</span> <span class="c1">//从Cookie中获取名为hello-cookie的值</span>
<span class="nd">@RestAddress</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">clientaddr</span><span class="o">;</span> <span class="c1">//客户端请求IP</span>
<span class="nd">@RestSessionid</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">sessionid</span><span class="o">;</span> <span class="c1">//用户Sessionid, 未登录时为null</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="o">}</span>
</pre></div>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloEntity</span> <span class="o">{</span>
<span class="nd">@Id</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">helloid</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">helloname</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">creator</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">updatetime</span><span class="o">;</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">createtime</span><span class="o">;</span>
<span class="nd">@RestHeader</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;hello-res&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">resname</span><span class="o">;</span>
<span class="nd">@RestAddress</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">clientaddr</span><span class="o">;</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="o">}</span>
</pre></div>
<div id="helloservice" class="highlight"><pre><span></span><span class="cm">/**</span>
<span class="cm"> * 类说明:</span>
<span class="cm"> * Flipper : Source组件中的翻页对象</span>
<span class="cm"> * UserInfo :当前用户类</span>
<span class="cm"> * HelloEntity: Hello模块的实体类</span>
<span class="cm"> * HelloBean: Hello模块实现FilterBean的过滤Bean类</span>
<span class="cm"> *</span>
<span class="cm"> */</span>
<span class="nd">@RestService</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;hello&quot;</span><span class="o">,</span> <span class="n">moduleid</span> <span class="o">=</span> <span class="mi">0</span><span class="o">,</span> <span class="n">repair</span> <span class="o">=</span> <span class="kc">true</span><span class="o">,</span> <span class="n">ignore</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello服务模块&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">HelloService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">DataSource</span> <span class="n">source</span><span class="o">;</span>
<span class="c1">//增加记录</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;create&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;创建Hello对象&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">RetResult</span><span class="o">&lt;</span><span class="n">HelloEntity</span><span class="o">&gt;</span> <span class="nf">createHello</span><span class="o">(</span><span class="n">UserInfo</span> <span class="n">info</span><span class="o">,</span> <span class="nd">@RestParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;bean&quot;</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象&quot;</span><span class="o">)</span> <span class="n">HelloEntity</span> <span class="n">entity</span><span class="o">)</span> <span class="o">{</span>
<span class="n">entity</span><span class="o">.</span><span class="na">setCreator</span><span class="o">(</span><span class="n">info</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="mi">0</span> <span class="o">:</span> <span class="n">info</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span> <span class="c1">//设置当前用户ID</span>
<span class="n">entity</span><span class="o">.</span><span class="na">setCreatetime</span><span class="o">(</span><span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">());</span>
<span class="n">source</span><span class="o">.</span><span class="na">insert</span><span class="o">(</span><span class="n">entity</span><span class="o">);</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">&lt;&gt;(</span><span class="n">entity</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//删除记录</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;delete&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;根据id删除Hello对象&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">deleteHello</span><span class="o">(</span><span class="nd">@RestParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;#&quot;</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象id&quot;</span><span class="o">)</span> <span class="kt">int</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//通过 /hello/delete/1234 删除对象</span>
<span class="n">source</span><span class="o">.</span><span class="na">delete</span><span class="o">(</span><span class="n">HelloEntity</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">id</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//修改记录</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;update&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;修改Hello对象&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">updateHello</span><span class="o">(</span><span class="nd">@RestParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;bean&quot;</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象&quot;</span><span class="o">)</span> <span class="n">HelloEntity</span> <span class="n">entity</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//通过 /hello/update?bean={...} 修改对象</span>
<span class="n">entity</span><span class="o">.</span><span class="na">setUpdatetime</span><span class="o">(</span><span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">());</span>
<span class="n">source</span><span class="o">.</span><span class="na">update</span><span class="o">(</span><span class="n">entity</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//查询列表</span>
<span class="c1">//通过 /hello/query/offset:0/limit:20?bean={...} 获取结果</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;query&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;查询Hello对象列表&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">Sheet</span><span class="o">&lt;</span><span class="n">HelloEntity</span><span class="o">&gt;</span> <span class="nf">queryHello</span><span class="o">(</span><span class="nd">@RestParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;bean&quot;</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;过滤条件&quot;</span><span class="o">)</span> <span class="n">HelloBean</span> <span class="n">bean</span><span class="o">,</span> <span class="n">Flipper</span> <span class="n">flipper</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">source</span><span class="o">.</span><span class="na">querySheet</span><span class="o">(</span><span class="n">HelloEntity</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">flipper</span><span class="o">,</span> <span class="n">bean</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//查询单个</span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;find&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;根据id查找单个Hello对象&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">HelloEntity</span> <span class="nf">findHello</span><span class="o">(</span><span class="nd">@RestParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;#&quot;</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象id&quot;</span><span class="o">)</span> <span class="kt">int</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//通过 /hello/find/1234 查询对象</span>
<span class="k">return</span> <span class="n">source</span><span class="o">.</span><span class="na">find</span><span class="o">(</span><span class="n">HelloEntity</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">id</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1"><b>//异步查询单个</b></span>
<span class="nd">@RestMapping</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;asyncfind&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;根据id查找单个Hello对象&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="n">CompletableFuture&lt;HelloEntity&gt;</span> <span class="nf">findAsyncHello</span><span class="o">(</span><span class="nd">@RestParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;#&quot;</span><span class="o">)</span> <span class="kt">int</span> <span class="n">id</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//通过 /pipes/hello/asyncfind/1234 查询对象</span>
<span class="k">return</span> <span class="n">source</span><span class="o">.</span><span class="na">findAsync</span><span class="o">(</span><span class="n">HelloEntity</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">id</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;根据默认命名规则可以看出以上范例生成的HttpServlet与去掉所有@RestService、@RestMapping、@RestParam后的Service生成的是完全相同的。 REST根据Service会动态生成HttpServlet以上范例自动生成的HttpServlet如下<br>
</p>
<div class="highlight"><pre><span></span><span class="nd">@WebServlet</span><span class="o">(</span><span class="n">value</span> <span class="o">=</span> <span class="o">{</span><span class="s">&quot;/hello/*&quot;</span><span class="o">},</span> <span class="n">repair</span> <span class="o">=</span> <span class="kc">true</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">_DynHelloRestServlet</span> <span class="kd">extends</span> <span class="n">SimpleRestServlet</span> <span class="o">{</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">HelloService</span> <span class="n">_service</span><span class="o">;</span>
<span class="nd">@Resource</span>
<span class="kd">private</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">String</span><span class="o">,</span> <span class="n">HelloService</span><span class="o">&gt;</span> <span class="n">_servicemap</span><span class="o">;</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/hello/create&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;创建Hello对象&quot;</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;bean&quot;</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">HelloEntity</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">create</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">HelloService</span> <span class="n">service</span> <span class="o">=</span> <span class="n">_servicemap</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">_service</span> <span class="o">:</span> <span class="n">_servicemap</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="n">Rest</span><span class="o">.</span><span class="na">REST_HEADER_RESOURCE_NAME</span><span class="o">,</span> <span class="s">&quot;&quot;</span><span class="o">));</span>
<span class="n">HelloEntity</span> <span class="n">bean</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getJsonParameter</span><span class="o">(</span><span class="n">HelloEntity</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="s">&quot;bean&quot;</span><span class="o">);</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setClientaddr</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRemoteAddr</span><span class="o">());</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setResname</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="s">&quot;hello-res&quot;</span><span class="o">));</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="n">currentUser</span><span class="o">(</span><span class="n">req</span><span class="o">);</span>
<span class="n">RetResult</span><span class="o">&lt;</span><span class="n">HelloEntity</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">createHello</span><span class="o">(</span><span class="n">user</span><span class="o">,</span> <span class="n">bean</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">result</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/hello/delete/&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;根据id删除Hello对象&quot;</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;#&quot;</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="kt">int</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象id&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">delete</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">HelloService</span> <span class="n">service</span> <span class="o">=</span> <span class="n">_servicemap</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">_service</span> <span class="o">:</span> <span class="n">_servicemap</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="n">Rest</span><span class="o">.</span><span class="na">REST_HEADER_RESOURCE_NAME</span><span class="o">,</span> <span class="s">&quot;&quot;</span><span class="o">));</span>
<span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRequstURILastPath</span><span class="o">());</span>
<span class="n">service</span><span class="o">.</span><span class="na">deleteHello</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetResult</span><span class="o">.</span><span class="na">success</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/hello/update&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;修改Hello对象&quot;</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;bean&quot;</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">HelloEntity</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">update</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">HelloService</span> <span class="n">service</span> <span class="o">=</span> <span class="n">_servicemap</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">_service</span> <span class="o">:</span> <span class="n">_servicemap</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="n">Rest</span><span class="o">.</span><span class="na">REST_HEADER_RESOURCE_NAME</span><span class="o">,</span> <span class="s">&quot;&quot;</span><span class="o">));</span>
<span class="n">HelloEntity</span> <span class="n">bean</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getJsonParameter</span><span class="o">(</span><span class="n">HelloEntity</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="s">&quot;bean&quot;</span><span class="o">);</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setClientaddr</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRemoteAddr</span><span class="o">());</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setResname</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="s">&quot;hello-res&quot;</span><span class="o">));</span>
<span class="n">service</span><span class="o">.</span><span class="na">updateHello</span><span class="o">(</span><span class="n">bean</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">RetResult</span><span class="o">.</span><span class="na">success</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/hello/query&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;查询Hello对象列表&quot;</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;bean&quot;</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">HelloBean</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;过滤条件&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">query</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">HelloService</span> <span class="n">service</span> <span class="o">=</span> <span class="n">_servicemap</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">_service</span> <span class="o">:</span> <span class="n">_servicemap</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="n">Rest</span><span class="o">.</span><span class="na">REST_HEADER_RESOURCE_NAME</span><span class="o">,</span> <span class="s">&quot;&quot;</span><span class="o">));</span>
<span class="n">HelloBean</span> <span class="n">bean</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getJsonParameter</span><span class="o">(</span><span class="n">HelloBean</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="s">&quot;bean&quot;</span><span class="o">);</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setClientaddr</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRemoteAddr</span><span class="o">());</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setUseragent</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="s">&quot;User-Agent&quot;</span><span class="o">));</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setRescookie</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getCookie</span><span class="o">(</span><span class="s">&quot;hello-cookie&quot;</span><span class="o">));</span>
<span class="n">bean</span><span class="o">.</span><span class="na">setSessionid</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(</span><span class="kc">false</span><span class="o">));</span>
<span class="n">Flipper</span> <span class="n">flipper</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="na">getFlipper</span><span class="o">();</span>
<span class="n">Sheet</span><span class="o">&lt;</span><span class="n">HelloEntity</span><span class="o">&gt;</span> <span class="n">result</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">queryHello</span><span class="o">(</span><span class="n">bean</span><span class="o">,</span> <span class="n">flipper</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">result</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/hello/find/&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;根据id查找单个Hello对象&quot;</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;#&quot;</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="kt">int</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象id&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">find</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">HelloService</span> <span class="n">service</span> <span class="o">=</span> <span class="n">_servicemap</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">_service</span> <span class="o">:</span> <span class="n">_servicemap</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="n">Rest</span><span class="o">.</span><span class="na">REST_HEADER_RESOURCE_NAME</span><span class="o">,</span> <span class="s">&quot;&quot;</span><span class="o">));</span>
<span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRequstURILastPath</span><span class="o">());</span>
<span class="n">HelloEntity</span> <span class="n">bean</span> <span class="o">=</span> <span class="n">service</span><span class="o">.</span><span class="na">findHello</span><span class="o">(</span><span class="n">id</span><span class="o">);</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">bean</span><span class="o">);</span>
<span class="o">}</span>
<span class="nd">@HttpMapping</span><span class="o">(</span><span class="n">url</span> <span class="o">=</span> <span class="s">&quot;/hello/asyncfind/&quot;</span><span class="o">,</span> <span class="n">auth</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;根据id查找单个Hello对象&quot;</span><span class="o">)</span>
<span class="nd">@HttpParam</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;#&quot;</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="kt">int</span><span class="o">.</span><span class="na">class</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;Hello对象id&quot;</span><span class="o">)</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">asyncfind</span><span class="o">(</span><span class="n">HttpRequest</span> <span class="n">req</span><span class="o">,</span> <span class="n">HttpResponse</span> <span class="n">resp</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">IOException</span> <span class="o">{</span>
<span class="n">HelloService</span> <span class="n">service</span> <span class="o">=</span> <span class="n">_servicemap</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="n">_service</span> <span class="o">:</span> <span class="n">_servicemap</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getHeader</span><span class="o">(</span><span class="n">Rest</span><span class="o">.</span><span class="na">REST_HEADER_RESOURCE_NAME</span><span class="o">,</span> <span class="s">&quot;&quot;</span><span class="o">));</span>
<span class="kt">int</span> <span class="n">id</span> <span class="o">=</span> <span class="n">Integer</span><span class="o">.</span><span class="na">parseInt</span><span class="o">(</span><span class="n">req</span><span class="o">.</span><span class="na">getRequstURILastPath</span><span class="o">());</span>
<span class="n">resp</span><span class="o">.</span><span class="na">finishJson</span><span class="o">(</span><span class="n">service</span><span class="o">.</span><span class="na">findAsyncHello</span><span class="o">(</span><span class="n">id</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<h3><a id="service_async" class="anchor" href="#" aria-hidden="true"></a>Service 异步调用</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;远程模式不仅对@RpcCall注解进行处理而且对方法含有 <b>CompletionHandler</b> 的参数或返回类型为<b>CompletableFuture</b>也进行异步特殊处理。异步调用对远程模式非常有意义可以减少同步方式对当前线程的占用时间。也给Source组件的异步调用提供了基础。</p>
<div class="highlight"><pre> <span class="nd">@Override</span>
<span class="kd">public</span> <span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="kt">void</span> <span class="nf">updateAsync</span><span class="o">(</span><span class="kd">final</span> <span class="n">CompletionHandler</span><span class="o">&lt;</span><span class="n">Void</span><span class="o">,</span> <span class="n">T</span><span class="o">[]&gt;</span> <span class="n">handler</span><span class="o">,</span> <span class="nd">@RpcAttachment</span> <span class="kd">final</span> <span class="n">T</span><span class="o">...</span> <span class="n">values</span><span class="o">)</span> <span class="o">{</span>
<span class="n">source</span><span class="o">.</span><span class="na">update</span><span class="o">(</span><span class="n">values</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">handler</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="n">handler</span><span class="o">.</span><span class="na">completed</span><span class="o">(</span><span class="kc">null</span><span class="o">,</span> <span class="n">values</span><span class="o">);</span>
<span class="o">}</span></pre></div>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上图源码,异步接口(含<b>CompletionHandler</b>参数或返回类型为<b>CompletableFuture</b>)与同步接口执行流程相同。当Service为远程模式时调用异步接口时通信接口发到远程服务器时CompletionHandler参数的值传<b>null</b>返回数据后再调用本地的CompletionHandler参数值执行。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;异步调用方式是提高服务并发性的有效手段特别是在远程模式Service比较多的情况下效果更明显。以HTTP服务为例在Tomcat刚刚改版成NIO的时候网上随处可见都是大谈NIO性能比BIO多好认为BIO与NIO的不同是BIO往往会引入多线程每个连接一个单独的线程NIO则是使用单线程或者只使用少量的多线程每个连接共用一个线程。而事实上呢通常还是通过增加线程数来提高并发量。为什么NIO作用不大呢 因为一个HTTP动态请求耗时最多是业务逻辑层特别是操作数据库IO操作的耗时比重小得多只有在静态资源请求这种纯IO操作才能体现NIO、AIO(NIO.2)的优势。举例一个简单的数据查询请求采用BIO方式耗时为了方便比较将所耗时间扩大几倍如下: <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1、服务器TCP连接开始到进入HttpServlet耗时 10ms <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2、用户态判断和参数验证&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 耗时 10ms <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3、调用远程数据源(DataSource)查询数据,耗时 150ms <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;4、数据序列化与response的IO输出 &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 耗时 10ms <br>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上描述,一个请求处理耗时 180ms同时占用一个线程的时间也是 180ms。若换成NIO使IO耗时减少为了方便计算假设IO耗时为0(实际情况是不可能的), 那么步骤1、4的耗时忽略不计线程的占用时间由180ms变成160ms。 假设数据查询接口IO操作本身耗时也是10ms那么有140ms是用于等待。若采用DataSource异步接口 则140ms的等待时间可以释放当前线程资源。虽然整个请求的处理时间还是180ms但是线程的占用时间却只有20ms。可以看出减少耗时多的步骤的等待时间才能事半功倍大幅度地提高性能。异步接口的主要作用是远程请求在等待过程中释放当前线程资源大大减少线程数。
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

View File

@@ -1,469 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="source_intro" class="anchor" href="#" aria-hidden="true"></a>Source 组件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Source 主要为数据源提供简易的操作接口,使底层的具体数据源(传统数据库、文件系统、内存数据库、Memcached/Redis缓存)对上层是透明的。其提供两种类型的数据源DataSource 和 CacheSource。DataSource 为数据库或内存数据库提供类似JPA、Hibernate的接口与功能。CacheSource 为缓存数据提供类似Memcached、Redis的接口和功能。两者也提供了异步接口(基于<a href="service.html#service_remote" target="_blank">远程模式Service</a>)。<br/></p>
<a href="article_regain.html"></a>
<h3><a id="source_datasource" class="anchor" href="#" aria-hidden="true"></a>DataSource 入门</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JPA虽已提供了简洁成熟的数据库操作接口但当数据、业务量很庞大的时候就显得捉襟见肘与JPA相比DataSource有以下几个特点<br/>
<a href="article_regain.html"></a>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1、简易的过滤查询接口但仅支持简单的表关联查询。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2、简化分表分库操作。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3、通过watch组件动态更改数据库连接参数。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4、读写分离的简易配置。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 5、提供异步接口。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;数据库操作方面常见的是过滤查询操作JPA规范中的JPQL虽然简化了SQL但是对于动态产生的过滤条件,开发人员还是无法免去组装过滤条件的过程(无论JPQL还是CriteriaQuery), DataSource定义了FilterBean接口可以省略组装条件的过程FilterNode提供了类似CriteriaQuery的功能且这两种对象都可以序列化<a href="service.html#service_remote" target="_blank">远程模式Service</a>提供了基础微服务架构提倡服务之间尽量降低耦合因此DataSource仅支持简单的关联查询复杂的表关联查询或统计应放在数据分析系统中。一个服务通常部署多个进程若用JPA的缓存则进程之间的缓存无法同步而DataSource采用SNCP协议即可方便地达到自动同步缓存功能。JPA无法在主数据库异常时动态切换到备份数据库<a href="#source_confproperties">source.properties</a>文件更改后已运行中的进程不会自动切换需要开启watch组件通过watch动态更改正在运行进程中的配置。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了降低学习成本DataSource重用了JPA里的部分注解与配置文件使用方法基本相同与JPA用法的区别是注解只能标记于字段不能标记在方法上。
</p>
<table style="margin: auto;">
<tr><th>注解类名</th><th>功能描述</th></tr>
<tr><td style="text-align: left;">org.redkale.persistence.Cacheable</td><td>标记Entity类是否需要缓存与JPA用法一致</td></tr>
<tr><td style="text-align: left;">org.redkale.persistence.Column</td><td>标记字段只使用其name()、insertable()、updatable()属性</td></tr>
<tr><td style="text-align: left;">org.redkale.persistence.Entity</td><td>JPA的Entity类必须标记为@Entity, 而Redkale不强制要求该注解一般较少使用</td></tr>
<tr><td style="text-align: left;">org.redkale.persistence.Id<td>标记主键字段与JPA用法一致</td></tr>
<tr><td style="text-align: left;">org.redkale.persistence.Table<td>标记表的别名与JPA用法一致</td></tr>
<tr><td style="text-align: left;">org.redkale.persistence.Transient<td>标记是否为表对应的字段与JPA用法一致</td></tr>
<tr><td style="text-align: center;font-size: 0.9rem;" colspan="2"><b>以下是Redkale自定义的注解</b></td></tr>
<tr><td style="text-align: left;"><b>@VirtualEntity</b></td><td>用于非数据库表对应的Entity类且仅用于开启缓存模式的DataSource</td></tr>
<tr><td style="text-align: left;"><b>@DistributeTable</b></td><td>标记表进行分表分库存储, 与DistributeTableStrategy接口结合使用</td></tr>
<tr><td style="text-align: left;"><b>@FilterColumn</b></td><td>用于FilterBean过滤类的字段设置</td></tr>
<tr><td style="text-align: left;"><b>@FilterJoinColumn</b></td><td>用于FilterBean过滤类的关联表字段设置</td></tr>
<tr><td style="text-align: left;"><b>@FilterGroup</b></td><td>用于FilterBean过滤类的过滤条件分组设置</td></tr>
</table>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;操作数据源主要使用的对象有 DataSource、FilterBean、FilterNode。DataSource 提供的接口分几种系列:
</p>
<table style="margin: auto;">
<tr><th>系列方法</th><th>功能描述</th></tr>
<tr><td style="text-align: left;">insert</td><td>插入数据</td></tr>
<tr><td style="text-align: left;">delete</td><td>删除数据</td></tr>
<tr><td style="text-align: left;">update</td><td>更新数据</td></tr>
<tr><td style="text-align: left;">updateColumn</td><td>更新数据的部分字段</td></tr>
<tr><td style="text-align: left;">getNumberXXX</td><td>统计查询,用于查询字段的总和、最大值、平均值等数据</td></tr>
<tr><td style="text-align: left;">queryColumnXXX<td>单个字段数据查询和字段的统计查询</td></tr>
<tr><td style="text-align: left;">find<td>查找单个对象</td></tr>
<tr><td style="text-align: left;">queryList<td>查询对象的List集合</td></tr>
<tr><td style="text-align: left;">querySheet</td><td>查询对象的Sheet页式集合</td></tr>
<tr><td style="text-align: left;">directXXX<td>直接运行SQL语句用于复杂的关联查询与更新(仅限DataSqlSource)</td></tr>
</table>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以上接口除了directXXX其他都有等同的异步接口。insert、delete、update接口与JPA同名接口用法一样。DataSource提供了丰富的查询接口且有独特的翻页查询功能。每以系列的方法主要重载三类 单个字段过滤、FilterBean过滤和FilterNode过滤。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>返回类型为CompletableFuture的接口均为异步接口</b><br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;开发者可以借鉴 <a href="https://github.com/redkale/redkale-demo" target="_blank">Redkale-demo</a> 中的 <a href="https://github.com/redkale/redkale-demo/blob/master/src/main/java/org/redkale/demo/base/AutoClassCreator.java" target="_blank"> AutoClassCreator</a>的代码根据数据表自动生成Entity代码。
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;<b>过滤条件</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FilterBean、FilterNode对象用于构造过滤条件。FilterBean可以转化为FilterNode。FilterBean主要用于接收外界构建的过滤条件而FilterNode为了构建内部的过滤条件且降低过滤条件变化的耦合性FilterNode中name值以#开头的视为虚拟字段不会构建成过滤条件仅供分布分库的DistributeTableStrategy策略使用。</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserBean</span> <span class="kd">implements</span> <span class="n">FilterBean</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">;</span>
<span class="nd">@FilterColumn</span><span class="o">(</span><span class="n">express</span> <span class="o">=</span> <span class="n">FilterExpress</span><span class="o">.</span><span class="na">LIKE</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">userName</span><span class="o">;</span>
<span class="kd">private</span> <span class="n">Range</span> <span class="n">age</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">UserBean</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">userName</span><span class="o">,</span> <span class="n">Range</span> <span class="n">age</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">userid</span> <span class="o">=</span> <span class="n">userid</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">userName</span> <span class="o">=</span> <span class="n">userName</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">age</span> <span class="o">=</span> <span class="n">age</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">/**</span> <span class="n">以下省略getter</span> <span class="n">setter方法</span> <span class="o">*/</span>
<span class="o">}</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">))</span> <span class="o">等价于</span>
<span class="n">FilterNodes</span><span class="o">.</span><span class="na">eq</span><span class="o">(</span><span class="s">&quot;userid&quot;</span><span class="o">,</span> <span class="mi">200001</span><span class="o">).</span><span class="na">like</span><span class="o">(</span><span class="s">&quot;userName&quot;</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">).</span><span class="na">between</span><span class="o">(</span><span class="s">&quot;age&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="n">Range</span><span class="o">.</span><span class="na">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">))</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span><span class="s">&quot;redkale&quot;</span><span class="o">,</span><span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span><span class="mi">36</span><span class="o">))</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userid=200001 AND userName LIKE &#39;%redkale%&#39; AND age BETWEEN 14 AND 36&quot;</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="kc">null</span><span class="o">)</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userid = 200001 AND userName LIKE &#39;%redkale%&#39;&quot;</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="kc">null</span><span class="o">)</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userName LIKE &#39;%redkale%&#39;&quot;</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上定义UserBean过滤条件当非数值类字段值为null、字符串值为空、数值类字段值小于@FilterColumn.least()值(least的默认值为1)都不会构建成过滤条件。@FilterColumn.express根据字段的类型有不同的默认值若字段类型为Collection子类或数组则express默认为FilterExpress.IN若字段类型为Range的子类则express默认为FilterExpress.BETWEEN其他类型则express默认为FilterExpress.EQUAL。默认字段之间是AND关系若想使用OR关系则需要使用@FilterGroup进行标记</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserBean</span> <span class="kd">implements</span> <span class="n">FilterBean</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kt">int</span> <span class="n">userid</span><span class="o">;</span>
<span class="nd">@FilterGroup</span><span class="o">(</span><span class="s">&quot;[OR]a&quot;</span><span class="o">)</span>
<span class="nd">@FilterColumn</span><span class="o">(</span><span class="n">express</span> <span class="o">=</span> <span class="n">FilterExpress</span><span class="o">.</span><span class="na">LIKE</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">userName</span><span class="o">;</span>
<span class="nd">@FilterGroup</span><span class="o">(</span><span class="s">&quot;[OR]a&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">Range</span> <span class="n">age</span><span class="o">;</span>
<span class="kd">public</span> <span class="nf">UserBean</span><span class="o">(</span><span class="kt">int</span> <span class="n">userid</span><span class="o">,</span> <span class="n">String</span> <span class="n">userName</span><span class="o">,</span> <span class="n">Range</span> <span class="n">age</span><span class="o">)</span> <span class="o">{</span>
<span class="k">this</span><span class="o">.</span><span class="na">userid</span> <span class="o">=</span> <span class="n">userid</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">userName</span> <span class="o">=</span> <span class="n">userName</span><span class="o">;</span>
<span class="k">this</span><span class="o">.</span><span class="na">age</span> <span class="o">=</span> <span class="n">age</span><span class="o">;</span>
<span class="o">}</span>
<span class="o">/**</span> <span class="n">以下省略getter</span> <span class="n">setter方法</span> <span class="o">*/</span>
<span class="o">}</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">))</span> <span class="o">等价于</span>
<span class="n">FilterNode</span> <span class="n">orNode</span> <span class="o">=</span> <span class="n">FilterNodes</span><span class="o">.</span><span class="na">like</span><span class="o">(</span><span class="s">&quot;userName&quot;</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">).</span><span class="na">or</span><span class="o">(</span><span class="s">&quot;age&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="n">Range</span><span class="o">.</span><span class="na">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">));</span>
<span class="n">FilterNode</span> <span class="n">node</span> <span class="o">=</span> <span class="n">FilterNodes</span><span class="o">.</span><span class="na">eq</span><span class="o">(</span><span class="s">&quot;userid&quot;</span><span class="o">,</span> <span class="mi">200001</span><span class="o">).</span><span class="na">and</span><span class="o">(</span><span class="n">orNode</span><span class="o">);</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span><span class="s">&quot;redkale&quot;</span><span class="o">,</span><span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span><span class="mi">36</span><span class="o">))</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userid=200001 AND (userName LIKE &#39;%redkale%&#39; OR age BETWEEN 14 AND 36)&quot;</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">200001</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="kc">null</span><span class="o">)</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userid = 200001 AND userName LIKE &#39;%redkale%&#39;&quot;</span>
<span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="kc">null</span><span class="o">)</span> <span class="o">等价于</span> <span class="s">&quot;WHERE userName LIKE &#39;%redkale%&#39;&quot;</span>
<span class="n">source</span><span class="o">.</span><span class="na">getNumberResult</span><span class="o">(</span><span class="n">User</span><span class="o">.</span><span class="k">class</span><span class="o">,</span> <span class="n">FilterFunc</span><span class="o">.</span><span class="na">COUNT</span><span class="o">,</span> <span class="kc">null</span><span class="o">,</span> <span class="k">new</span> <span class="nf">UserBean</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="s">&quot;redkale&quot;</span><span class="o">,</span> <span class="k">new</span> <span class="nf">IntRange</span><span class="o">(</span><span class="mi">14</span><span class="o">,</span> <span class="mi">36</span><span class="o">))).</span><span class="na">intValue</span><span class="o">()</span> <span class="o">等价于</span>
<span class="s">&quot;SELECT COUNT(*) FROM user WHERE userName LIKE &#39;%redkale%&#39; AND age BETWEEN 14 AND 36&quot;</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上@FilterGroup 的value 必须是[OR]或者[AND]开头,没有标记@FilterGroup的字段等价于标记了@FilterGroup(value = "[AND]")。[AND]、[OR]后面的字符串为GROUP_NAME默认的GROUP_NAME为空字符串。如上"[OR]a"可以直接使用"[OR]",有多个[OR]或者[AND]则需要加上不同的NAME。</p>
<p id="source_distribute">&nbsp;&nbsp;&nbsp;&nbsp;<b>分表分库</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DataSource提供了单个实体类对应多个数据库表的功能通常流水型的数据量比较大单个数据库无法存储DataSource提供了简单的分表操作同时在接口设计上尽量减少单表操作与分表操作的差异。分表分库只需在实体类上注解@DistributeTable并实现DistributeTableStrategy分表策略即可。</p>
<div class="highlight"><pre><span></span><span class="kd">public</span> <span class="kd">interface</span> <span class="nc">DistributeTableStrategy</span><span class="o">&lt;</span><span class="n">T</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="cm">/**</span>
<span class="cm"> * 获取对象的表名</span>
<span class="cm"> * 查询单个对象时调用本方法获取表名</span>
<span class="cm"> *</span>
<span class="cm"> * @param table 模板表的表名</span>
<span class="cm"> * @param primary 记录主键</span>
<span class="cm"> *</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">Serializable</span> <span class="n">primary</span><span class="o">);</span>
<span class="cm">/**</span>
<span class="cm"> * 获取对象的表名</span>
<span class="cm"> * 查询、修改、删除对象时调用本方法获取表名</span>
<span class="cm"> * 注意: 需保证FilterNode过滤的结果集合必须在一个数据库表中</span>
<span class="cm"> *</span>
<span class="cm"> * @param table 模板表的表名</span>
<span class="cm"> * @param node 过滤条件</span>
<span class="cm"> *</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">FilterNode</span> <span class="n">node</span><span class="o">);</span>
<span class="cm">/**</span>
<span class="cm"> * 获取对象的表名</span>
<span class="cm"> * 新增对象或更新单个对象时调用本方法获取表名</span>
<span class="cm"> *</span>
<span class="cm"> * @param table 模板表的表名</span>
<span class="cm"> * @param bean 实体对象</span>
<span class="cm"> *</span>
<span class="cm"> * @return</span>
<span class="cm"> */</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">T</span> <span class="n">bean</span><span class="o">);</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DistributeTableStrategy分表策略需要实现三个接口模板表由实体类的@Table注解提供。Redkale默认实现的MySQL数据库的拷贝表结构语句其他数据库类型需要通过指定<a href="#source_confproperties">source.properties</a> 中的 <b>tablenotexist-sqlstates</b><b>tablecopy-sqltemplate</b> 来配置。</p>
<div class="highlight"><pre><span></span><span class="nd">@DistributeTable</span><span class="o">(</span><span class="n">strategy</span> <span class="o">=</span> <span class="n">LoginRecord</span><span class="o">.</span><span class="na">TableStrategy</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">LoginRecord</span> <span class="kd">extends</span> <span class="n">BaseEntity</span> <span class="o">{</span>
<span class="nd">@Id</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">comment</span> <span class="o">=</span> <span class="s">"主键ID; 值=create36time(9位)+'-'+UUID(32位)"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">loginid</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//主键ID; 值=create36time(9位)+'-'+UUID(32位)</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"C端用户ID"</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">userid</span><span class="o">;</span> <span class="c1">//C端用户ID</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"登录网络类型; wifi/4g/3g"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">netMode</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//登录网络类型; wifi/4g/3g</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"APP版本信息"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">appVersion</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//APP版本信息</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"APP操作系统信息"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">appos</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//APP操作系统信息</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"登录时客户端信息"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">loginAgent</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//登录时客户端信息</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"登录时的IP"</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">loginAddr</span> <span class="o">=</span> <span class="s">""</span><span class="o">;</span> <span class="c1">//登录时的IP</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">"创建时间"</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">createTime</span><span class="o">;</span> <span class="c1">//创建时间</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="c1">//创建对象</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kt">void</span> <span class="nf">main</span><span class="o">(</span><span class="n">String</span><span class="o">[]</span> <span class="n">args</span><span class="o">)</span> <span class="kd">throws</span> <span class="n">Throwable</span> <span class="o">{</span>
<span class="n">LoginRecord</span> <span class="n">record</span> <span class="o">=</span> <span class="k">new</span> <span class="n">LoginRecord</span><span class="o">();</span>
<span class="kt">long</span> <span class="n">now</span> <span class="o">=</span> <span class="n">System</span><span class="o">.</span><span class="na">currentTimeMillis</span><span class="o">();</span>
<span class="n">record</span><span class="o">.</span><span class="na">setCreateTime</span><span class="o">(</span><span class="n">now</span><span class="o">);</span> <span class="c1">//设置创建时间</span>
<span class="n">record</span><span class="o">.</span><span class="na">setLoginid</span><span class="o">(</span><span class="n">Utility</span><span class="o">.</span><span class="na">format36time</span><span class="o">(</span><span class="n">now</span><span class="o">)</span> <span class="o">+</span> <span class="s">"-"</span> <span class="o">+</span> <span class="n">Utility</span><span class="o">.</span><span class="na">uuid</span><span class="o">());</span> <span class="c1">//主键的生成规则</span>
<span class="c1">//.... 填充其他字段</span>
<span class="n">source</span><span class="o">.</span><span class="na">insert</span><span class="o">(</span><span class="n">record</span><span class="o">);</span>
<span class="o">}</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">TableStrategy</span> <span class="kd">implements</span> <span class="n">DistributeTableStrategy</span><span class="o">&lt;</span><span class="n">LoginRecord</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">dayformat</span> <span class="o">=</span> <span class="s">"%1$tY%1$tm%1$td"</span><span class="o">;</span> <span class="c1">//一天一个表</span>
<span class="kd">private</span> <span class="kd">static</span> <span class="kd">final</span> <span class="n">String</span> <span class="n">yearformat</span> <span class="o">=</span> <span class="s">"%1$tY"</span><span class="o">;</span> <span class="c1">//一年一个库</span>
<span class="c1">//过滤查询时调用本方法</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">FilterNode</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Serializable</span> <span class="n">day</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">"#day"</span><span class="o">);</span> <span class="c1">//LoginRecord没有day字段所以前面要加#,表示虚拟字段, 值为yyyyMMdd格式</span>
<span class="k">if</span> <span class="o">(</span><span class="n">day</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">day</span><span class="o">,</span> <span class="mi">0</span><span class="n">L</span><span class="o">);</span> <span class="c1">//存在#day参数则直接使用day值</span>
<span class="n">Serializable</span> <span class="n">time</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">"createTime"</span><span class="o">);</span> <span class="c1">//存在createTime则使用最小时间且createTime的范围必须在一天内因为本表以天为单位建表</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="o">(</span><span class="n">time</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="mi">0</span><span class="n">L</span> <span class="o">:</span> <span class="o">(</span><span class="n">time</span> <span class="k">instanceof</span> <span class="n">Range</span> <span class="o">?</span> <span class="o">((</span><span class="n">Range</span><span class="o">.</span><span class="na">LongRange</span><span class="o">)</span> <span class="n">time</span><span class="o">).</span><span class="na">getMin</span><span class="o">()</span> <span class="o">:</span> <span class="o">(</span><span class="n">Long</span><span class="o">)</span> <span class="n">time</span><span class="o">)));</span>
<span class="o">}</span>
<span class="c1">//创建或单个查询时调用本方法</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">LoginRecord</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getCreateTime</span><span class="o">());</span>
<span class="o">}</span>
<span class="c1">//根据主键ID查询单个记录时调用本方法</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">Serializable</span> <span class="n">primary</span><span class="o">)</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">id</span> <span class="o">=</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">primary</span><span class="o">;</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="mi">0</span><span class="o">,</span> <span class="n">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">id</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="mi">9</span><span class="o">),</span> <span class="mi">36</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="kt">int</span> <span class="n">day</span><span class="o">,</span> <span class="kt">long</span> <span class="n">createTime</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//day为0或yyyyMMdd格式数据</span>
<span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">'.'</span><span class="o">);</span>
<span class="n">String</span> <span class="n">year</span> <span class="o">=</span> <span class="n">day</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">String</span><span class="o">.</span><span class="na">valueOf</span><span class="o">(</span><span class="n">day</span> <span class="o">/</span> <span class="mi">10000</span><span class="o">)</span> <span class="o">:</span> <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="n">yearformat</span><span class="o">,</span> <span class="n">createTime</span><span class="o">);</span> <span class="c1">//没有day取createTime</span>
<span class="k">return</span> <span class="s">"platf_login_"</span> <span class="o">+</span> <span class="n">year</span> <span class="o">+</span> <span class="s">"."</span> <span class="o">+</span> <span class="n">table</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">+</span> <span class="s">"_"</span> <span class="o">+</span> <span class="o">(</span><span class="n">day</span> <span class="o">&gt;</span> <span class="mi">0</span> <span class="o">?</span> <span class="n">day</span> <span class="o">:</span> <span class="n">String</span><span class="o">.</span><span class="na">format</span><span class="o">(</span><span class="n">dayformat</span><span class="o">,</span> <span class="n">createTime</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如上范例用户登陆记录的分表分库策略为一年一个库一个库中365张表每天一个表。为了分表策略的三个接口均得到实现需要对主键ID的生成规则进行一定的设计。常见的场景是查询单个用户的登录列表。上面的范例就无法满足查询单个用户的登录信息需求而分表策略又只能根据一种规则生成因此需要按用户维度存在另外一张表中。</p>
<div class="highlight"><pre><span></span><span class="nd">@DistributeTable</span><span class="o">(</span><span class="n">strategy</span> <span class="o">=</span> <span class="n">LoginUserRecord</span><span class="o">.</span><span class="na">TableStrategy</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">LoginUserRecord</span> <span class="kd">extends</span> <span class="n">BaseEntity</span> <span class="o">{</span>
<span class="nd">@Id</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;记录ID; 值=userid+'-'+UUID&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">seqid</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//记录ID; 值=userid+'-'+UUID</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;C端用户ID&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">userid</span><span class="o">;</span> <span class="c1">//C端用户ID</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;LoginRecord主键&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">loginid</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//LoginRecord主键</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;创建时间&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">createTime</span><span class="o">;</span> <span class="c1">//创建时间</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">TableStrategy</span> <span class="kd">implements</span> <span class="n">DistributeTableStrategy</span><span class="o">&lt;</span><span class="n">LoginUserRecord</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">LoginUserRecord</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">FilterNode</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Serializable</span> <span class="n">id</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">&quot;userid&quot;</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">id</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="n">id</span><span class="o">);</span>
<span class="k">return</span> <span class="n">getHashTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">&quot;#hash&quot;</span><span class="o">));</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">Serializable</span> <span class="n">primary</span><span class="o">)</span> <span class="o">{</span>
<span class="n">String</span> <span class="n">id</span> <span class="o">=</span> <span class="o">(</span><span class="n">String</span><span class="o">)</span> <span class="n">primary</span><span class="o">;</span>
<span class="k">return</span> <span class="n">getHashTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(</span><span class="n">Long</span><span class="o">.</span><span class="na">parseLong</span><span class="o">(</span><span class="n">id</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="mi">0</span><span class="o">,</span> <span class="n">id</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">&#39;-&#39;</span><span class="o">)))</span> <span class="o">%</span> <span class="mi">100</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">String</span> <span class="nf">getHashTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="kt">int</span> <span class="n">hash</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">&#39;.&#39;</span><span class="o">);</span>
<span class="k">return</span> <span class="s">&quot;platf_login.&quot;</span> <span class="o">+</span> <span class="n">table</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="o">(</span><span class="n">hash</span> <span class="o">&gt;</span> <span class="mi">9</span> <span class="o">?</span> <span class="n">hash</span> <span class="o">:</span> <span class="o">(</span><span class="s">&quot;0&quot;</span> <span class="o">+</span> <span class="n">hash</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如上表LoginUserRecord只存储用户ID与登录信息ID的关联关系以用户ID取模100进行hash存储获取用户登录列表时先查询LoginUserRecord一页的数据再根据loginid查询LoginRecord实体。常见的分表策略是时间和主键hash例如用户信息表采用主键hash分表</p>
<div class="highlight"><pre><span></span><span class="nd">@DistributeTable</span><span class="o">(</span><span class="n">strategy</span> <span class="o">=</span> <span class="n">UserDetail</span><span class="o">.</span><span class="na">TableStrategy</span><span class="o">.</span><span class="na">class</span><span class="o">)</span>
<span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserDetail</span> <span class="kd">extends</span> <span class="n">BaseEntity</span> <span class="o">{</span>
<span class="nd">@Id</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">userid</span><span class="o">;</span> <span class="c1">//用户ID</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">64</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;用户昵称&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">userName</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//用户昵称</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">32</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;手机号码&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">mobile</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//手机号码</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">64</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;密码&quot;</span><span class="o">)</span>
<span class="nd">@ConvertColumn</span><span class="o">(</span><span class="n">ignore</span> <span class="o">=</span> <span class="kc">true</span><span class="o">,</span> <span class="n">type</span> <span class="o">=</span> <span class="n">ConvertType</span><span class="o">.</span><span class="na">ALL</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">password</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//密码</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">length</span> <span class="o">=</span> <span class="mi">128</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;备注&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="n">String</span> <span class="n">remark</span> <span class="o">=</span> <span class="s">&quot;&quot;</span><span class="o">;</span> <span class="c1">//备注</span>
<span class="nd">@Column</span><span class="o">(</span><span class="n">updatable</span> <span class="o">=</span> <span class="kc">false</span><span class="o">,</span> <span class="n">comment</span> <span class="o">=</span> <span class="s">&quot;创建时间&quot;</span><span class="o">)</span>
<span class="kd">private</span> <span class="kt">long</span> <span class="n">createTime</span><span class="o">;</span> <span class="c1">//创建时间</span>
<span class="cm">/** 以下省略getter setter方法 */</span>
<span class="kd">public</span> <span class="kd">static</span> <span class="kd">class</span> <span class="nc">TableStrategy</span> <span class="kd">implements</span> <span class="n">DistributeTableStrategy</span><span class="o">&lt;</span><span class="n">UserDetail</span><span class="o">&gt;</span> <span class="o">{</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">UserDetail</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">FilterNode</span> <span class="n">node</span><span class="o">)</span> <span class="o">{</span>
<span class="n">Serializable</span> <span class="n">id</span> <span class="o">=</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">&quot;userid&quot;</span><span class="o">);</span>
<span class="k">if</span> <span class="o">(</span><span class="n">id</span> <span class="o">!=</span> <span class="kc">null</span><span class="o">)</span> <span class="k">return</span> <span class="n">getTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="n">id</span><span class="o">);</span>
<span class="k">return</span> <span class="n">getHashTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="n">Integer</span><span class="o">)</span> <span class="n">node</span><span class="o">.</span><span class="na">findValue</span><span class="o">(</span><span class="s">&quot;#hash&quot;</span><span class="o">));</span>
<span class="o">}</span>
<span class="nd">@Override</span>
<span class="kd">public</span> <span class="n">String</span> <span class="nf">getTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="n">Serializable</span> <span class="n">userid</span><span class="o">)</span> <span class="o">{</span>
<span class="k">return</span> <span class="n">getHashTable</span><span class="o">(</span><span class="n">table</span><span class="o">,</span> <span class="o">(</span><span class="kt">int</span><span class="o">)</span> <span class="o">(((</span><span class="n">Long</span><span class="o">)</span> <span class="n">userid</span><span class="o">)</span> <span class="o">%</span> <span class="mi">100</span><span class="o">));</span>
<span class="o">}</span>
<span class="kd">private</span> <span class="n">String</span> <span class="nf">getHashTable</span><span class="o">(</span><span class="n">String</span> <span class="n">table</span><span class="o">,</span> <span class="kt">int</span> <span class="n">hash</span><span class="o">)</span> <span class="o">{</span>
<span class="kt">int</span> <span class="n">pos</span> <span class="o">=</span> <span class="n">table</span><span class="o">.</span><span class="na">indexOf</span><span class="o">(</span><span class="sc">&#39;.&#39;</span><span class="o">);</span>
<span class="k">return</span> <span class="s">&quot;platf_user.&quot;</span> <span class="o">+</span> <span class="n">table</span><span class="o">.</span><span class="na">substring</span><span class="o">(</span><span class="n">pos</span> <span class="o">+</span> <span class="mi">1</span><span class="o">)</span> <span class="o">+</span> <span class="s">&quot;_&quot;</span> <span class="o">+</span> <span class="o">(</span><span class="n">hash</span> <span class="o">&gt;</span> <span class="mi">9</span> <span class="o">?</span> <span class="n">hash</span> <span class="o">:</span> <span class="o">(</span><span class="s">&quot;0&quot;</span> <span class="o">+</span> <span class="n">hash</span><span class="o">));</span>
<span class="o">}</span>
<span class="o">}</span>
<span class="o">}</span>
</pre></div><p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 如上用户表以userid取模100进行hash分表若需要提供根据手机号查询单个用户信息则需要另外存在一个用户ID对应手机号码的关系表同样可以以手机号后两位数字为hash存储。</p>
<h3><a id="source_cachesource" class="anchor" href="#" aria-hidden="true"></a>CacheSource 入门</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CacheSource同Memcached类似像一个带有过期功能地Map容器存放key-value数据。常见的使用场景就是存放HTTP的Session信息。Redkale把用户会话信息数据当做业务数据处理而不是接入层的数据。WebSocket的连接态数据也是用CacheSource存储。key为WebSocket的groupidvalue为WebSocket服务端节点的IP地址列表。</p>
<div class="highlight"><pre><span class="kd">public</span> <span class="kd">class</span> <span class="nc">UserService</span> <span class="kd">implements</span> <span class="n">Service</span> <span class="o">{</span>
<span class="c1">//用户简单信息缓存</span>
<span class="kd">private</span> <span class="kd">final</span> <span class="n">Map</span><span class="o">&lt;</span><span class="n">Integer</span><span class="o">,</span> <span class="n">UserInfo</span><span class="o">&gt;</span> <span class="n">users</span> <span class="o">=</span> <span class="k">new</span> <span class="n">ConcurrentHashMap</span><span class="o">&lt;&gt;();</span>
<span class="c1">//使用CacheSource必须要指明泛型</span>
<span class="nd">@Resource</span><span class="o">(</span><span class="n">name</span> <span class="o">=</span> <span class="s">&quot;usersessions&quot;</span><span class="o">)</span>
<span class="kd">protected</span> <span class="n">CacheSource</span> <span class="n">sessions</span><span class="o">;</span>
<span class="c1">//登录</span>
<span class="kd">public</span> <span class="n">RetResult</span><span class="o">&lt;</span><span class="n">UserInfo</span><span class="o">&gt;</span> <span class="nf">login</span><span class="o">(</span><span class="n">LoginBean</span> <span class="n">bean</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//bean.sessionid 在接入层进行赋值</span>
<span class="n">UserInfo</span> <span class="n">user</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>
<span class="c1">// 登陆逻辑 user = ...</span>
<span class="n">users</span><span class="o">.</span><span class="na">put</span><span class="o">(</span><span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">(),</span> <span class="n">user</span><span class="o">);</span>
<span class="n">sessions</span><span class="o">.</span><span class="na">setLong</span><span class="o">(</span><span class="mi">600</span><span class="o">,</span> <span class="n">bean</span><span class="o">.</span><span class="na">getSessionid</span><span class="o">(),</span> <span class="n">user</span><span class="o">.</span><span class="na">getUserid</span><span class="o">());</span> <span class="c1">//session过期时间设置为10分钟</span>
<span class="k">return</span> <span class="k">new</span> <span class="n">RetResult</span><span class="o">&lt;&gt;(</span><span class="n">user</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//获取当前用户信息</span>
<span class="kd">public</span> <span class="n">UserInfo</span> <span class="nf">current</span><span class="o">(</span><span class="n">String</span> <span class="n">sessionid</span><span class="o">)</span> <span class="o">{</span> <span class="c1">//给HTTP的BaseServlet用</span>
<span class="n">Long</span> <span class="n">userid</span> <span class="o">=</span> <span class="n">sessions</span><span class="o">.</span><span class="na">getexLong</span><span class="o">(</span><span class="n">sessionid</span><span class="o">);</span>
<span class="k">return</span> <span class="n">userid</span> <span class="o">==</span> <span class="kc">null</span> <span class="o">?</span> <span class="kc">null</span> <span class="o">:</span> <span class="n">users</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">userid.intValue()</span><span class="o">);</span>
<span class="o">}</span>
<span class="c1">//注销</span>
<span class="kd">public</span> <span class="kt">void</span> <span class="nf">logout</span><span class="o">(</span><span class="n">String</span> <span class="n">sessionid</span><span class="o">)</span> <span class="o">{</span>
<span class="n">sessions</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">sessionid</span><span class="o">);</span>
<span class="o">}</span>
<span class="o">}</span></pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以上是个简单的范例用于用户模块存放sessionid。</p>
<h3><a id="source_confproperties" href="#" aria-hidden="true"></a>source.properties 配置说明</h3>
<div class="highlight"><pre>
<span></span><span class="c1"># CacheSource @Resource(name="usersession")</span>
<span class="c1"># type可以不用设置框架会根据url判断使用哪个CacheSource实现类</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">org</span><span class="o">.</span><span class="n">redkalex</span><span class="o">.</span><span class="n">cache</span><span class="o">.</span><span class="n">redis</span><span class="o">.</span><span class="n">RedisCacheSource</span>
<span class="c1"># 最大连接数</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">maxconns</span> <span class="o">=</span> <span class="mi">16</span>
<span class="c1"># 节点地址</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">redis</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">6363</span>
<span class="c1"># 节点密码</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="mi">12345678</span>
<span class="c1"># 节点db</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">cachesource</span><span class="p">[</span><span class="n">usersession</span><span class="p">]</span><span class="o">.</span><span class="n">node</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">db</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># DataSource @Resource(name="platf")</span>
<span class="c1"># type可以不用设置框架会根据url判断使用哪个DataSource实现类默认值: org.redkale.source.DataJdbcSource</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">type</span> <span class="o">=</span> <span class="n">org</span><span class="o">.</span><span class="n">redkale</span><span class="o">.</span><span class="n">source</span><span class="o">.</span><span class="n">DataJdbcSource</span>
<span class="c1"># 是否开启缓存(标记为@Cacheable的Entity类),值目前只支持两种: ALL: 所有开启缓存。 NONE: 关闭所有缓存, 非NONE字样统一视为ALL</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">cachemode</span> <span class="o">=</span> <span class="n">ALL</span>
<span class="c1"># 是否自动建表当表不存在的时候, 目前只支持mysql、postgres 默认为false</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">table</span><span class="o">-</span><span class="n">autoddl</span> <span class="o">=</span> <span class="n">false</span>
<span class="c1"># 用户</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">root</span>
<span class="c1"># 密码</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="mi">12345678</span>
<span class="c1"># 多个URL用;隔开如分布式SearchSource需要配多个URL</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">jdbc</span><span class="p">:</span><span class="n">mysql</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">3306</span><span class="o">/</span><span class="n">platf</span><span class="">?</span><span class="n">allowPublicKeyRetrieval</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">rewriteBatchedStatements</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">serverTimezone</span><span class="o">=</span><span class="n">UTC</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">characterEncoding</span><span class="o">=</span><span class="n">utf8</span>
<span class="c1"># 最大连接数默认值CPU数</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">maxconns</span> <span class="o">=</span> <span class="mi">16</span>
<span class="c1"># 包含的SQL模板相当于反向LIKE不同的JDBC驱动的SQL语句不一样Redkale内置了MySQL的语句</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">contain</span><span class="o">-</span><span class="n">sqltemplate</span> <span class="o">=</span> <span class="n">LOCATE</span><span class="p">(</span><span class="">$</span><span class="p">{</span><span class="n">keystr</span><span class="p">},</span> <span class="">$</span><span class="p">{</span><span class="n">column</span><span class="p">})</span> <span class="o">&gt;</span> <span class="mi">0</span>
<span class="c1"># 包含的SQL模板相当于反向LIKE不同的JDBC驱动的SQL语句不一样Redkale内置了MySQL的语句</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">notcontain</span><span class="o">-</span><span class="n">sqltemplate</span> <span class="o">=</span> <span class="n">LOCATE</span><span class="p">(</span><span class="">$</span><span class="p">{</span><span class="n">keystr</span><span class="p">},</span> <span class="">$</span><span class="p">{</span><span class="n">column</span><span class="p">})</span> <span class="o">=</span> <span class="mi">0</span>
<span class="c1"># 复制表结构的SQL模板Redkale内置了MySQL的语句</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">tablenotexist</span><span class="o">-</span><span class="n">sqlstates</span> <span class="o">=</span> <span class="mi">42000</span><span class="p">;</span><span class="mi">42</span><span class="n">S02</span>
<span class="c1"># 复制表结构的SQL模板Redkale内置了MySQL的语句</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">tablecopy</span><span class="o">-</span><span class="n">sqltemplate</span> <span class="o">=</span> <span class="n">CREATE</span> <span class="n">TABLE</span> <span class="n">IF</span> <span class="n">NOT</span> <span class="n">EXISTS</span> <span class="">$</span><span class="p">{</span><span class="n">newtable</span><span class="p">}</span> <span class="n">LIKE</span> <span class="">$</span><span class="p">{</span><span class="n">oldtable</span><span class="p">}</span>
<span class="c1"># DataSource 读写分离</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">jdbc</span><span class="p">:</span><span class="n">mysql</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">3306</span><span class="o">/</span><span class="n">platf_r</span><span class="">?</span><span class="n">allowPublicKeyRetrieval</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">rewriteBatchedStatements</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">serverTimezone</span><span class="o">=</span><span class="n">UTC</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">characterEncoding</span><span class="o">=</span><span class="n">utf8</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">root</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">read</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="mi">12345678</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">url</span> <span class="o">=</span> <span class="n">jdbc</span><span class="p">:</span><span class="n">mysql</span><span class="p">:</span><span class="o">//</span><span class="mf">127.0</span><span class="o">.</span><span class="mf">0.1</span><span class="p">:</span><span class="mi">3306</span><span class="o">/</span><span class="n">platf_w</span><span class="">?</span><span class="n">allowPublicKeyRetrieval</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">rewriteBatchedStatements</span><span class="o">=</span><span class="n">true</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">serverTimezone</span><span class="o">=</span><span class="n">UTC</span><span class="o">&amp;</span><span class="n">amp</span><span class="p">;</span><span class="n">characterEncoding</span><span class="o">=</span><span class="n">utf8</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">user</span> <span class="o">=</span> <span class="n">root</span>
<span class="n">redkale</span><span class="o">.</span><span class="n">datasource</span><span class="p">[</span><span class="n">platf</span><span class="p">]</span><span class="o">.</span><span class="n">write</span><span class="o">.</span><span class="n">password</span> <span class="o">=</span> <span class="mi">12345678</span>
</pre></div>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +0,0 @@
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="UTF-8">
<title>Redkale(红菜苔)--基于Java 8全新的微服务开源框架 - Redkale官网</title>
<meta name="keywords" content="Redkale,redkale,java,微服务,架构"/>
<meta name="description" content="Redkale(红菜苔)是基于Java 8全新的微服务开源框架"/>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" href="stylesheets/stylesheet.css" media="screen">
</head>
<body>
<section class="page-header">
<a href="index.html" class="project-name">Redkale</a>
<h2 class="project-tagline"></h2>
<a href="redkale.html" class="btn">Redkale 入门</a>
<a href="convert.html" class="btn">Convert 组件</a>
<a href="service.html" class="btn">Service 组件</a>
<a href="source.html" class="btn">Source 组件</a>
<a href="net.html" class="btn">Net 组件</a>
<a href="watch.html" class="btn">Watch 组件</a>
<a href="plugins.html" class="btn">Redkale 插件</a>
<a href="articles.html" class="btn">技术文章</a>
</section>
<section class="main-content">
<h3><a id="watch-intro" class="anchor" href="#welcome-to-github-pages" aria-hidden="true"></a>Watch 组件介绍</h3>
<p>敬请期待…… <br/>
</p>
<footer class="site-footer">
<span class="site-footer-owner">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;欢迎加入Redkale QQ群: 527523235</span>
</footer>
</section>
<script>
var _hmt = _hmt || [];
(function () {
var hm = document.createElement("script");
hm.src = "//hm.baidu.com/hm.js?aee2e6e1addaf28cd4e21e2d5a509123";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script>
</body>
</html>