﻿<?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-给工作生活留点痕迹(haoxuewu)-文章分类-java基础知识点</title><link>http://www.blogjava.net/haoxuewu/category/51950.html</link><description>路漫漫其修远兮，吾将上下而求索</description><language>zh-cn</language><lastBuildDate>Tue, 12 Jun 2012 14:56:59 GMT</lastBuildDate><pubDate>Tue, 12 Jun 2012 14:56:59 GMT</pubDate><ttl>60</ttl><item><title>HTTP请求报文解剖 </title><link>http://www.blogjava.net/haoxuewu/articles/380633.html</link><dc:creator>陕西BOY</dc:creator><author>陕西BOY</author><pubDate>Tue, 12 Jun 2012 11:02:00 GMT</pubDate><guid>http://www.blogjava.net/haoxuewu/articles/380633.html</guid><wfw:comment>http://www.blogjava.net/haoxuewu/comments/380633.html</wfw:comment><comments>http://www.blogjava.net/haoxuewu/articles/380633.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/haoxuewu/comments/commentRss/380633.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/haoxuewu/services/trackbacks/380633.html</trackback:ping><description><![CDATA[HTTP请求报文由3部分组成（<span style="color: blue"><strong>请求行+请求头+请求体</strong></span>）： <br /><br /><img src="http://dl.iteye.com/upload/attachment/0069/3485/1a4e7e6a-6d7b-38f1-af8a-043140034c8f.jpg"  alt="" /> <br /><br />下面是一个实际的请求报文： <br /><br /><img class="magplus" title="点击查看原始大小图片" src="http://dl.iteye.com/upload/attachment/0069/3451/412b4451-2738-3ebc-b1f6-a0cc13b9697b.jpg" width="760" height="448"  alt="" /> <br /><br />&#9312;是请求方法，GET和POST是最常见的HTTP方法，除此以外还包括DELETE、HEAD、OPTIONS、PUT、TRACE。不过，当前的大多数浏览器只支持GET和POST，Spring 3.0提供了一个HiddenHttpMethodFilter，允许你通过&#8220;_method&#8221;的表单参数指定这些特殊的HTTP方法（实际上还是通过POST提交表单）。服务端配置了HiddenHttpMethodFilter后，Spring会根据_method参数指定的值模拟出相应的HTTP方法，这样，就可以使用这些HTTP方法对处理方法进行映射了。 <br /><br />&#9313;为请求对应的URL地址，它和报文头的Host属性组成完整的请求URL，&#9314;是协议名称及版本号。 <br /><br />&#9315;是HTTP的报文头，报文头包含若干个属性，格式为&#8220;属性名:属性值&#8221;，服务端据此获取客户端的信息。 <br /><br />&#9316;是报文体，它将一个页面表单中的组件值通过param1=value1&amp;param2=value2的键值对形式编码成一个格式化串，它承载多个请求参数的数据。不但报文体可以传递请求参数，请求URL也可以通过类似于&#8220;/chapter15/user.html? param1=value1&amp;param2=value2&#8221;的方式传递请求参数。 <br /><br />对照上面的请求报文，我们把它进一步分解，你可以看到一幅更详细的结构图： <br /><br /><img src="http://dl.iteye.com/upload/attachment/0069/3487/cdc4dbbb-f98e-31d5-8270-3c37bf1c54e5.jpg"  alt="" /> <br /><br /><br />
<div class="quote_title">引用</div>
<div class="quote_div"><a href="http://www.httpwatch.com/download/" target="_blank">HttpWatch</a>是强大的网页数据分析工具，安装后将集成到Internet Explorer工具栏中。它不用代理服务器或一些复杂的网络监控工具，就能抓取请求及响应的完整信息，包括Cookies、消息头、查询参数、响应报文等，是Web应用开发人员的必备工具。</div><br /><br /><strong><span style="font-size: x-large"><font size="5">HTTP请求报文头属性</font></span></strong> <br /><br />报文头属性是什么东西呢？我们不妨以一个小故事来说明吧。 <br /><br />
<div class="quote_title">引用</div>
<div class="quote_div">快到中午了，张三丰不想去食堂吃饭，于是打电话叫外卖：老板，我要一份[鱼香肉丝]，要12：30之前给我送过来哦，我在江湖湖公司研发部，叫张三丰。</div><br /><br />这里，你要[鱼香肉丝]相当于HTTP报文体，而&#8220;12：30之前送过来&#8221;，你叫&#8220;张三丰&#8221;等信息就相当于HTTP的报文头。它们是一些附属信息，帮忙你和饭店老板顺利完成这次交易。 <br /><br />请求HTTP报文和响应HTTP报文都拥有若干个报文关属性，它们是为协助客户端及服务端交易的一些附属信息。 <br /><br /><br /><strong><span style="font-size: large"><font size="4">常见的HTTP请求报文头属性</font></span></strong> <br /><br /><strong>Accept</strong> <br /><br />请求报文可通过一个&#8220;Accept&#8221;报文头属性告诉服务端 客户端接受什么类型的响应。 <br /><br />如下报文头相当于告诉服务端，俺客户端能够接受的响应类型仅为纯文本数据啊，你丫别发其它什么图片啊，视频啊过来，那样我会歇菜的~~~： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>Accept:text/plain&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="0" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">Accept:text/plain</pre><br /><br />Accept属性的值可以为一个或多个MIME类型的值，关于MIME类型，大家请参考：<a href="http://en.wikipedia.org/wiki/MIME_type" target="_blank">http://en.wikipedia.org/wiki/MIME_type</a> <br /><br /><strong>Cookie</strong> <br /><br />客户端的Cookie就是通过这个报文头属性传给服务端的哦！如下所示： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>Cookie:&nbsp;$Version=</span><span class="number"><font color="#c00000">1</font></span><span>;&nbsp;Skin=</span><span class="keyword">new</span><span>;jsessionid=5F4771183629C9834F8382E23BE13C4C&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="1" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">  Cookie: $Version=1; Skin=new;jsessionid=5F4771183629C9834F8382E23BE13C4C
</pre><br />服务端是怎么知道客户端的多个请求是隶属于一个Session呢？注意到后台的那个jsessionid=5F4771183629C9834F8382E23BE13C4C木有？原来就是通过HTTP请求报文头的Cookie属性的jsessionid的值关联起来的！（当然也可以通过重写URL的方式将会话ID附带在每个URL的后面哦）。 <br /><br /><br /><strong>Referer</strong> <br /><br />表示这个请求是从哪个URL过来的，假如你通过google搜索出一个商家的广告页面，你对这个广告页面感兴趣，鼠标一点发送一个请求报文到商家的网站，这个请求报文的Referer报文头属性值就是http://www.google.com。 <br />
<div class="quote_title">引用</div>
<div class="quote_div"><br />唐僧到了西天. <br />如来问：侬是不是从东土大唐来啊？ <br />唐僧：厉害！你咋知道的！ <br />如来：呵呵，我偷看了你的Referer... <br /></div><br /><br />很多貌似神奇的网页监控软件（如著名的 <a href="http://www.51.la/" target="_blank">我要啦</a>），只要在你的网页上放上一段JavaScript，就可以帮你监控流量，全国访问客户的分布情况等报表和图表，其原理就是通过这个Referer及其它一些HTTP报文头工作的。 <br /><br /><strong>Cache-Control</strong> <br /><br />对缓存进行控制，如一个请求希望响应返回的内容在客户端要被缓存一年，或不希望被缓存就可以通过这个报文头达到目的。 <br /><br />如以下设置，相当于让服务端将对应请求返回的响应内容不要在客户端缓存： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>Cache-Control:&nbsp;no-cache&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="2" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">Cache-Control: no-cache</pre><br /><br /><strong><span style="font-size: large"><font size="4">其它请求报文头属性</font></span></strong> <br /><br />参见：<a href="http://en.wikipedia.org/wiki/List_of_HTTP_header_fields" target="_blank">http://en.wikipedia.org/wiki/List_of_HTTP_header_fields</a> <br /><br /><strong><span style="font-size: large"><font size="4">如何访问请求报文头</font></span></strong> <br /><br />由于请求报文头是客户端发过来的，服务端当然只能读取了，以下是HttpServletRequest一些用于读取请求报文头的API： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="comment">//获取请求报文中的属性名称 </span><span>&nbsp;&nbsp;</span></li><li><span>java.util.Enumeration&lt;java.lang.String&gt;&nbsp;&nbsp;&nbsp;getHeaderNames(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="comment">//获取指定名称的报文头属性的值 </span><span>&nbsp;&nbsp;</span></span></li><li><span>java.lang.String&nbsp;getHeader(java.lang.String&nbsp;name)&nbsp;&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="3" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">//获取请求报文中的属性名称
java.util.Enumeration&lt;java.lang.String&gt;	getHeaderNames();

