This commit is contained in:
wentch
2016-01-15 16:54:50 +08:00
parent b17d482229
commit 975c035882
4 changed files with 126 additions and 123 deletions

View File

@@ -26,11 +26,11 @@
<section class="main-content">
<h3><a id="convert_intro" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>Convert 组件介绍</h3>
<p>&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>
<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"><span class="octicon octicon-link"></span></a>Convert 快速上手</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本介绍仅以JSON为例(BSON与JSON使用方式雷同)。其操作类主要是JsonConvert配置类主要是JsonFactory、ConvertColumn。JsonFactory采用同ClassLoader类似的双亲委托方式设计。</br></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;JsonConvert 序列化encode方法</p>
<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>
@@ -48,7 +48,7 @@
<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;JsonConvert 反解析decode方法</p>
<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>
@@ -61,22 +61,22 @@
<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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 与 ByteBuffer 的结合 </p>
<p id="json_net_bytebuffer">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从以上的方法可以看出与其他JSON框架相比Convert多了与ByteBuffer结合的方法。特别是convertTo方法加了Supplier&lt;ByteBuffer&gt;方法这么做是为了提高数据传输的性能。在大部分情况下JSON序列化得到的数据流是为了传输出去常见的场景就是HTTP+JSON接口。Convert提供ByteBuffer接口会大量减少中间临时数据的产生。大部分输出JSON数据的方法如下:
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 与 ByteBuffer 的结合 </p>
<p id="json_net_bytebuffer">&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;几乎所有的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;RedKale框架的HTTP服务内置了Convert的JSON接口避免了大量的垃圾数据产生。RedKale的HTTP是基于AIO(NIO.2)实现且存在ByteBuffer对象池response的finishJson系列方法将HTTP服务的ByteBuffer对象池传给Convert 使Convert在序列化过程中直接以UTF-8编码方式输出到ByteBuffer里输出结束后将ByteBuffer交给对象池回收从而减少大量构建bye[]、char[]所产生的临时数据。</p>
<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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 基本用法:</p>
<p>&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>
@@ -120,7 +120,7 @@
<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;在RedKale里存在默认的JsonConvert、BsonConvert对象。 只需在所有Service、Servlet中增加依赖注入资源。</p>
<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>
@@ -140,7 +140,7 @@
<span class="o">}</span>
</pre></div>
<p id="convert_diffout">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;同一类型数据通过设置新的JsonFactory可以有不同的输出。</p>
<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>
@@ -227,8 +227,8 @@
</pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 支持非空构造函数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. <b>public</b> 的非空构造函数加上 @java.beans.ConstructorProperties 注解:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 支持非空构造函数。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. <b>public</b> 的非空构造函数加上 @java.beans.ConstructorProperties 注解:</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>
@@ -256,7 +256,7 @@
<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; 2. 非<b>public</b> 的非空构造函数类自定义Creator</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. 非<b>public</b> 的非空构造函数类自定义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>
@@ -305,8 +305,8 @@
</pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 支持自定义Decode、Encode。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. 通过Factory显式的注册</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Convert 支持自定义Decode、Encode。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1. 通过Factory显式的注册</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>
@@ -328,7 +328,7 @@
<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;2. 通过JavaBean类自定义静态方法自动加载</p>
<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>
@@ -422,22 +422,22 @@
<br/>
<h3><a id="convert_bson_buffer" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>BSON的协议格式</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BSON类似Java自带的Serializable 其格式如下: <br/>
&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;2). SmallString(无特殊字符且长度小于256的字符串): length(1 byte) + byte[](utf8); 通常用于类名、字段名、枚举。 <br/>
&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;4). 数组: length(4 bytes) + byte[]... <br/>
&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;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;2. 空字符串(SmallString) <br/>
&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;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;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;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;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;4.4 字段的值Object <br/>
&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;6. SIGN_OBJECTE 标记位值固定为0xEE (short)<br/>
<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"><a href="https://github.com/wentch/redkale">RedKale</a> © <a href="https://github.com/wentch">wentch</a> &nbsp;&nbsp;&nbsp;&nbsp;欢迎加入RedKale技术交流QQ群: 527523235</span>

