﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>语源科技BlogJava-捏造的信仰的博客</title><link>http://www.blogjava.net/yidinghe/</link><description>汗臭味的男人自有汗臭味男人的味道！</description><language>zh-cn</language><lastBuildDate>Mon, 13 Apr 2026 08:58:02 GMT</lastBuildDate><pubDate>Mon, 13 Apr 2026 08:58:02 GMT</pubDate><ttl>60</ttl><item><title>一个简单的 RBAC 鉴权框架的设计</title><link>http://www.blogjava.net/yidinghe/archive/2012/11/27/391233.html</link><dc:creator>捏造的信仰</dc:creator><author>捏造的信仰</author><pubDate>Tue, 27 Nov 2012 04:21:00 GMT</pubDate><guid>http://www.blogjava.net/yidinghe/archive/2012/11/27/391233.html</guid><wfw:comment>http://www.blogjava.net/yidinghe/comments/391233.html</wfw:comment><comments>http://www.blogjava.net/yidinghe/archive/2012/11/27/391233.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yidinghe/comments/commentRss/391233.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yidinghe/services/trackbacks/391233.html</trackback:ping><description><![CDATA[（本文沿着思路来写，不会一开始就给出最后结论。）<br /><br />很多项目需要对用户操作进行鉴权。它们的需求可以归纳为下面几点：<br />1、基于角色的权限控制，一个用户可能被授予多个角色；<br />2、用户对同一条记录的不同操作（如查看和修改）需要分别授权；<br />3、记录之间可能存在父子关系，子记录的权限自动从父记录继承，不需要明确授权。<br /><br />所以，可以看出这个权限模型存在四个基本要素：用户、角色、操作、记录。<br /><strong>用户</strong>：实际进行操作的单位。<br /><strong>角色</strong>：用户进行操作时的身份。<br /><strong>操作</strong>：用户执行的与记录有关的动作。<br /><strong>记录</strong>：被操作的对象。<br /><br />因为鉴权只针对角色而非用户，所以一个鉴权应该可以描述为：<strong>判断<u>某角色</u>是否对<u>某记录</u>拥有<u>某操作</u>的权限</strong>。<br /><br />可以看出，每个权限都是一个&#8220;<strong>角色&#8212;操作&#8212;记录</strong>&#8221;的三要素关联关系。如果我们要设计一张表保存所有授权，那么这张表至少应该包含这三个字段。<br /><br />那么问题来了：随着记录的增加，这张表的记录数将呈级数增长，特别是记录之间存在父子关系的情况下，为父记录授权就意味着同样要为所有子记录授权，删除一条授权也会造成大量的查询和更新，这张表的维护将成为噩梦，这样的表设计没有实用性。<br /><br />造成这种情况的根本原因是，记录是经常变化的，而鉴权规则很少改变，二者之间存在脱节。<br /><br />在这里我们不得不重新思考授权的本质：<strong>授权本来就不是针对某条具体的记录的</strong>。以博客系统为例，&#8220;作者有权删除其创建的文章&#8221;这个规则中，角色是&#8220;作者&#8221;，操作是&#8220;删除&#8221;，而记录呢？&#8220;作者创建的文章&#8221;并不是一条具体的记录。所以说，授权是对规则的描述，它针对的不是具体的记录，而是更抽象的东西。<br /><br />这种更抽象的东西，我们暂把它叫做&#8220;资源&#8221;。那么鉴权的三要素，应该称作&#8220;<strong>角色&#8212;操作&#8212;资源</strong>&#8221;。资源是对记录的抽象，就如角色是对用户的抽象一样。这样，一条权限就变成了完全抽象的：它既不针对具体的某个用户，也不针对具体的某条记录，它完全是对规则的描述。当一个用户对一条记录的操作需要鉴权时，需要进行映射，将用户映射到角色，将记录映射到资源，然后再搜索是否寻在允许的授权。<br /><br />因为&#8220;用户&#8212;角色&#8221;是多对多的关系，&#8220;记录&#8212;资源&#8221;也是多对多的关系（比如一篇博客文章可能是&#8220;我的文章&#8221;，也可能是&#8220;别人的文章&#8221;），所以<strong>&#8220;用户&#8212;操作&#8212;记录&#8221;先要被映射到&#8220;角色[]&#8212;操作&#8212;资源[]&#8221;（[]表示有多个），然后再从匹配关系的组合中搜索是否存在允许的授权</strong>。如果存在则表示鉴权通过，否则鉴权不通过。<br /><br />至此为止，权限表设计已经从&#8220;<strong>角色&#8212;操作&#8212;记录</strong>&#8221;改为&#8220;<strong>角色&#8212;操作&#8212;资源</strong>&#8221;，它符合&#8220;授权的本质&#8221;，所以不会有大量的级联查询和更新。但它仍然存在两个问题：1）因为存在角色与资源的多对多组合，所以每次鉴权需要进行大量的判断。2）我们没有办法实现从记录到资源的映射，因为两者并没有直接关联。为什么这么说呢？以博客系统为例，一篇文章在作者面前可以被映射为&#8220;我的文章&#8221;，在管理员面前可以被映射为&#8220;普通文章&#8221;，也许还会存在其他的映射，这是无法确定的。我们需要仔细考察这里面的关系。<br /><br />经过仔细考察，我发现这两个问题其实是有关联的。我们需要重新审视资源的概念：资源不是独立存在的，而是与角色关联的，不同的角色需要面对不同的资源。比如博客系统中，管理员面对用户、角色等资源，而普通用户则面对文章、博客等资源。所以记录到资源的映射与角色有着密切关系，比如一篇文章在博客作者面前要么是&#8220;我的文章&#8221;，要么是&#8220;别人的文章&#8221;，而在管理员面前要么是&#8220;普通文章&#8221;，要么是&#8220;其他文章&#8221;。这是很合理的：一条记录在不同的角色面前以不同的角度呈现。<br /><br />所以通过角色，我们可以将&#8220;用户&#8212;操作&#8212;记录&#8221;映射到&#8220;角色&#8212;操作&#8212;资源&#8221;的步骤改为：<strong>首先完成用户到角色的映射，然后对每种角色，列出记录到资源的映射，然后搜索是否存在允许的授权。</strong>这样能够明显减少判断的次数。<br /><br />我们还要考虑记录的继承关系。这个逻辑不复杂：当一条记录搜索不到授权时，还要获取其父记录并搜索父记录的授权。直到所有的父记录都找不到授权，才能返回授权不通过。<br /><br />然后我们要考虑同步：对同一个&#8220;角色（不是用户，因为这样同步范围更大）&#8212;操作&#8212;记录（不是资源，因为这样搜索更精准）&#8221;的鉴权需要进行同步锁，这样可以避免重复搜索浪费资源。<br /><br />最后我们要考虑如何缓存。通常为了提高鉴权效率，所有已经判断的授权都要缓存起来可以避免重复搜索。缓存是对记录（而非资源）授权的缓存，即缓存&#8220;用户/角色&#8212;操作&#8212;记录&#8221;，这样可以避免重复搜索父记录授权。<br /><br />当授权变更时，缓存如何维护？这个问题也要考虑。当添加一条授权时，我们不需要关心，因为经过一段时间的搜索，相应的缓存记录就会自动补充起来；当一条&#8220;角色&#8212;操作&#8212;资源&#8221;授权被删除时，需要删除：1）所有对应的&#8220;角色&#8212;操作&#8212;记录&#8221;缓存；2）找到角色对应的用户，删除所有对应的&#8220;用户&#8212;操作&#8212;记录&#8221;缓存。这个过程效率当然可能不高，但考虑到删除授权本身不会很频繁，所以应该能够接受。<br /><br />至此为止，表设计和鉴权的逻辑过程我们都清晰了，然后是如何实现。鉴权过程的实现关键在于映射，特别是从记录到资源的映射。这个映射是不可能光靠数据库配置来完成的，必须要有代码逻辑，比如博客系统的文章映射到&#8220;我的文章&#8221;，就需要判断该用户是不是文章的作者。这样的逻辑我们可以抽象为一个接口：<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />&nbsp;*&nbsp;将记录映射到资源的接口。不同类型的记录应该有不同的实现类<br />&nbsp;</span><span style="color: #008000; ">*/</span><br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">interface</span>&nbsp;ResourceMapper&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/**</span><span style="color: #008000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;根据角色将记录映射到资源<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080; ">@param</span><span style="color: #008000; ">&nbsp;recordId&nbsp;记录ID<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080; ">@param</span><span style="color: #008000; ">&nbsp;roleId&nbsp;&nbsp;&nbsp;角色ID<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080; ">@return</span><span style="color: #008000; ">&nbsp;资源ID<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span><br />&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;getResourceId(Long&nbsp;recordId,&nbsp;Long&nbsp;roleId);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">/**</span><span style="color: #008000; "><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;搜索父记录，如果不存在则返回&nbsp;null<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080; ">@param</span><span style="color: #008000; ">&nbsp;recordId&nbsp;&nbsp;记录ID<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080; ">@return</span><span style="color: #008000; ">&nbsp;父记录ID，如果不存在则返回&nbsp;null<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000; ">*/</span><br />&nbsp;&nbsp;&nbsp;&nbsp;Long&nbsp;getParent(Long&nbsp;recordId);<br />}</div><br />至于其他的部分，本文就不赘述了。我要赶紧去实现一个看看。<br /><br />最后总结一下这个鉴权系统的主要部分：<br />1、数据库设计：角色表（ID，名称），鉴权表（角色，操作，资源），资源表（ID，名称，角色【如果为空则表示对所有角色可见】）<br />2、鉴权的核心逻辑：映射 + 搜索<br />3、鉴权的外围逻辑：缓存<br />4、需要用户实现的逻辑：映射接口 ResourceMapper<img src ="http://www.blogjava.net/yidinghe/aggbug/391233.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yidinghe/" target="_blank">捏造的信仰</a> 2012-11-27 12:21 <a href="http://www.blogjava.net/yidinghe/archive/2012/11/27/391233.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何在 apache commons-httpclient 4.2 中使用自定义的 DNS 解析</title><link>http://www.blogjava.net/yidinghe/archive/2012/11/10/391147.html</link><dc:creator>捏造的信仰</dc:creator><author>捏造的信仰</author><pubDate>Sat, 10 Nov 2012 11:18:00 GMT</pubDate><guid>http://www.blogjava.net/yidinghe/archive/2012/11/10/391147.html</guid><wfw:comment>http://www.blogjava.net/yidinghe/comments/391147.html</wfw:comment><comments>http://www.blogjava.net/yidinghe/archive/2012/11/10/391147.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yidinghe/comments/commentRss/391147.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yidinghe/services/trackbacks/391147.html</trackback:ping><description><![CDATA[要想使&nbsp;DefaultHttpClient 对象使用自定义的 DNS 解析（比如将 blogjava.net 关联到 127.0.0.1，使其访问 "http://blogjava.net" 时请求本地服务器），可以用下面的办法（我在官网上没找到相关文章，是看了源代码自己琢磨出来的，也不是道是不是标准做法）<br /><br /><div style="background-color:#eeeeee;font-size:13px;border:1px solid #CCCCCC;padding-right: 5px;padding-bottom: 4px;padding-left: 4px;padding-top: 4px;width: 98%;word-break:break-all"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">import</span>&nbsp;org.apache.http.HttpResponse;<br /><span style="color: #0000FF; ">import</span>&nbsp;org.apache.http.client.methods.HttpGet;<br /><span style="color: #0000FF; ">import</span>&nbsp;org.apache.http.conn.ClientConnectionOperator;<br /><span style="color: #0000FF; ">import</span>&nbsp;org.apache.http.conn.DnsResolver;<br /><span style="color: #0000FF; ">import</span>&nbsp;org.apache.http.conn.scheme.SchemeRegistry;<br /><span style="color: #0000FF; ">import</span>&nbsp;org.apache.http.impl.client.DefaultHttpClient;<br /><span style="color: #0000FF; ">import</span>&nbsp;org.apache.http.impl.conn.BasicClientConnectionManager;<br /><span style="color: #0000FF; ">import</span>&nbsp;org.apache.http.impl.conn.DefaultClientConnectionOperator;<br /><br /><span style="color: #0000FF; ">import</span>&nbsp;java.net.InetAddress;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.net.UnknownHostException;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.util.HashMap;<br /><span style="color: #0000FF; ">import</span>&nbsp;java.util.Map;<br /><br /><span style="color: #008000; ">/**</span><span style="color: #008000; "><br />&nbsp;*&nbsp;在&nbsp;httpclient&nbsp;4.2&nbsp;中使用自定义的&nbsp;DNS&nbsp;解析<br />&nbsp;</span><span style="color: #008000; ">*/</span><br /><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;CustomDnsResolverDemo&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;main(String[]&nbsp;args)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;Exception&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;创建自定义的&nbsp;ConnectionManager</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BasicClientConnectionManager&nbsp;connectionManager&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;BasicClientConnectionManager()&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">protected</span>&nbsp;ClientConnectionOperator&nbsp;createConnectionOperator(SchemeRegistry&nbsp;schreg)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;DefaultClientConnectionOperator(schreg,&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;MyDnsResolver());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;创建&nbsp;HttpClient&nbsp;对象</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;DefaultHttpClient&nbsp;httpclient&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;DefaultHttpClient(connectionManager);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;构造请求</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpGet&nbsp;httpget&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;HttpGet("https://www.google.com/");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(httpget.getRequestLine());<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;发送请求并返回结果</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpResponse&nbsp;response&nbsp;=&nbsp;httpclient.execute(httpget);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(response.getEntity().getContentType());<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(response.getStatusLine());<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;这句不是必须的，只是让程序结束更快点</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;httpclient.getConnectionManager().shutdown();<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #008000; ">//</span><span style="color: #008000; ">&nbsp;自定义的&nbsp;DNS&nbsp;解析类</span><span style="color: #008000; "><br /></span>&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">class</span>&nbsp;MyDnsResolver&nbsp;<span style="color: #0000FF; ">implements</span>&nbsp;DnsResolver&nbsp;{<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">final</span>&nbsp;Map&lt;String,&nbsp;InetAddress[]&gt;&nbsp;MAPPINGS&nbsp;=&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;HashMap&lt;String,&nbsp;InetAddress[]&gt;();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;addResolve("www.google.com",&nbsp;"74.125.134.138");<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">private</span>&nbsp;<span style="color: #0000FF; ">static</span>&nbsp;<span style="color: #0000FF; ">void</span>&nbsp;addResolve(String&nbsp;host,&nbsp;String&nbsp;ip)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">try</span>&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MAPPINGS.put(host,&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;InetAddress[]{InetAddress.getByName(ip)});<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;<span style="color: #0000FF; ">catch</span>&nbsp;(UnknownHostException&nbsp;e)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@Override<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">public</span>&nbsp;InetAddress[]&nbsp;resolve(String&nbsp;host)&nbsp;<span style="color: #0000FF; ">throws</span>&nbsp;UnknownHostException&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;MAPPINGS.containsKey(host)&nbsp;?&nbsp;MAPPINGS.get(host)&nbsp;:&nbsp;<span style="color: #0000FF; ">new</span>&nbsp;InetAddress[0];<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />}</div><img src ="http://www.blogjava.net/yidinghe/aggbug/391147.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yidinghe/" target="_blank">捏造的信仰</a> 2012-11-10 19:18 <a href="http://www.blogjava.net/yidinghe/archive/2012/11/10/391147.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java示例：如何执行进程并读取输出</title><link>http://www.blogjava.net/yidinghe/archive/2012/10/26/390296.html</link><dc:creator>捏造的信仰</dc:creator><author>捏造的信仰</author><pubDate>Fri, 26 Oct 2012 12:14:00 GMT</pubDate><guid>http://www.blogjava.net/yidinghe/archive/2012/10/26/390296.html</guid><wfw:comment>http://www.blogjava.net/yidinghe/comments/390296.html</wfw:comment><comments>http://www.blogjava.net/yidinghe/archive/2012/10/26/390296.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yidinghe/comments/commentRss/390296.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yidinghe/services/trackbacks/390296.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 下面是一个例子，演示如何执行一个进程（类似于在命令行下键入命令），读取进程执行的输出，并根据进程的返回值判断是否执行成功。一般来说，进程返回 0 表示执行成功，其他值表示失败。&nbsp;&nbsp;<a href='http://www.blogjava.net/yidinghe/archive/2012/10/26/390296.html'>阅读全文</a><img src ="http://www.blogjava.net/yidinghe/aggbug/390296.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yidinghe/" target="_blank">捏造的信仰</a> 2012-10-26 20:14 <a href="http://www.blogjava.net/yidinghe/archive/2012/10/26/390296.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何提高开发效率（3）</title><link>http://www.blogjava.net/yidinghe/archive/2012/09/25/388533.html</link><dc:creator>捏造的信仰</dc:creator><author>捏造的信仰</author><pubDate>Tue, 25 Sep 2012 12:23:00 GMT</pubDate><guid>http://www.blogjava.net/yidinghe/archive/2012/09/25/388533.html</guid><wfw:comment>http://www.blogjava.net/yidinghe/comments/388533.html</wfw:comment><comments>http://www.blogjava.net/yidinghe/archive/2012/09/25/388533.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yidinghe/comments/commentRss/388533.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yidinghe/services/trackbacks/388533.html</trackback:ping><description><![CDATA[本文介绍如何更加轻松的编写代码。<br />
<br />
为什么有的代码写起来让人头昏脑胀呢？就是因为逻辑太复杂。逻辑的复杂无非体现在两个方面，要么是步骤太长，要么是条件分支（也就是需要考虑的&#8220;<span style="font-family: verdana, 'courier new'; ">例外情况</span>&nbsp;<br />
&#8221;）太多。<br />
<br />
人们处理复杂的事情，向来有一套方法，叫分而治之，它完全可以用在开发上。<br />
<br />
使用分而治之的方式编写代码，好处就是关注点减少了。把一个长的步骤分成若干个短小的步骤，那么你每次只需要关注其中的一步就可以了；把一系列复杂的判断交给不同的对象去打理，那么你的思维又可以回到主流程上来。关注点减少的结果，一方面降低了出错的可能，另一方面不会令人绞尽脑汁弄得身心疲惫。<br />
<br />
如何对复杂的逻辑分而治之呢？就本人的开发经验，我觉得有两点很重要：<br />
<br />
<strong>1、关注顶层逻辑</strong><br />
任何方法都只应该体现其顶层逻辑。比如用户登录的顶层逻辑，只有三个步骤：1）检查参数格式；2）处理逻辑；3）返回结果。<br /><div style="background-color: #eeeeee; font-size: 13px; border: 1px solid #cccccc; padding: 4px 5px 4px 4px; width: 98%; word-break: break-all; "><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000FF; ">public</span>&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;login(String&nbsp;username,&nbsp;String&nbsp;password)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">if</span>&nbsp;(!checkParameters(username,&nbsp;password)&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;<span style="color: #0000FF; ">false</span>;<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br />&nbsp; &nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">boolean</span>&nbsp;result&nbsp;=&nbsp;checkUserPassword(username,&nbsp;password);<br />&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;<span style="color: #0000FF; ">return</span>&nbsp;result;<br />}</div>这是顶层逻辑，将这三句话写好之后，我们再分别去实现每个步骤，而每个步骤当中又只包含顶层逻辑。这样做有效的减少了关注点，让代码写起来更加轻松。<br /><br /><strong>2、职责分明</strong><br />我们生活在一个分工精细的社会，任何事情都能（至少在名义上）找到相应的人对其负责。业务逻辑也是一样，字符串的处理、XML的解析、连接的打开关闭、日期时间的校验，这些逻辑都应该交给相应的类去处理，不要一窝蜂的都写在一个方法里面，这样写出来的东西是一团乱麻，写了一半可能你自己都不知道写到哪了。<br /><br />我觉得只要做到上面这两点，面对任何复杂的逻辑都可以轻松对付，而且不易出错&#8212;&#8212;你可以想象当别人埋头苦干的时候，你却在一边轻松的听歌喝咖啡了~~<br /><img src ="http://www.blogjava.net/yidinghe/aggbug/388533.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yidinghe/" target="_blank">捏造的信仰</a> 2012-09-25 20:23 <a href="http://www.blogjava.net/yidinghe/archive/2012/09/25/388533.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何提高开发效率（2）</title><link>http://www.blogjava.net/yidinghe/archive/2012/09/21/388246.html</link><dc:creator>捏造的信仰</dc:creator><author>捏造的信仰</author><pubDate>Fri, 21 Sep 2012 05:09:00 GMT</pubDate><guid>http://www.blogjava.net/yidinghe/archive/2012/09/21/388246.html</guid><wfw:comment>http://www.blogjava.net/yidinghe/comments/388246.html</wfw:comment><comments>http://www.blogjava.net/yidinghe/archive/2012/09/21/388246.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yidinghe/comments/commentRss/388246.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yidinghe/services/trackbacks/388246.html</trackback:ping><description><![CDATA[本文介绍如何更加轻松的阅读代码。<br /><br />有人会说，阅读代码是否轻松，取决于代码的可读性吧。是的，而且请不要误会，本文不是要介绍编码规范。不管代码本身的可读性如何，你都可以找到更好的手段去帮助阅读。下面是几个可供参考的建议：<br /><br />1、用丰富的颜色区分类型、成员、方法、变量、参数等等。例如下面两张图片，你觉得哪个阅读起来更轻松呢？<br /><img src="http://www.blogjava.net/images/blogjava_net/yidinghe/图片2.png" border="1" alt="" width="284" height="121" /><img src="http://www.blogjava.net/images/blogjava_net/yidinghe/图片1.png" border="1" alt="" width="295" height="110" /><br />颜色的区分不仅仅是为了好看，颜色越多，代码展示的信息就越丰富。特别是当有时候变量名称覆盖了成员名称的时候，一眼就能看出来。<br /><br />2、适当用空行将逻辑隔开。在下面的例子中，第一段的代码没有使用空行，看起来比较凌乱；第二段代码只是加了几个空行，逻辑马上变得清晰起来，有利于阅读。<br /><img src="http://www.blogjava.net/images/blogjava_net/yidinghe/图片3.png" border="1" alt="" width="319" height="220" /><img src="http://www.blogjava.net/images/blogjava_net/yidinghe/图片4.png" border="1" alt="" width="322" height="270" /><br /><br />3、为逻辑区块添加注释。有人说好的代码不需要注释，但一方面好的代码太少，另一方面英语不是我们母语，所以适当的加上注释是有必要的。<br /><img src="http://www.blogjava.net/images/blogjava_net/yidinghe/图片5.png" border="0" alt="" width="387" height="277" /><br />上面的代码没有加注释，虽然逻辑做了一定的整理，但要看懂还是不容易。<br /><img src="http://www.blogjava.net/images/blogjava_net/yidinghe/图片6.png" border="0" alt="" width="365" height="307" /><br />加了注释之后，看起来更轻松了。<br /><br />另外，如果代码当中的变量命名晦涩，可以用重构的方式对变量重命名，以方便阅读。<img src ="http://www.blogjava.net/yidinghe/aggbug/388246.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yidinghe/" target="_blank">捏造的信仰</a> 2012-09-21 13:09 <a href="http://www.blogjava.net/yidinghe/archive/2012/09/21/388246.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何提高开发效率（1）</title><link>http://www.blogjava.net/yidinghe/archive/2012/09/19/388102.html</link><dc:creator>捏造的信仰</dc:creator><author>捏造的信仰</author><pubDate>Wed, 19 Sep 2012 15:06:00 GMT</pubDate><guid>http://www.blogjava.net/yidinghe/archive/2012/09/19/388102.html</guid><wfw:comment>http://www.blogjava.net/yidinghe/comments/388102.html</wfw:comment><comments>http://www.blogjava.net/yidinghe/archive/2012/09/19/388102.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/yidinghe/comments/commentRss/388102.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/yidinghe/services/trackbacks/388102.html</trackback:ping><description><![CDATA[这里所说的&#8220;提高开发效率&#8221;不是指在相同的时间内做更多的事情，而是：<br /><span style="color: red; ">用更少的脑力完成同样多的事情。<br /><br /></span>为什么要用更少的脑力完成同样多的事情？因为一个人的脑力劳动同体力劳动一样，劳动强度越高，能够坚持的时间越少，人越觉得疲惫。<br /><br />想想一天只有24小时，除去8小时睡眠，8小时工作，花在自己和家人上的时间最多也就8小时（这还是很理想的情况）。如果工作很累的话，你还有多少精力留给自己和家人？<br /><br />作为开发人员，我们花费精力的事情无非就是三个：阅读代码，编写代码，运行代码。在这三件事情上减少脑力负担可以令工作更轻松。我希望能通过一系列文章帮助大家用更少的脑力阅读、编写和运行代码。<br /><br />不过在这之前，有一件任务必须先完成，那就是：优化工作环境。<br /><br />你的工作环境有多大的优化余地？请尝试考虑一下下面的问题：<br /><div><ul><li>你的椅子过高还是过低？</li><li>脖子、肩膀、腰和手腕是否酸痛？</li><li>你的周围环境是否过于嘈杂？</li><li>你桌面上的物件是整洁的还是凌乱的？</li><li>你的鼠标是否不灵？</li><li>你的显示屏上是否有层灰？</li><li>你的笔记本是否热到让你不敢把手放在键盘上？</li><li>你的内存是否够用？<br /></li><li>你的硬盘是否足够快？</li></ul></div><div>这些方面都应该尽可能的做调整，不要让这些细枝末节打断你工作中的思路。<br /><br />比如说硬盘不够快的问题，如果你用 Windows 7，那么它的 ReadyBoost 特性应该好好利用，它可以加快读取文件的速度。要知道 Java IDE 通常都是非常大的，每次打开来要读取半天。当插上一支 U 盘并将其用于 ReadyBoost 之后，不管是打开项目还是编译运行，速度都会加快很多。你想象过打开 Word 文档就像打开记事本一样快吗？<br /><br />我将在接下来的文章中介绍如何用更少的脑力阅读、编写和运行代码。</div><img src ="http://www.blogjava.net/yidinghe/aggbug/388102.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/yidinghe/" target="_blank">捏造的信仰</a> 2012-09-19 23:06 <a href="http://www.blogjava.net/yidinghe/archive/2012/09/19/388102.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>