//获取指定名称的报文头属性的值
java.lang.String getHeader(java.lang.String name) 
</pre><br /><br />由于一些请求报文头属性&#8220;太著名&#8221;了，因此HttpServletRequest为它们提供了VIP的API： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="comment">//获取报文头中的Cookie(读取Cookie的报文头属性） </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;Cookie[]&nbsp;&nbsp;&nbsp;getCookies()&nbsp;; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="comment">//获取客户端本地化信息（读取&nbsp;Accept-Language&nbsp;的报文头属性） </span><span>&nbsp;&nbsp;</span></span></li><li><span>java.util.Locale&nbsp;&nbsp;&nbsp;&nbsp;getLocale()&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="comment">//获取请求报文体的长度（读取Content-Length的报文头属性） </span><span>&nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">int</span><span>&nbsp;getContentLength();&nbsp;&nbsp;</span></span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="4" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">//获取报文头中的Cookie(读取Cookie的报文头属性）
 Cookie[]	getCookies() ;

//获取客户端本地化信息（读取 Accept-Language 的报文头属性）
java.util.Locale	getLocale() 

//获取请求报文体的长度（读取Content-Length的报文头属性）
int getContentLength();
</pre><br /><br />HttpServletRequest可以通过 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>HttpSession&nbsp;getSession()&nbsp;&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="5" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">HttpSession getSession() </pre><br />获取请求所关联的HttpSession,其内部的机理是通过读取请求报文头中Cookie属性的JSESSIONID的值，在服务端的一个会话Map中，根据这个JSESSIONID获取对应的HttpSession的对象。（这样，你就不会觉得HttpSession很神秘了吧，你自己也可以做一个类似的会话管理&nbsp;<img src="http://www.iteye.com/images/smiles/icon_surprised.gif"  alt="" /> ） <br /><br /><strong><span style="font-size: x-large"><font size="5">HTTP响应报文解剖</font></span></strong> <br /><br /><strong><span style="font-size: large"><font size="4">响应报文结构</font></span></strong> <br /><br />HTTP的响应报文也由三部分组成（<strong><span style="color: blue">响应行+响应头+响应体</span></strong>）： <br /><br /><img src="http://dl.iteye.com/upload/attachment/0069/3489/0236098f-1a98-3a4f-ba6c-4a44c6ec4ed0.jpg"  alt="" /> <br /><br />以下是一个实际的HTTP响应报文： <br /><br /><img src="http://dl.iteye.com/upload/attachment/0069/3492/bddb00b6-a3e1-3112-a4f4-4b3cb8687c70.jpg"  alt="" /> <br /><br />&#9312;报文协议及版本； <br />&#9313;状态码及状态描述； <br />&#9314;响应报文头，也是由多个属性组成； <br />&#9315;响应报文体，即我们真正要的&#8220;干货&#8221;。 <br /><br /><strong><span style="font-size: large"><font size="4">响应状态码</font></span></strong> <br /><br />和请求报文相比，响应报文多了一个&#8220;响应状态码&#8221;，它以&#8220;清晰明确&#8221;的语言告诉客户端本次请求的处理结果。 <br /><br />HTTP的响应状态码由5段组成： <br /><br />
<ul><li>1xx 消息，一般是告诉客户端，请求已经收到了，正在处理，别急...</li><li>2xx 处理成功，一般表示：请求收悉、我明白你要的、请求已受理、已经处理完成等信息.</li><li>3xx 重定向到其它地方。它让客户端再发起一个请求以完成整个处理。</li><li>4xx 处理发生错误，责任在客户端，如客户端的请求一个不存在的资源，客户端未被授权，禁止访问等。</li><li>5xx 处理发生错误，责任在服务端，如服务端抛出异常，路由出错，HTTP版本不支持等。 </li></ul><br /><br />以下是几个常见的状态码： <br /><br /><strong>200 OK</strong> <br /><br />你最希望看到的，即处理成功！ <br /><br /><strong>303 See Other</strong> <br /><br />我把你redirect到其它的页面，目标的URL通过响应报文头的Location告诉你。 <br />
<div class="quote_title">引用</div>
<div class="quote_div">悟空：师傅给个桃吧，走了一天了<img src="http://www.iteye.com/images/smiles/icon_confused.gif"  alt="" /> <br />唐僧：我哪有桃啊！去王母娘娘那找吧<img src="http://www.iteye.com/images/smiles/icon_wink.gif"  alt="" /> </div><br /><br /><strong>304 Not Modified</strong> <br /><br />告诉客户端，你请求的这个资源至你上次取得后，并没有更改，你直接用你本地的缓存吧，我很忙哦，你能不能少来烦我啊！ <br /><br /><strong>404 Not Found</strong> <br /><br />你最不希望看到的，即找不到页面。如你在google上找到一个页面，点击这个链接返回404，表示这个页面已经被网站删除了，google那边的记录只是美好的回忆。 <br /><br /><strong>500 Internal Server Error</strong> <br /><br />看到这个错误，你就应该查查服务端的日志了，肯定抛出了一堆异常，别睡了，起来改BUG去吧！ <br /><br /><br />其它的状态码参见：<a href="http://en.wikipedia.org/wiki/List_of_HTTP_status_codes" target="_blank">http://en.wikipedia.org/wiki/List_of_HTTP_status_codes</a> <br /><br /><br />有些响应码，Web应用服务器会自动给生成。你可以通过HttpServletResponse的API设置状态码： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="comment">//设置状态码，状态码在HttpServletResponse中通过一系列的常量预定义了，如SC_ACCEPTED，SC_OK </span><span>&nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">void</span><span>&nbsp;&nbsp;&nbsp;&nbsp;setStatus(</span><span class="keyword">int</span><span>&nbsp;sc)&nbsp;&nbsp;&nbsp;</span></span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="6" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">//设置状态码，状态码在HttpServletResponse中通过一系列的常量预定义了，如SC_ACCEPTED，SC_OK
void	setStatus(int sc) 
</pre><br /><br /><strong><span style="font-size: large"><font size="4">常见的HTTP响应报文头属性</font></span></strong> <br /><br /><strong>Cache-Control</strong> <br /><br />响应输出到客户端后，服务端通过该报文头属告诉客户端如何控制响应内容的缓存。 <br /><br />下面，的设置让客户端对响应内容缓存3600秒，也即在3600秒内，如果客户再次访问该资源，直接从客户端的缓存中返回内容给客户，不要再从服务端获取<span style="color: gray">（当然，这个功能是靠客户端实现的，服务端只是通过这个属性提示客户端&#8220;应该这么做&#8221;，做不做，还是决定于客户端，如果是自己宣称支持HTTP的客户端，则就应该这样实现）</span>。 <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>Cache-Control:&nbsp;max-age=</span><span class="number"><font color="#c00000">3600</font></span><span>&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="7" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">Cache-Control: max-age=3600</pre><br /><br /><strong>ETag</strong> <br /><br />一个代表响应服务端资源（如页面）版本的报文头属性，如果某个服务端资源发生变化了，这个ETag就会相应发生变化。它是Cache-Control的有益补充，可以让客户端&#8220;更智能&#8221;地处理什么时候要从服务端取资源，什么时候可以直接从缓存中返回响应。 <br /><br />关于ETag的说明，你可以参见：<a href="http://en.wikipedia.org/wiki/HTTP_ETag" target="_blank">http://en.wikipedia.org/wiki/HTTP_ETag</a>。 <br />Spring 3.0还专门为此提供了一个org.springframework.web.filter.ShallowEtagHeaderFilter（实现原理很简单，对JSP输出的内容MD5，这样内容有变化ETag就相应变化了），用于生成响应的ETag，因为这东东确实可以帮助减少请求和响应的交互。 <br /><br />下面是一个ETag： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>ETag:&nbsp;</span><span class="string">"737060cd8c284d8af7ad3082f209582d"</span><span>&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="8" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">ETag: "737060cd8c284d8af7ad3082f209582d"</pre><br /><br /><strong>Location</strong> <br /><br />我们在JSP中让页面Redirect到一个某个A页面中，其实是让客户端再发一个请求到A页面，这个需要Redirect到的A页面的URL，其实就是通过响应报文头的Location属性告知客户端的，如下的报文头属性，将使客户端redirect到iteye的首页中： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>Location:&nbsp;http:</span><span class="comment">//www.iteye.com</span><span>&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="9" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">Location: http://www.iteye.com</pre><br /><br /><strong>Set-Cookie</strong> <br /><br />服务端可以设置客户端的Cookie，其原理就是通过这个响应报文头属性实现的： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>Set-Cookie:&nbsp;UserID=JohnDoe;&nbsp;Max-Age=</span><span class="number"><font color="#c00000">3600</font></span><span>;&nbsp;Version=</span><span class="number"><font color="#c00000">1</font></span><span>&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="10" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">Set-Cookie: UserID=JohnDoe; Max-Age=3600; Version=1</pre><br /><br /><br /><strong><span style="font-size: large"><font size="4">其它HTTP响应报文头属性</font></span></strong> <br /><br />更多其它的HTTP响应头报文，参见：<a href="http://en.wikipedia.org/wiki/List_of_HTTP_header_fields" target="_blank">http://en.wikipedia.org/wiki/List_of_HTTP_header_fields</a> <br /><br /><br /><strong><span style="font-size: large"><font size="4">如何写HTTP请求报文头</font></span></strong> <br /><br />在服务端可以通过HttpServletResponse的API写响应报文头的属性： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="comment">//添加一个响应报文头属性 </span><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">void</span><span>&nbsp;&nbsp;&nbsp;&nbsp;setHeader(String&nbsp;name,&nbsp;String&nbsp;value)&nbsp;&nbsp;&nbsp;</span></span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="11" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">//添加一个响应报文头属性
void	setHeader(String name, String value) 
</pre><br /><br />象Cookie，Location这些响应都是有福之人，HttpServletResponse为它们都提供了VIP版的API： <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1124408#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="comment">//添加Cookie报文头属性 </span><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">void</span><span>&nbsp;addCookie(Cookie&nbsp;cookie)&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="comment">//不但会设置Location的响应报文头，还会生成303的状态码呢，两者天仙配呢 </span><span>&nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">void</span><span>&nbsp;&nbsp;&nbsp;&nbsp;sendRedirect(String&nbsp;location)&nbsp;&nbsp;&nbsp;</span></span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(9)----HTTP报文（系列全）" pre_index="12" source_url="http://www.iteye.com/topic/1124408#2357363" codeable_id="2357363" codeable_type="Post" name="code">//添加Cookie报文头属性
void addCookie(Cookie cookie) 