View File

@@ -26,46 +26,46 @@
<section class="main-content">
<h3><a id="redkale_start" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>RedKale 功能</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RedKale虽然只有1.xM大小但是麻雀虽小五脏俱全。既可作为服务器使用也可当工具包使用。作为独立的工具包提供以下功能<br/>
&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;2、convert包提供Java对象二进制的序列化和反解析功能类似Protobuf。 <br/>
&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;4、net包提供TCP/UDP服务功能 类似Mina。 <br/>
&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;6、ResourceFactory提供轻量级的依赖注入功能 类似Google Guice。 <br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RedKale虽然只有1.xM大小但是麻雀虽小五脏俱全。既可作为服务器使用也可当工具包使用。作为独立的工具包提供以下功能<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_server" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>RedKale 服务器</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RedKale作为服务器的目录如下: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>bin</b>&nbsp;&nbsp;&nbsp; 存放启动关闭脚本(start.sh、shutdown.sh、start.bat、shutdown.bat) <br/>
&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; <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; 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; persistence.xml数据库配置文件 (可选)<br/>
&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;<b>logs</b> logging.properties 配置中默认的日志存放目录。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>root</b>&nbsp; application.xml 配置中HTTP服务所需页面的默认根目录。 <br/>
<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; 存放启动关闭脚本(start.sh、shutdown.sh、start.bat、shutdown.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; persistence.xml数据库配置文件 (可选)<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>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; application.xml 配置中HTTP服务所需页面的默认根目录。 <br/>
</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RedKale启动的流程如下<br/>
&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;2、初始化 <b>&lt;resources&gt;</b> 节点中的资源。 <br/>
&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;4、初始化并启动所有<b>&lt;server&gt;</b> 节点的Server服务 (优先加载SNCP协议的Server)。 <br/>
&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;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;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;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;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;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;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;5.7、启动Server的服务监听。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;6、启动进程本身的监听服务。 <br/>
<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)。 <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;&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;&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;&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;&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;&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;&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;&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"><span class="octicon octicon-link"></span></a>基于RedKale的开发与调试</h3>
<p>&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;编写完代码可以通过启动脚本进行调试, 也可以在IDE设置项目的主类为 org.redkale.boot.Application 或者工程内定义主类进行启动调试:
<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>
@@ -73,7 +73,7 @@
<span class="n">com</span><span class="o">.</span><span class="na">swyc</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;若需要调试单个Service可以通过 <b>Application.singleton</b> 方法进行调试: </p>
<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>
@@ -81,23 +81,23 @@
<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;Application.singleton 运行流程与通过bin脚本启动的流程基本一致区别在于singleton运行时不会启动Server和Application自身的服务监听。RedKale提倡接入层(Servlet)与业务层(Service)分开Service在代码上不能依赖于Servlet因此调试Service自身逻辑时不需要启动接入层服务(类似WebSocket依赖Servlet的功能除外)。 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Application.singleton 运行流程与通过bin脚本启动的流程基本一致区别在于singleton运行时不会启动Server和Application自身的服务监听。RedKale提倡接入层(Servlet)与业务层(Service)分开Service在代码上不能依赖于Servlet因此调试Service自身逻辑时不需要启动接入层服务(类似WebSocket依赖Servlet的功能除外)。 </p>
<h3><a id="redkale_deploy" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>RedKale 架构部署</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;通常一个系统会分为三层接入层、业务层、数据层。对应到RedKale的组件是 Servlet、Service、Source。大部分系统提供的是HTTP服务为了方便演示RedKale从集中式到分布式的变化以一个简单的HTTP服务作为范例。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;开发一个极简单的小论坛系统。包含三个模块: <br/>
&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;帖子模块 ForumSerivice: &nbsp;&nbsp;&nbsp;&nbsp;提供看帖、发帖、删帖等功能, ForumServlet作为接入层。<br/>
&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;其中数据源有: <br/>
&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;CacheSource: &nbsp;&nbsp; 仅供UserSerivice用于存放session的缓存Servicename为 usersessions, 且session只存放用户ID( int 类型)。<br/>
<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;<b>1、单点部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在早期用户量很少或者开发、调试环境中只需部署一个进程就可满足需求。 </p>
<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;如上图所有模块的HttpServlet、Service与Source数据库操作全部署在一起。 application.xml作简单的配置即可:</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>
@@ -106,10 +106,10 @@
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>2、多点部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在生产环境需要避免单点问题一个服务一般会部署多套。在此做个简单的容灾部署最前端部署一个nginx作反向代理和负载均衡服务器后面部署两套系统。 </p>
<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;如上图两个进程间的Serivce都是本地模式两者会通过SNCP服务保持数据同步若DataSource开启了数据缓存也会自动同步。两套的配置文件相同配置如下:</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>
@@ -145,11 +145,11 @@
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>3、分层部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;随着业务的复杂度增加,接入层与业务层混在一起会越来越难部署和维护,因此需要进行分层部署。 </p>
<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;如上图对HttpServlet与Service进行了分离。每个接入层的Service都是远程模式业务层只需提供SNCP供远程调用。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接入层中每个进程的配置相同,配置如下:</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>
@@ -171,7 +171,7 @@
<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;业务层中每个进程的配置相同,配置如下:</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>
@@ -197,11 +197,11 @@
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>4、微服务部署</b></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;当用户量和发帖量增加到上百万的时候,明显地将所有模块的服务部署到一个进程里是不行的。 因此需要将Service服务都独立部署形成微服务架构。</p>
<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;如上图将Serivice都独立部署并进行容灾部署当然如果有需要Servlet之间、Source都可以各自分离独立部署。不同类型的Service之间都是远程模式调用。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;接入层中每个进程的配置相同,配置如下:</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>
@@ -234,7 +234,7 @@
<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;用户模块UserService服务群中各个进程的配置相同配置如下:</p>
<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>
@@ -266,7 +266,7 @@
<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;通知模块NotifyService服务群中各个进程的配置相同配置如下:</p>
<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>
@@ -295,7 +295,7 @@
<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;帖子模块ForumService服务群中各个进程的配置相同配置如下:</p>
<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>
@@ -323,8 +323,8 @@
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<b>5、API网关式部署</b></p>
<p>&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>
<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>
@@ -377,9 +377,9 @@
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从代码看出UserServiceGateWay继承了UserService 确保了UserService对外的服务接口不变上面代码是用户量在600-800万之间的写法通过简单的用户ID分段根据不同用户ID调不同的服务节点。</p>
<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;如上图网关下的UserService部署分三类 userservice_reg只用于注册用户userservice_mob提供查询手机号码与用户ID间的关系的服务userservice_node按用户段提供已有用户的服务。且每个UserService的实例在UserServiceGateWay都是远程模式。每种类型可以部署多个节点为了结构图简单上图每个类型只部署一个节点。UserServiceGateWay192.168.50.110、192.168.50.111)的配置如下:</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>
@@ -423,8 +423,8 @@
<span class="nt">&lt;/server&gt;</span>
<span class="nt">&lt;/application&gt;</span></pre></div>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上几种部署方式的范例可以看出RedKale提供了非常强大的架构集中式到微服务架构不需要增加修改一行代码即可随意切换即使网关式部署也只是新增很少的代码就可切换且不影响其他服务。复杂的系统都可以如小系统般快速地开发出来。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了降低接入层与业务层代码的耦合, 可以将Service分接口与实现两个类接入层只加载接口包、业务层使用实现包。
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上几种部署方式的范例可以看出RedKale提供了非常强大的架构集中式到微服务架构不需要增加修改一行代码即可随意切换即使网关式部署也只是新增很少的代码就可切换且不影响其他服务。复杂的系统都可以如小系统般快速地开发出来。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了降低接入层与业务层代码的耦合, 可以将Service分接口与实现两个类接入层只加载接口包、业务层使用实现包。
</p>
<br/>