//不但会设置Location的响应报文头，还会生成303的状态码呢，两者天仙配呢
void	sendRedirect(String location) 
</pre><br /><img src ="http://www.blogjava.net/haoxuewu/aggbug/380633.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/haoxuewu/" target="_blank">陕西BOY</a> 2012-06-12 19:02 <a href="http://www.blogjava.net/haoxuewu/articles/380633.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring AOP讲解</title><link>http://www.blogjava.net/haoxuewu/articles/380632.html</link><dc:creator>陕西BOY</dc:creator><author>陕西BOY</author><pubDate>Tue, 12 Jun 2012 10:56:00 GMT</pubDate><guid>http://www.blogjava.net/haoxuewu/articles/380632.html</guid><wfw:comment>http://www.blogjava.net/haoxuewu/comments/380632.html</wfw:comment><comments>http://www.blogjava.net/haoxuewu/articles/380632.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/haoxuewu/comments/commentRss/380632.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/haoxuewu/services/trackbacks/380632.html</trackback:ping><description><![CDATA[Spring AOP使用动态代理技术在运行期织入增强的代码，为了揭示Spring AOP底层的工作机理，有必要对涉及到的Java知识进行学习。Spring AOP使用了两种代理机制：一种是基于JDK的动态代理；另一种是基于CGLib的动态代理。之所以需要两种代理机制，很大程度上是因为JDK本身只提供接口的代理，而不支持类的代理。 <br /><br /><strong><span style="font-size: x-large"><font size="5">带有横切逻辑的实例</font></span></strong> <br /><br />我们通过具体化代码实现上一节所介绍例子的性能监视横切逻辑，并通过动态代理技术对此进行改造。在调用每一个目标类方法时启动方法的性能监视，在目标类方法调用完成时记录方法的花费时间。 <br /><br />代码清单6-2&nbsp; ForumService：包含性能监视横切代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;ForumServiceImpl&nbsp;</span><span class="keyword">implements</span><span>&nbsp;ForumService&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;removeTopic(</span><span class="keyword">int</span><span>&nbsp;topicId)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9312;-1开始对该方法进行性能监视 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceMonitor.begin( &nbsp;&nbsp;</span></li><li><span>&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;</span><span class="string">"com.baobaotao.proxy.ForumServiceImpl.&nbsp;removeTopic"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"模拟删除Topic记录:"</span><span>+topicId); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().sleep(</span><span class="number"><font color="#c00000">20</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(Exception&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;RuntimeException(e); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9312;-2结束对该方法进行性能监视 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceMonitor.end(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;removeForum(</span><span class="keyword">int</span><span>&nbsp;forumId)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9313;-1开始对该方法进行性能监视 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceMonitor.begin( &nbsp;&nbsp;</span></li><li><span></span><span class="string">"com.baobaotao.proxy.ForumServiceImpl.&nbsp;removeForum"</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"模拟删除Forum记录:"</span><span>+forumId); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().sleep(</span><span class="number"><font color="#c00000">40</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(Exception&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;RuntimeException(e); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9313;-2结束对该方法进行性能监视 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceMonitor.end(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="0" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">package com.baobaotao.proxy;
public class ForumServiceImpl implements ForumService {
	public void removeTopic(int topicId) {
    		
         //&#9312;-1开始对该方法进行性能监视
		PerformanceMonitor.begin(
                            "com.baobaotao.proxy.ForumServiceImpl. removeTopic");
		System.out.println("模拟删除Topic记录:"+topicId);
		try {
			Thread.currentThread().sleep(20);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}		

         //&#9312;-2结束对该方法进行性能监视
		PerformanceMonitor.end();
	}