View File

@@ -26,15 +26,15 @@
<section class="main-content">
<h3><a id="service_intro" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>Service 组件介绍</h3>
<p>&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; 为了能确保本地模式与远程模式自由切换对Service的实现类有一定的约束: <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1. Service实现类会被继承不能修饰为 <span style="color: #0000FF;">final</span> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. 带@MultiRun注解的方法会被重载不能修饰为 <span style="color: #0000FF;">final</span> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RedKale进程启动时扫描可加载的Service实现类根据配置文件配置的模式采用JDK 8内置的ASM技术动态生成相应的Service临时类进行实例化并注册到ResourceFactory同其他Service、Servlet依赖注入。
<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实现类会被继承不能修饰为 <span style="color: #0000FF;">final</span> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2. 带@MultiRun注解的方法会被重载不能修饰为 <span style="color: #0000FF;">final</span> <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RedKale进程启动时扫描可加载的Service实现类根据配置文件配置的模式采用JDK 8内置的ASM技术动态生成相应的Service临时类进行实例化并注册到ResourceFactory同其他Service、Servlet依赖注入。
</p>
<h3><a id="service_local" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>Service 本地模式</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;以一个简单的UserService类范例来说明动态生成的两种模式临时类。UserService提供查询用户、注册、登陆、修改用户名功能:</br></p>
<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>
@@ -87,7 +87,7 @@
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态生成的本地模式UserService</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态生成的本地模式UserService</p>
<div class="highlight"><pre><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="kd">class</span><span class="o">})</span>
@@ -137,7 +137,7 @@
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上等价的代码可以看出来本地模式Service会重载被@MultiRun注解的方法。@MultiRun有以下几个参数: </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上等价的代码可以看出来本地模式Service会重载被@MultiRun注解的方法。@MultiRun有以下几个参数: </p>
<div class="highlight"><pre><span class="kd">public</span> <span class="nd">@interface</span> <span class="n">MultiRun</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>
@@ -148,7 +148,7 @@
<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;在动态生成的远程模式UserService时会根据不同参数生成相应的方法。若一个Service类没有含@MultiRun注解的方法那么动态类只会重载toString方法。当UserService服务仅需要部署一个进程由于没有其他等同服务的进程因此在UserService实例化时_client会赋值为null。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在动态生成的远程模式UserService时会根据不同参数生成相应的方法。若一个Service类没有含@MultiRun注解的方法那么动态类只会重载toString方法。当UserService服务仅需要部署一个进程由于没有其他等同服务的进程因此在UserService实例化时_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>
@@ -169,10 +169,10 @@
<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;如上配置若当前进程所在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>
<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"><span class="octicon octicon-link"></span></a>Service 远程模式</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态生成的远程模式UserService</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;动态生成的远程模式UserService</p>
<div class="highlight"><pre><span class="nd">@Resource</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="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>
@@ -233,7 +233,7 @@
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上代码可以看出来远程模式Service是根据本地模式Service临时类动态生成的。远程类执行方法时通过SNCP协议将参数序列化并带上当前方法信息传输到远程服务器上执行完后将结果流反解析并返回, 其流程与WebService类似。与WebService最大的区别在于远程模式的Service允许修改参数本身的内容。范例如下</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;由以上代码可以看出来远程模式Service是根据本地模式Service临时类动态生成的。远程类执行方法时通过SNCP协议将参数序列化并带上当前方法信息传输到远程服务器上执行完后将结果流反解析并返回, 其流程与WebService类似。与WebService最大的区别在于远程模式的Service允许修改参数本身的内容。范例如下</p>
<div class="highlight"><pre><span class="cm">/**</span>
<span class="cm"> * 由于该方法在处理过程中修改了参数bean的内容为了保证本地模式与远程模式的一致性需要提供@DynCall回调接口</span>
<span class="cm"> *</span>
@@ -279,16 +279,19 @@
<span class="o">}</span>
<span class="o">}</span>
</pre></div>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;生成远程模式Service时发现参数带有@DynCall注解的方法在远程调用返回结果时会进行回调处理。</p>
<br/>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;异步调用 </p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;远程模式不仅对@DynCall注解进行处理而且对方法含有 <b>java.nio.channels.CompletionHandler</b> 的参数也进行异步特殊处理。异步调用对远程模式非常有意义可以减少同步方式对当前线程的占用时间。也给Source组件的异步调用提供了基础。</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;生成远程模式Service时发现参数带有@DynCall注解的方法在远程调用返回结果时会进行回调处理。</p>
<h3><a id="service_async" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>Service 异步调用</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;远程模式不仅对@DynCall注解进行处理而且对方法含有 <b>java.nio.channels.CompletionHandler</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">update</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">@DynAttachment</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;如上图DataSourceService的源码当DataSource为本地实例时异步接口(含<b>CompletionHandler</b>参数的)与同步接口执行流程相同。当DataSource为远程模式时调用异步接口时通信接口发到远程服务器时CompletionHandler参数的值传<b>null</b>返回数据后再调用本地的CompletionHandler参数值执行。</p>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;如上图DataSourceService的源码当DataSource为本地实例时异步接口(含<b>CompletionHandler</b>参数的)与同步接口执行流程相同。当DataSource为远程模式时调用异步接口时通信接口发到远程服务器时CompletionHandler参数的值传<b>null</b>返回数据后再调用本地的CompletionHandler参数值执行。<br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;异步调用方式是提高服务并发性的有效手段特别是在远程模式Service比较多的情况下效果更明显。以HTTP服务为例在Tomcat刚刚改版成NIO的时候网上随处可见都是大谈NIO性能比BIO多好认为BIO与NIO的不同是BIO往往会引入多线程每个连接一个单独的线程而NIO则是使用单线程或者只使用少量的多线程每个连接共用一个线程。
</p>
<footer class="site-footer">
<span class="site-footer-owner"><a href="https://github.com/wentch/redkale">RedKale</a> © <a href="https://github.com/wentch">wentch</a> &nbsp;&nbsp;&nbsp;&nbsp;欢迎加入RedKale技术交流QQ群: 527523235</span>
</footer>

View File

@@ -26,16 +26,16 @@
<section class="main-content">
<h3><a id="source_intro" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>Source 组件介绍</h3>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Source 提供两种类型的数据源DataSource 和 CacheSource。DataSource 为数据库或内存数据库提供类似JPA、Hibernate的接口与功能。CacheSource 为缓存数据 提供类似Memcached、Redis的接口和功能。两者也提供了异步接口(基于<a href="service.html#service_remote" target="_blank">远程模式的Service</a>)。<br/></p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Source 提供两种类型的数据源DataSource 和 CacheSource。DataSource 为数据库或内存数据库提供类似JPA、Hibernate的接口与功能。CacheSource 为缓存数据 提供类似Memcached、Redis的接口和功能。两者也提供了异步接口(基于<a href="service.html#service_remote" target="_blank">远程模式的Service</a>)。<br/></p>
<h3><a id="datasource_study" class="anchor" href="#" aria-hidden="true"><span class="octicon octicon-link"></span></a>DataSource 入门</h3>
<p>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与JPA相比DataSource有以下几个特点<br/>
&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; 2. 提供分布式的主键自增功能。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3. 提供动态修改数据库连接参数功能。 <br/>
&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; 5. 提供进程间缓存自动同步功能。 <br/>
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;与JPA相比DataSource有以下几个特点<br/>
&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. 提供动态修改数据库连接参数功能。 <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/>
</p>
<p>未完待续…… <br/>
</p>