	public void removeForum(int forumId) {
          //&#9313;-1开始对该方法进行性能监视
		PerformanceMonitor.begin(
"com.baobaotao.proxy.ForumServiceImpl. removeForum");
		System.out.println("模拟删除Forum记录:"+forumId);
		try {
			Thread.currentThread().sleep(40);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}		

         //&#9313;-2结束对该方法进行性能监视
		PerformanceMonitor.end();
	}
}</pre><br />代码清单6-2中粗体表示的代码就是具有横切逻辑特征的代码，每个Service类和每个业务方法体的前后都执行相同的代码逻辑：方法调用前启动PerformanceMonitor，方法调用后通知PerformanceMonitor结束性能监视并给记录性能监视结果。 <br /><br />PerformanceMonitor是性能监视的实现类，我们给出一个非常简单的实现版本，其代码如代码清单6-3所示： <br /><br />代码清单6-3&nbsp; PerformanceMonitor <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;PerformanceMonitor&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9312;通过一个ThreadLocal保存调用线程相关的性能监视信息 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;ThreadLocal&lt;MethodPerformace&gt;&nbsp;performanceRecord&nbsp;=&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&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;</span><span class="keyword">new</span><span>&nbsp;ThreadLocal&lt;MethodPerformance&gt;(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9313;启动对某一目标方法的性能监视 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;begin(String&nbsp;method)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"begin&nbsp;monitor..."</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MethodPerformance&nbsp;mp&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;MethodPerformance(method); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;performanceRecord.set(mp); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;end()&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"end&nbsp;monitor..."</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MethodPerformance&nbsp;mp&nbsp;=&nbsp;performanceRecord.get(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9314;打印出方法性能监视的结果信息。 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;mp.printPerformance(); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="1" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">package com.baobaotao.proxy;
public class PerformanceMonitor {
     //&#9312;通过一个ThreadLocal保存调用线程相关的性能监视信息
	private static ThreadLocal&lt;MethodPerformace&gt; performanceRecord =        
								new ThreadLocal&lt;MethodPerformance&gt;();
	
    //&#9313;启动对某一目标方法的性能监视
     public static void begin(String method) {
		System.out.println("begin monitor...");
		MethodPerformance mp = new MethodPerformance(method);
		performanceRecord.set(mp);
	}
	public static void end() {
		System.out.println("end monitor...");
		MethodPerformance mp = performanceRecord.get();

         //&#9314;打印出方法性能监视的结果信息。
		mp.printPerformance();
	}
}</pre><br />ThreadLocal是将非线程安全类改造为线程安全类的法宝，在9.2节中我们将详细介绍这个Java基础知识。PerformanceMonitor提供了两个方法：通过调用begin(String method)方法开始对某个目标类方法的监视，method为目标类方法的全限定名；而end()方法结束对目标类方法的监视，并给出性能监视的信息。这两个方法必须配套使用。 <br /><br />用于记录性能监视信息的MethodPerformance类的代码如所示： <br /><br />代码清单6-4&nbsp; MethodPerformance <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;MethodPerformance&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">long</span><span>&nbsp;begin; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;</span><span class="keyword">long</span><span>&nbsp;end; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;String&nbsp;serviceMethod; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;MethodPerformance(String&nbsp;serviceMethod){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.serviceMethod&nbsp;=&nbsp;serviceMethod; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9312;记录目标类方法开始执行点的系统时间&nbsp;&nbsp; </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.begin&nbsp;=&nbsp;System.currentTimeMillis();&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;printPerformance(){ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9313;获取目标类方法执行完成后的系统时间，并进而计算出目标类方法执行时间 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;=&nbsp;System.currentTimeMillis();&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">long</span><span>&nbsp;elapse&nbsp;=&nbsp;end&nbsp;-&nbsp;begin; &nbsp;&nbsp;</span></span></li><li><span>&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9314;报告目标类方法的执行时间 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(serviceMethod+</span><span class="string">"花费"</span><span>+elapse+</span><span class="string">"毫秒。"</span><span>);&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="2" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">package com.baobaotao.proxy;
public class MethodPerformance {
	private long begin;
	private long end;
	private String serviceMethod;
    public MethodPerformance(String serviceMethod){
       this.serviceMethod = serviceMethod;

       //&#9312;记录目标类方法开始执行点的系统时间  
       this.begin = System.currentTimeMillis(); 
 
    }
    public void printPerformance(){
     
        //&#9313;获取目标类方法执行完成后的系统时间，并进而计算出目标类方法执行时间
        end = System.currentTimeMillis(); 
        long elapse = end - begin;
 
        //&#9314;报告目标类方法的执行时间
        System.out.println(serviceMethod+"花费"+elapse+"毫秒。");  
    }
}</pre><br />通过下面的代码测试拥有性能监视能力的ForumServiceImpl业务方法： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;TestForumService&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ForumService&nbsp;forumService&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ForumServiceImpl(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;forumService&nbsp;.removeForum(</span><span class="number"><font color="#c00000">10</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;forumService&nbsp;.removeTopic(</span><span class="number"><font color="#c00000">1012</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="3" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">package com.baobaotao.proxy;

public class TestForumService {
	public static void main(String[] args) {
        ForumService forumService = new ForumServiceImpl();
        forumService .removeForum(10);
	   forumService .removeTopic(1012);
	}
}</pre><br />我们得到以下输出信息： <br />
<div class="quote_title">引用</div>
<div class="quote_div">begin monitor... &#9312;removeForum(10)方法的性能监视报告 <br />模拟删除Forum记录:10 <br />end monitor... <br />com.baobaotao.proxy.ForumServiceImpl.removeForum花费47毫秒。 <br /><br />begin monitor... &#9312;removeTopic(1012)方法的性能监视报告 <br />模拟删除Topic记录:1012 <br />end monitor... <br />com.baobaotao.proxy.ForumServiceImpl.removeTopic花费26毫秒。</div><br />正如代码清单6 2实例所示，当某个方法需要进行性能监视，就必须调整方法代码，在方法体前后分别添加上开启性能监视和结束性能监视的代码。这些非业务逻辑的性能监视代码破坏了ForumServiceImpl业务逻辑的纯粹性。我们希望通过代理的方式，将业务类方法中开启和结束性能监视的这些横切代码从业务类中完全移除。并通过JDK动态代理技术或CGLib动态代理技术将横切代码动态织入到目标方法的相应位置。 <br /><br /><strong><span style="font-size: x-large"><font size="5">JDK动态代理</font></span></strong> <br /><br />JDK 1.3以后，Java提供了动态代理的技术，允许开发者在运行期创建接口的代理实例。在Sun刚推出动态代理时，还很难想象它有多大的实际用途，现在我们终于发现动态代理是实现AOP的绝好底层技术。 <br /><br />JDK的动态代理主要涉及到java.lang.reflect包中的两个类：Proxy和InvocationHandler。其中InvocationHandler是一个接口，可以通过实现该接口定义横切逻辑，并通过反射机制调用目标类的代码，动态将横切逻辑和业务逻辑编织在一起。 <br /><br />而Proxy利用InvocationHandler动态创建一个符合某一接口的实例，生成目标类的代理对象。这样讲一定很抽象，我们马上着手使用Proxy和InvocationHandler这两个魔法戒对上一节中的性能监视代码进行革新。 <br /><br />首先，我们从业务类ForumServiceImpl中删除性能监视的横切代码，使ForumServiceImpl只负责具体的业务逻辑，如代码清单6-5所示： <br /><br />代码清单6-5&nbsp; ForumServiceImpl：移除性能监视横切代码 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;ForumServiceImpl&nbsp;</span><span class="keyword">implements</span><span>&nbsp;ForumService&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;removeTopic(</span><span class="keyword">int</span><span>&nbsp;topicId)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&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;&#9312; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"模拟删除Topic记录:"</span><span>+topicId); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().sleep(</span><span class="number"><font color="#c00000">20</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(Exception&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;RuntimeException(e); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&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;&#9312; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;removeForum(</span><span class="keyword">int</span><span>&nbsp;forumId)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&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;&#9313; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span class="string">"模拟删除Forum记录:"</span><span>+forumId); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">try</span><span>&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.currentThread().sleep(</span><span class="number"><font color="#c00000">40</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span class="keyword">catch</span><span>&nbsp;(Exception&nbsp;e)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throw</span><span>&nbsp;</span><span class="keyword">new</span><span>&nbsp;RuntimeException(e); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&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;&#9313; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="4" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">package com.baobaotao.proxy;

public class ForumServiceImpl implements ForumService {

	public void removeTopic(int topicId) {
                                &#9312;
		System.out.println("模拟删除Topic记录:"+topicId);
		try {
			Thread.currentThread().sleep(20);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
 		                      &#9312;
	}
	public void removeForum(int forumId) {
       	                  &#9313;
		System.out.println("模拟删除Forum记录:"+forumId);
		try {
			Thread.currentThread().sleep(40);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
       	                  &#9313;
	}
}</pre><br />在代码清单6-5中的&#9312;和&#9313;处，原来的性能监视代码被移除了，我们只保留了真正的业务逻辑。 <br /><br />从业务类中移除的性能监视横切代码当然不能漂浮在空气中，它还得找到一个安身之所，InvocationHandler就是横切代码的安家乐园，我们将性能监视的代码安置在PerformanceHandler中，如代码清单6-6所示： <br /><br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span>代码清单</span><span class="number"><font color="#c00000">6</font></span><span>-</span><span class="number"><font color="#c00000">6</font></span><span>&nbsp;&nbsp;PerformanceHandler &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.lang.reflect.InvocationHandler; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.lang.reflect.Method; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;PerformanceHandler&nbsp;</span><span class="keyword">implements</span><span>&nbsp;InvocationHandler&nbsp;{</span><span class="comment">//&#9312;实现InvocationHandler </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;Object&nbsp;target; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;PerformanceHandler(Object&nbsp;target){&nbsp;</span><span class="comment">//&#9313;target为目标的业务类 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">this</span><span>.target&nbsp;=&nbsp;target; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Object&nbsp;invoke(Object&nbsp;proxy,&nbsp;Method&nbsp;method,&nbsp;Object[]&nbsp;args)&nbsp;&#9314; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Throwable&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceMonitor.begin(target.getClass().getName()+</span><span class="string">"."</span><span>+&nbsp;method.&nbsp;getName());&#9314;-</span><span class="number"><font color="#c00000">1</font></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;obj&nbsp;=&nbsp;method.invoke(target,&nbsp;args);</span><span class="comment">//&nbsp;&#9314;-2通过反射方法调用业务类的目标方法 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceMonitor.end();&#9314;-</span><span class="number"><font color="#c00000">1</font></span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;obj; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="5" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">代码清单6-6  PerformanceHandler
package com.baobaotao.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class PerformanceHandler implements InvocationHandler {//&#9312;实现InvocationHandler
    private Object target;
	public PerformanceHandler(Object target){ //&#9313;target为目标的业务类
		this.target = target;
	}
	public Object invoke(Object proxy, Method method, Object[] args) &#9314;
			throws Throwable {
		PerformanceMonitor.begin(target.getClass().getName()+"."+ method. getName());&#9314;-1
		Object obj = method.invoke(target, args);// &#9314;-2通过反射方法调用业务类的目标方法
		PerformanceMonitor.end();&#9314;-1
		return obj;
	}
}</pre><br /><br />&#9314;处invoke()方法中粗体所示部分的代码为性能监视的横切代码，我们发现，横切代码只出现一次，而不是原来那样星洒各处。&#9314;-2处的method.invoke()语句通过Java反射机制间接调用目标对象的方法，这样InvocationHandler的invoke()方法就将横切逻辑代码（&#9314;-1）和业务类方法的业务逻辑代码（&#9314;-2）编织到一起了，所以我们可以将InvocationHandler看成是一个编织器。下面，我们对这段代码做进一步的说明。 <br /><br />首先，我们实现InvocationHandler接口，该接口定义了一个 invoke(Object proxy, Method method, Object[] args)的方法，proxy是最终生成的代理实例，一般不会用到；method是被代理目标实例的某个具体方法，通过它可以发起目标实例方法的反射调用；args是通过被代理实例某一个方法的入参，在方法反射调用时使用。 <br /><br />此外，我们在构造函数里通过target传入希望被代理的目标对象，如&#9313;处所示，在InvocationHandler接口方法invoke(Object proxy, Method method, Object[] args)里，将目标实例传给method.invoke()方法，调用目标实例的方法，如&#9314;所示。 <br />下面，我们通过Proxy结合PerformanceHandler创建ForumService接口的代理实例，如代码清单6-7所示： <br /><br />代码清单6-7&nbsp; TestForumService：创建代理实例 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.lang.reflect.Proxy; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;TestForumService&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9312;希望被代理的目标业务类 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ForumService&nbsp;target&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;ForumServiceImpl();&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9313;将目标业务类和横切代码编织到一起 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceHandler&nbsp;handler&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;PerformanceHandler(target); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9314;根据编织了目标业务类逻辑和性能监视横切逻辑的InvocationHandler实例创建代理实例 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ForumService&nbsp;proxy&nbsp;=&nbsp;(ForumService)&nbsp;Proxy.newProxyInstance(&nbsp;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;target.getClass().getClassLoader(), &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;target.getClass().getInterfaces(), &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;handler); &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9315;调用代理实例 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy.removeForum(</span><span class="number"><font color="#c00000">10</font></span><span>);&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;proxy.removeTopic(</span><span class="number"><font color="#c00000">1012</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="6" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">package com.baobaotao.proxy;
import java.lang.reflect.Proxy;
public class TestForumService {
	public static void main(String[] args) {
               
               //&#9312;希望被代理的目标业务类
		ForumService target = new ForumServiceImpl(); 
		
               //&#9313;将目标业务类和横切代码编织到一起
		PerformanceHandler handler = new PerformanceHandler(target);
		
                //&#9314;根据编织了目标业务类逻辑和性能监视横切逻辑的InvocationHandler实例创建代理实例
		ForumService proxy = (ForumService) Proxy.newProxyInstance(  
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(),
				handler);

                //&#9315;调用代理实例
		proxy.removeForum(10);   
		proxy.removeTopic(1012);
	}
}</pre><br />上面的代码完成业务类代码和横切代码的编织工作并生成了代理实例。在&#9313;处，我们让PerformanceHandler将性能监视横切逻辑编织到ForumService实例中，然后在&#9314;处，通过Proxy的newProxyInstance()静态方法为编织了业务类逻辑和性能监视逻辑的handler创建一个符合ForumService接口的代理实例。该方法的第一个入参为类加载器；第二个入参为创建代理实例所需要实现的一组接口；第三个参数是整合了业务逻辑和横切逻辑的编织器对象。 <br /><br />按照&#9314;处的设置方式，这个代理实例实现了目标业务类的所有接口，即Forum ServiceImpl的ForumService接口。这样，我们就可以按照调用ForumService接口实例相同的方式调用代理实例，如&#9315;所示。运行以上的代码，输出以下信息： <br />
<div class="quote_title">引用</div>
<div class="quote_div">begin monitor... <br />模拟删除Forum记录:10 <br />end monitor... <br />com.baobaotao.proxy.ForumServiceImpl.removeForum花费47毫秒。 <br /><br />begin monitor... <br />模拟删除Topic记录:1012 <br />end monitor... <br />com.baobaotao.proxy.ForumServiceImpl.removeTopic花费26毫秒。</div><br />我们发现，程序的运行效果和直接在业务类中编写性能监视逻辑的效果一致，但是在这里，原来分散的横切逻辑代码已经被我们抽取到PerformanceHandler中。当其他业务类（如UserService、SystemService等）的业务方法也需要使用性能监视时，我们只要按照代码清单6-7相似的方式，分别为它们创建代理对象就可以了。下面，我们通过时序图描述通过创建代理对象进行业务方法调用的整体逻辑，以进一步认识代理对象的本质，如图6-3所示。 <br /><br /><br /><img class="magplus" title="点击查看原始大小图片" src="http://dl.iteye.com/upload/attachment/0067/4415/eaafc698-ec08-3ef3-aae0-6d14514cc976.jpg" width="760" height="522"  alt="" /> <br /><br /><br />我们在上图中使用虚线的方式对通过Proxy创建的ForumService代理实例加以凸显，ForumService代理实例内部利用PerformaceHandler整合横切逻辑和业务逻辑。调用者调用代理对象的removeForum()和removeTopic()方法时，上图的内部调用时序清晰地告诉我们实际上所发生的一切。 <br /><br /><strong><span style="font-size: x-large"><font size="5">CGLib动态代理</font></span></strong> <br /><br />使用JDK创建代理有一个限制，即它只能为接口创建代理实例，这一点我们可从Proxy的接口newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)的方法签名中就看得很清楚：第二个入参interfaces就是需要代理实例实现的接口列表。虽然面向接口编程的思想被很多大师级人物（包括Rod Johnson）推崇，但在实际开发中，许多开发者也对此深感困惑：难道对一个简单业务表的操作也需要老老实实地创建5个类（领域对象类、Dao接口，Dao实现类，Service接口和Service实现类）吗？难道不能直接通过实现类构建程序吗？对于这个问题，我们很难给出一个孰好孰劣的准确判断，但我们确实发现有很多不使用接口的项目也取得了非常好的效果（包括大家所熟悉的SpringSide开源项目）。 <br /><br />对于没有通过接口定义业务方法的类，如何动态创建代理实例呢？JDK的代理技术显然已经黔驴技穷，CGLib作为一个替代者，填补了这个空缺。 <br /><br />CGLib采用非常底层的字节码技术，可以为一个类创建子类，并在子类中采用方法拦截的技术拦截所有父类方法的调用，并顺势织入横切逻辑。下面，我们采用CGLib技术，编写一个可以为任何类创建织入性能监视横切逻辑代理对象的代理创建器，如代码清单 6-8所示： <br /><br />代码清单6-8&nbsp; CglibProxy <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.lang.reflect.Method; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;net.sf.cglib.proxy.Enhancer; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;net.sf.cglib.proxy.MethodInterceptor; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">import</span><span>&nbsp;net.sf.cglib.proxy.MethodProxy; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;</span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;CglibProxy&nbsp;</span><span class="keyword">implements</span><span>&nbsp;MethodInterceptor&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">private</span><span>&nbsp;Enhancer&nbsp;enhancer&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;Enhancer(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Object&nbsp;getProxy(Class&nbsp;clazz)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enhancer.setSuperclass(clazz);&nbsp;</span><span class="comment">//&#9312;&nbsp;设置需要创建子类的类 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enhancer.setCallback(</span><span class="keyword">this</span><span>);&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;enhancer.create();&nbsp;</span><span class="comment">//&#9313;通过字节码技术动态创建子类实例 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="comment">//&#9314;拦截父类所有方法的调用 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;Object&nbsp;intercept(Object&nbsp;obj,&nbsp;Method&nbsp;method,&nbsp;Object[]&nbsp;args,&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MethodProxy&nbsp;proxy)&nbsp;</span><span class="keyword">throws</span><span>&nbsp;Throwable&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceMonitor.begin(obj.getClass().getName()+</span><span class="string">"."</span><span>+method.&nbsp;getName());</span><span class="comment">//&#9314;-1 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object&nbsp;result=proxy.invokeSuper(obj,&nbsp;args);&nbsp;&#9314;-</span><span class="number"><font color="#c00000">2</font></span><span>&nbsp; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PerformanceMonitor.end();</span><span class="comment">//&#9314;-1通过代理类调用父类中的方法 </span><span>&nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">return</span><span>&nbsp;result; &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="7" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">package com.baobaotao.proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CglibProxy implements MethodInterceptor {
	private Enhancer enhancer = new Enhancer();
	public Object getProxy(Class clazz) {
		enhancer.setSuperclass(clazz); //&#9312; 设置需要创建子类的类
		enhancer.setCallback(this); 
		return enhancer.create(); //&#9313;通过字节码技术动态创建子类实例
 
	}

        //&#9314;拦截父类所有方法的调用
	public Object intercept(Object obj, Method method, Object[] args, 
			MethodProxy proxy) throws Throwable {
		PerformanceMonitor.begin(obj.getClass().getName()+"."+method. getName());//&#9314;-1
		Object result=proxy.invokeSuper(obj, args); &#9314;-2 
		PerformanceMonitor.end();//&#9314;-1通过代理类调用父类中的方法
		return result;
	}
}</pre><br />在上面代码中，用户可以通过getProxy(Class clazz)为一个类创建动态代理对象，该代理对象通过扩展clazz创建代理对象。在这个代理对象中，我们织入性能监视的横切逻辑（&#9314;-1）。intercept(Object obj, Method method, Object[] args,MethodProxy proxy)是CGLib定义的Interceptor接口的方法，它拦截所有目标类方法的调用，obj表示目标类的实例；method为目标类方法的反射对象；args为方法的动态入参；而proxy为代理类实例。 <br /><br />下面，我们通过CglibProxy为ForumServiceImpl类创建代理对象，并测试代理对象的方法，如代码清单6-9所示： <br /><br />代码清单6-9&nbsp; TestForumService：测试Cglib创建的代理类 <br />
<div class="dp-highlighter">
<div class="bar">
<div class="tools">Java代码 <a title="复制代码" href="http://www.iteye.com/topic/1123293#"><img alt="复制代码" src="http://www.iteye.com/images/icon_copy.gif" /></a>&nbsp;<a title="收藏这段代码" href="javascript:void()"><img class="star" alt="收藏代码" src="http://www.iteye.com/images/icon_star.png" /><img style="display: none" class="spinner" src="http://www.iteye.com/images/spinner.gif"  alt="" /></a></div></div>
<ol class="dp-j"><li><span class="keyword">package</span><span>&nbsp;com.baobaotao.proxy; &nbsp;&nbsp;</span></li><li><span></span><span class="keyword">import</span><span>&nbsp;java.lang.reflect.Proxy; &nbsp;&nbsp;</span></span></li><li><span></span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">class</span><span>&nbsp;TestForumService&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;</span><span class="keyword">public</span><span>&nbsp;</span><span class="keyword">static</span><span>&nbsp;</span><span class="keyword">void</span><span>&nbsp;main(String[]&nbsp;args)&nbsp;{ &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CglibProxy&nbsp;proxy&nbsp;=&nbsp;</span><span class="keyword">new</span><span>&nbsp;CglibProxy(); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ForumServiceImpl&nbsp;forumService&nbsp;=&nbsp;&#9312;&nbsp; &nbsp;&nbsp;</span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(ForumServiceImpl&nbsp;)proxy.getProxy(ForumServiceImpl.</span><span class="keyword">class</span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;forumService.removeForum(</span><span class="number"><font color="#c00000">10</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;forumService.removeTopic(</span><span class="number"><font color="#c00000">1023</font></span><span>); &nbsp;&nbsp;</span></span></li><li><span>&nbsp;&nbsp;&nbsp;&nbsp;} &nbsp;&nbsp;</span></li><li><span>}&nbsp;&nbsp;</span></li></ol></div><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(2)----动态代理" pre_index="8" source_url="http://www.iteye.com/topic/1123293#2348072" codeable_id="2348072" codeable_type="Post" name="code">package com.baobaotao.proxy;
import java.lang.reflect.Proxy;
public class TestForumService {
	public static void main(String[] args) {
	  CglibProxy proxy = new CglibProxy();
	  ForumServiceImpl forumService = &#9312; 
	            (ForumServiceImpl )proxy.getProxy(ForumServiceImpl.class);
	  forumService.removeForum(10);
	  forumService.removeTopic(1023);
	}
}</pre><br /><br />在&#9312;中，我们通过CglibProxy为ForumServiceImpl动态创建了一个织入性能监视逻辑的代理对象，并调用代理类的业务方法。运行上面的代码，输入以下信息： <br />
<div class="quote_title">引用</div>
<div class="quote_div">begin monitor... <br />模拟删除Forum记录:10 <br />end monitor... <br />com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0.removeForum花费47毫秒。 <br />begin monitor... <br />模拟删除Topic记录:1023 <br />end monitor... <br />com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0.removeTopic花费16毫秒。</div><br />观察以上的输出，除了发现两个业务方法中都织入了性能监控的逻辑外，我们还发现代理类的名字是com.baobaotao.proxy.ForumServiceImpl$$EnhancerByCGLIB$$2a9199c0，这个特殊的类就是CGLib为ForumServiceImpl动态创建的子类。 <br /><br /><strong><span style="font-size: x-large"><font size="5">代理知识小结</font></span></strong> <br /><br />Spring AOP的底层就是通过使用JDK动态代理或CGLib动态代理技术为目标Bean织入横切逻辑。在这里，我们对前面两节动态创建代理对象作一个小结。 <br /><br />我们虽然通过PerformanceHandler或CglibProxy实现了性能监视横切逻辑的动态织入，但这种实现方式存在三个明显需要改进的地方： <br /><br />1）目标类的所有方法都添加了性能监视横切逻辑，而有时，这并不是我们所期望的，我们可能只希望对业务类中的某些特定方法添加横切逻辑； <br />2）我们通过硬编码的方式指定了织入横切逻辑的织入点，即在目标类业务方法的开始和结束前织入代码； <br />3）我们手工编写代理实例的创建过程，为不同类创建代理时，需要分别编写相应的创建代码，无法做到通用。 <br /><br />以上三个问题，在AOP中占用重要的地位，因为Spring AOP的主要工作就是围绕以上三点展开：Spring AOP通过Pointcut（切点）指定在哪些类的哪些方法上织入横切逻辑，通过Advice（增强）描述横切逻辑和方法的具体织入点（方法前、方法后、方法的两端等）。此外，Spring通过Advisor（切面）将Pointcut和Advice两者组装起来。有了Advisor的信息，Spring就可以利用JDK或CGLib的动态代理技术采用统一的方式为目标Bean创建织入切面的代理对象了。 <img src ="http://www.blogjava.net/haoxuewu/aggbug/380632.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/haoxuewu/" target="_blank">陕西BOY</a> 2012-06-12 18:56 <a href="http://www.blogjava.net/haoxuewu/articles/380632.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Java反射机制</title><link>http://www.blogjava.net/haoxuewu/articles/380619.html</link><dc:creator>陕西BOY</dc:creator><author>陕西BOY</author><pubDate>Tue, 12 Jun 2012 08:26:00 GMT</pubDate><guid>http://www.blogjava.net/haoxuewu/articles/380619.html</guid><wfw:comment>http://www.blogjava.net/haoxuewu/comments/380619.html</wfw:comment><comments>http://www.blogjava.net/haoxuewu/articles/380619.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/haoxuewu/comments/commentRss/380619.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/haoxuewu/services/trackbacks/380619.html</trackback:ping><description><![CDATA[&nbsp;<br /><br />Class反射对象描述类语义结构，可以从Class对象中获取构造函数、成员变量、方法类等类元素的反射对象，并以编程的方式通过这些反射对象对目标类对象进行操作。这些反射对象类在java.reflect包中定义，下面是最主要的三个反射类： <br />
<ul><li>&nbsp; Constructor：类的构造函数反射类，通过Class#getConstructors()方法可以获得类的所有构造函数反射对象数组。在JDK5.0中，还可以通过getConstructor(Class... parameterTypes)获取拥有特定入参的构造函数反射对象。Constructor的一个主要方法是newInstance(Object[] initargs)，通过该方法可以创建一个对象类的实例，相当于new关键字。在JDK5.0中该方法演化为更为灵活的形式：newInstance (Object... initargs)。</li><li>&nbsp; Method：类方法的反射类，通过Class#getDeclaredMethods()方法可以获取类的所有方法反射类对象数组Method[]。在JDK5.0中可以通过getDeclaredMethod(String name, Class... parameterTypes)获取特定签名的方法，name为方法名；Class...为方法入参类型列表。Method最主要的方法是invoke(Object obj, Object[] args)，obj表示操作的目标对象；args为方法入参，代码清单3 10&#9314;处演示了这个反射类的使用方法。在JDK 5.0中，该方法的形式调整为invoke(Object obj, Object... args)。此外，Method还有很多用于获取类方法更多信息的方法： &nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1）Class getReturnType()：获取方法的返回值类型； <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2）Class[] getParameterTypes()：获取方法的入参类型数组； <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 3）Class[] getExceptionTypes()：获取方法的异常类型数组； <br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4）Annotation[][] getParameterAnnotations()：获取方法的注解信息，JDK 5.0中的新方法；</li><li>&nbsp; Field：类的成员变量的反射类，通过Class#getDeclaredFields()方法可以获取类的成员变量反射对象数组，通过Class#getDeclaredField(String name)则可获取某个特定名称的成员变量反射对象。Field类最主要的方法是set(Object obj, Object value)，obj表示操作的目标对象，通过value为目标对象的成员变量设置值。如果成员变量为基础类型，用户可以使用Field类中提供的带类型名的值设置方法，如setBoolean(Object obj, boolean value)、setInt(Object obj, int value)等。 </li></ul><br />此外，Java还为包提供了Package反射类，在JDK 5.0中还为注解提供了AnnotatedElement反射类。总之，Java的反射体系保证了可以通过程序化的方式访问目标类中所有的元素，对于private或protected的成员变量和方法，只要JVM的安全机制允许，也可以通过反射进行调用，请看下面的例子： <br /><br />代码清单3-12&nbsp; PrivateCarReflect <br /><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(1)----反射" pre_index="5" source_url="http://www.iteye.com/topic/1123081#2345199" codeable_id="2345199" codeable_type="Post" name="code">package com.baobaotao.reflect;
public class PrivateCar {
       //&#9312;private成员变量：使用传统的类实例调用方式，只能在本类中访问
   private String color; 
        //&#9313;protected方法：使用传统的类实例调用方式，只能在子类和本包中访问
   protected void drive(){
	   
System.out.println("drive private car! the color is:"+color);
   }
}</pre><br />color变量和drive()方法都是私有的，通过类实例变量无法在外部访问私有变量、调用私有方法的，但通过反射机制却可以绕过这个限制： <br /><br /><pre style="display: none" class="java" title="学习Spring必学的Java基础知识(1)----反射" pre_index="6" source_url="http://www.iteye.com/topic/1123081#2345199" codeable_id="2345199" codeable_type="Post" name="code">public class PrivateCarReflect {
   public static void main(String[] args) throws Throwable{
	   ClassLoader loader = Thread.currentThread().getContextClassLoader();
	   Class clazz = loader.loadClass("com.baobaotao.reflect.PrivateCar");
	   PrivateCar pcar = (PrivateCar)clazz.newInstance();
	   
	   Field colorFld = clazz.getDeclaredField("color");
        //&#9312;取消Java语言访问检查以访问private变量
	   colorFld.setAccessible(true); 
	   colorFld.set(pcar,"红色");
	   
	   Method driveMtd = clazz.getDeclaredMethod("drive",(Class[])null);
        //Method driveMtd = clazz.getDeclaredMethod("drive"); JDK5.0下使用
       
        //&#9313;取消Java语言访问检查以访问protected方法
	   driveMtd.setAccessible(true); 
        driveMtd.invoke(pcar,(Object[])null);
  }
}</pre><br />运行该类，打印出以下信息： <br />
<div class="quote_title">引用</div>
<div class="quote_div">drive private car! the color is:红色</div><br /><br />在访问private、protected成员变量和方法时必须通过setAccessible(boolean access)方法取消Java语言检查，否则将抛出IllegalAccessException。如果JVM的安全管理器设置了相应的安全机制，调用该方法将抛出SecurityException。 <img src ="http://www.blogjava.net/haoxuewu/aggbug/380619.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/haoxuewu/" target="_blank">陕西BOY</a> 2012-06-12 16:26 <a href="http://www.blogjava.net/haoxuewu/articles/380619.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>