﻿<?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/killme2008/category/21285.html</link><description /><language>zh-cn</language><lastBuildDate>Sat, 29 Sep 2007 11:26:00 GMT</lastBuildDate><pubDate>Sat, 29 Sep 2007 11:26:00 GMT</pubDate><ttl>60</ttl><item><title>Ruby的对象模型</title><link>http://www.blogjava.net/killme2008/archive/2007/09/29/149452.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 29 Sep 2007 01:43:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/09/29/149452.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/149452.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/09/29/149452.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/149452.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/149452.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; Ruby的对象模型，包含在下面这张图中：<br />
<img alt="" src="http://www.javaeye.com/topics/download/2fb4a83c-1a28-4aa0-aee0-4f77aafb8c2c" /><br />
<br />
&nbsp;&nbsp;&nbsp; 首先要知道，Ruby中的类也是对象，类相比于其他对象特殊的地方在于能够产生对象，既然类是对象，那么它显然也有类，也就是所谓类的类，这个类的类在Ruby中就是类的metaclass，图中的(OtherClass)，(OtherClass)就是类OtherClass的klass(C层次）,(OtherClass)存储了类的方法(类方法）和类的实例变量，并且是唯一的且不可实例化。在Ruby层次上我们想操作(otherclass)应该类似：<br />
&nbsp;&nbsp; <br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;OtherClass<br />
&nbsp;&nbsp;<br />
end<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">OtherClass<br />
&nbsp;&nbsp;attr_accessor:name&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">name是OtherClass的实例变量</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;test<br />
&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;</span><span style="color: #800000;">'</span><span style="color: #800000;">hello</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
&nbsp;&nbsp;end<br />
end<br />
OtherClass.name</span><span style="color: #000000;">=</span><span style="color: #800000;">'</span><span style="color: #800000;">1</span><span style="color: #800000;">'</span><span style="color: #000000;"><br />
p&nbsp;OtherClass.name<br />
OtherClass.test</span></div>
&nbsp;&nbsp;&nbsp; 图中的instance是OtherClass的一个实例，那么显然instance的class是OtherClass，可是图中的(instance)又是什么呢？(instance)就是对象的singleton类，singleton类这个名称怪怪的，不过每个对象只能有一个singleton类的角度上说也可以理解。看看下面的例子：<br />
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;OtherClass<br />
end<br />
instance</span><span style="color: #000000;">=</span><span style="color: #000000;">OtherClass.new<br />
</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">instance<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;test<br />
&nbsp;&nbsp;&nbsp;&nbsp;p&nbsp;</span><span style="color: #800000;">"</span><span style="color: #800000;">a.test</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
&nbsp;&nbsp;end<br />
&nbsp;&nbsp;attr_accessor:name<br />
end<br />
instance.test<br />
instance.name</span><span style="color: #000000;">=</span><span style="color: #800000;">"</span><span style="color: #800000;">dennis</span><span style="color: #800000;">"</span><span style="color: #000000;"><br />
p&nbsp;instance.name</span></div>
<br />
&nbsp;&nbsp;&nbsp;&nbsp;
instance通过OtherClass.new创建，但是此时(instance)还不存在，这与(OtherClass)情况不同，每个类一经创建就有一个metaclass，而对象就不一样，只有当你通过class&lt;&lt;instance 语法创建的时候，(instance)才被创建。注意test方法和name变量都将是instance对象特有的，类OtherClass并没有改变。观察下，发现(instance)继承于OtherClass，引出类的metaclass与对象的singleton类的又一个区别：类的metaclass继承自父类的metaclass，而对象的singleton类则是继承于对象的class。<br />
&nbsp;&nbsp;&nbsp; 那么当我们调用instance.class的时候，怎么不返回(instance)?这是c ruby在底层做了处理，instance的class在c ruby层次是(instance),当查找的时候忽略了singleton类以及下面将要谈到的include模块的代理类，沿着继承链上查找：<br />
86  VALUE<br />
87  rb_obj_class(obj)<br />
88      VALUE obj;<br />
89  {<br />
90      return rb_class_real(CLASS_OF(obj));<br />
91  }<br />
<br />
76  VALUE<br />
77  rb_class_real(cl)<br />
78      VALUE cl;<br />
79  {<br />
80      while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) {<br />
81          cl = RCLASS(cl)-&gt;super;<br />
82      }<br />
83      return cl;<br />
84  }<br />
<br />
(object.c)<br />
<br />
核心代码就是：<br />
while (FL_TEST(cl, FL_SINGLETON) || TYPE(cl) == T_ICLASS) {<br />
&nbsp;
cl = RCLASS(cl)-&gt;super;<br />
&nbsp;}<br />
&nbsp;&nbsp;&nbsp; 其中FL_TEST(cl,FL_SINGLETON)用于测试是否是singleton类，而TYPE(cl)==TL_ICLASS是否是包含模块的代理类，TL_ICLASS的I就是include的意思。<br />
&nbsp;&nbsp;&nbsp; 图中类OtherClass继承Object，这个是显而易见的，不再多说。而Object、Class和Module这三个类是没办法通过API创建的，称为元类，他们的之间的关系如图所示，Object的class是Class,Module继承Object,而Class又继承Module，因此Class.kind_of? Object返回true,这个问题类似先有鸡，还是先有蛋的问题，是先有Object？还是先有Class?而c ruby的解决办法是不管谁先有，创建Object开始，接着创建Module和Class，然后分别创建它们的metaclass，从此整个Ruby的对象模型开始运转。<br />
<br />
1243  rb_cObject = boot_defclass("Object", 0);<br />
1244  rb_cModule = boot_defclass("Module", rb_cObject);<br />
1245  rb_cClass =  boot_defclass("Class",  rb_cModule);<br />
1246<br />
1247  metaclass = rb_make_metaclass(rb_cObject, rb_cClass);<br />
1248  metaclass = rb_make_metaclass(rb_cModule, metaclass);<br />
1249  metaclass = rb_make_metaclass(rb_cClass, metaclass);<br />
<br />
(object.c)<br />
<br />
那么当我们调用Class.class发生了什么？Class的klass其实指向的是(Class)，可根据上面的代码，我们知道会忽略这个(Class)，继续往上找就是(Module),同理找到(Object)，而(Object)继承自Class,显然Class的类仍然是Class，Class的类的类也是Class,多么有趣。同理，Object.class和Module.class都将是Class类。<br />
<br />
&nbsp;&nbsp;&nbsp; 再来看看include模块时发生的故事。include模块的过程如下图所示：<br />
<img src="http://www.blogjava.net/images/blogjava_net/killme2008/ch_class_include.png" alt="" border="0" /><br />
include模块，本质上是在对象或者类的klass和super之间插入了一个代理类iclass,这个代理类的方法表(m_table)和变量表(iv_table)分别指向了被包含的模块的方法表和变量表（通过指针，因此当包含的Module变化的时候，对象或者类也能相应变化），那么在查找类或者对象的class的时候，上面已经说明将忽略这些代理类。<br />
<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/149452.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-09-29 09:43 <a href="http://www.blogjava.net/killme2008/archive/2007/09/29/149452.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Ruby变量在c ruby中的存储</title><link>http://www.blogjava.net/killme2008/archive/2007/09/20/146799.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 20 Sep 2007 08:17:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/09/20/146799.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/146799.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/09/20/146799.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/146799.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/146799.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 读完ruby hacking guide第6章，彻底总结下：<br />
1.在Ruby中，类也是一个对象，因此有实例变量。类的实例变量、类变量、常量都是存储在RClass struct的iv_tbl中，<br />
struct RClass {<br />
&nbsp;&nbsp;&nbsp; struct RBasic basic;<br />
&nbsp;&nbsp;&nbsp; struct st_table *iv_tbl;<br />
&nbsp;&nbsp;&nbsp; struct st_table *m_tbl;<br />
&nbsp;&nbsp;&nbsp; VALUE super;<br />
};<br />
iv_tbl的类型是st_table，我在<a href="http://www.blogjava.net/killme2008/archive/2007/09/18/146234.html">这里</a>用java实现了一下。<br />
<br />
2.用户自定义类的对象（ruby层次声明的类的对象)的实例变量存储在RObject struct的iv_tbl中，<br />
struct RObject {<br />
&nbsp; struct RBasic basic;<br />
&nbsp; struct st_table *iv_tbl;<br />
&nbsp;};<br />
调用方法，本质上是一个查表操作。buildin的几个类，比如String、Array、Hash等(在c层次上实现的类），它们的结构并没有iv_table，这是从节省内存空间的角度考虑，它们的实例变量存储在一张全局的st_table中。这张表比较特别，其中的每一个对应的值又是一个st_table，也就是一个&#8220;二元结构&#8221;，第一层结构是类名与实例变量表的映射，第二层才是实例变量名与实际值的映射。<br />
<br />
3.全局变量存储在一张全局的st_table中，这个表的键就是变量名ID，由于全局变量允许通过alias来设置别名，因此这张全局表中真正存储的是下面这个struct<br />
<br />
334  struct global_entry {<br />
335      struct global_variable *var;<br />
336      ID id;<br />
337  };<br />
<br />
324  struct global_variable {<br />
325      int   counter;      /* 引用计数 */<br />
326      void *data;         /* 变量值 */<br />
327      VALUE (*getter)();  /* 取值函数 */<br />
328      void  (*setter)();  /* 设置函数 */<br />
329      void  (*marker)();  /* 标记函数 */<br />
330      int block_trace;<br />
331      struct trace_var *trace;<br />
332  };<br />
(variable.c)<br />
<br />
当不同变量名（通过别名声明）指向的是同一个全局变量，其实它们指向的是同一个struct global_variable。<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/146799.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-09-20 16:17 <a href="http://www.blogjava.net/killme2008/archive/2007/09/20/146799.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>深入下Ruby中的String</title><link>http://www.blogjava.net/killme2008/archive/2007/09/12/144417.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 12 Sep 2007 01:43:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/09/12/144417.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/144417.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/09/12/144417.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/144417.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/144417.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; Ruby语言中的String是mutable的，不像java、C#中的String是immutable的。比如<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str1="abc"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str2="abc"<br />
在java中，对于字面量的字符串，jvm内部维持一张表，因此如果在java中，str1和str2是同一个String对象。而在Ruby中，str1和str2是完全不同的对象。同样，在java中对于String对象的操作都将产生一个新的对象，而Ruby则是操纵同一个对象，比如:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str="abc"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str.concat("cdf")<br />
此时str就是"abccdf"。Ruby对String是怎么处理的呢？我们只谈谈c ruby中的实现，有兴趣的先看看这篇文章《<a href="http://dreamhead.blogbus.com/logs/3299713.html">管窥Ruby——对象基础</a>》。在ruby.h中我们可以看到String对象的结构，Ruby中的对象（包括类也是对象）都是一个一个的struct，String也不能例外：<br />
struct RString {<br />
&nbsp;&nbsp;&nbsp; struct RBasic basic;<br />
&nbsp;&nbsp;&nbsp; long len;<br />
&nbsp;&nbsp;&nbsp; char *ptr;<br />
&nbsp;&nbsp;&nbsp; union {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; long capa;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; VALUE shared;<br />
&nbsp;&nbsp;&nbsp; } aux;<br />
};<br />
//ruby.h<br />
<br />
&nbsp;&nbsp;&nbsp; 显然，len是String的长度；ptr是一个char类型的指针，指向实际的字符串；然后是一个联合，这个稍后再说。如果你看看ruby.h可以发现，几乎所有定义的对象结构都有一个struct RBasic。显然,struct RBasic包含由所有对象结构体共享的一些重要信息的。看看RBasic:<br />
<br />
struct RBasic {
<br />
&nbsp;unsigned long flags; <br />
&nbsp;VALUE klass; <br />
};<br />
其中的flags是一个多用途的标记，大多数情况下用于记录结构体的类型，ruby.h中预定义了一些列的宏，比如T_STRING（表示struct RString)，T_ARRAY(表示struct RArray）等。Klass是一个VALUE类型，VALUE也是unsigned long，可以地将它当成指针（一个指针4字节，绰绰有余了）,它指向的是一个Ruby对象，这里以后再深入。<br />
&nbsp;&nbsp;&nbsp; 那么联合aux中的capa和shared是干什么用的呢？因为Ruby的String是可变的，可变意味着len可以改变，我们需要每次都根据len的变换来增减内存（使用c中的realloc()函数），这显然是一个很大的开销，解决办法就是预留一定的空间，ptr指向的内存大小略大于len，这样就不需要频繁调用realloc了，aux.capa就是一个长度，包含额外的内存大小。那么aux.shared是干什么的呢？这是一个VALUE类型，说明它是指向某个对象。aux.shared其实是用于加快字符串的创建速度，在一个循环中：<br />
<pre>while true do  # 无限重复<br />
a = "str"        # 以&#8220;str&#8221;为内容创建字符串，赋值给a<br />
a.concat("ing")  # 为a所指向的对象添加&#8220;ing&#8221;<br />
p(a)             # 显示&#8220;string&#8221;<br />
end<br />
每次都重新创建一个"str"对象，内部就是重复创建一个char[],这是相当奢侈，aux.shared就是用于共享char[],<br />
以字面量创建的字符串会共享一个char[],当要发生变化时，将字符串复制到一个非共享的内存中，变化针对这<br />
个新拷贝进行，这就是所谓的&#8220;copy-on-write"技术。解释了String的内部构造，貌似还没有介绍String是怎么<br />
实现mutable，我们写一个Ruby扩展测试下，我们想写这样一个Ruby类：<br />
class Test<br />
def test<br />
str="str"<br />
str.concat("ing")<br />
end<br />
end<br />
对应的c语言代码就是：<br />
</pre>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
--><span style="color: #000000;">#include</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">stdio.h</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br />
#include&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;"><a title="" href="http://www.ruby-lang.org">ruby</a>.h</span><span style="color: #000000;">"</span><span style="color: #000000;"><br />
<br />
</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;VALUE&nbsp;t_test(VALUE&nbsp;self)<br />
{<br />
&nbsp;&nbsp;VALUE&nbsp;str;<br />
&nbsp;&nbsp;str</span><span style="color: #000000;">=</span><span style="color: #000000;">rb_str_new2(</span><span style="color: #000000;">"</span><span style="color: #000000;">str</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">before&nbsp;concat:&nbsp;str:%p,&nbsp;str.aux.shared:%p,&nbsp;str.ptr:%s</span><span style="color: #000000;">"</span><span style="color: #000000;">n</span><span style="color: #000000;">"</span><span style="color: #000000;">,str,</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(RSTRING(str)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">aux).shared,RSTRING(str)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">ptr);<br />
&nbsp;&nbsp;rb_str_cat2(str,</span><span style="color: #000000;">"</span><span style="color: #000000;">ing</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br />
&nbsp;&nbsp;printf(</span><span style="color: #000000;">"</span><span style="color: #000000;">after&nbsp;concat:&nbsp;str:%p,&nbsp;str.aux.shared:%p,&nbsp;str.ptr:%s</span><span style="color: #000000;">"</span><span style="color: #000000;">n</span><span style="color: #000000;">"</span><span style="color: #000000;">,</span><span style="color: #000000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;str,(RSTRING(str)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">aux).shared,RSTRING(str)</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">ptr);<br />
&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;self;<br />
}<br />
VALUE&nbsp;cTest;<br />
</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;Init_string_hack(){<br />
&nbsp;&nbsp;cTest</span><span style="color: #000000;">=</span><span style="color: #000000;">rb_define_class(</span><span style="color: #000000;">"</span><span style="color: #000000;">Test</span><span style="color: #000000;">"</span><span style="color: #000000;">,rb_cObject);<br />
&nbsp;&nbsp;rb_define_method(cTest,</span><span style="color: #000000;">"</span><span style="color: #000000;">test</span><span style="color: #000000;">"</span><span style="color: #000000;">,t_test,</span><span style="color: #000000;">0</span><span style="color: #000000;">);<br />
<br />
}<br />
//string_hack.c<br />
</span></div>
<pre>   rb_define_class函数定义了一个类Test,rb_define_method将t_test方法以test的名称添加到Test类。在<br />
t_test中，通过rb_str_new2每次生成一个RString结构，然后通过rb_str_cat2将str与"ing"连接起来，添加<br />
了一些打印用于跟踪。利用mkmf产生Makefile,写一个extconf.rb<br />
require 'mkmf'<br />
create_makefile("string_hack");<br />
执行ruby extconf.rb，将产生一个Makefile,执行make，生成一个string_hack.so的链接库。扩展写完了，通过<br />
ruby调用：<br />
require 'string_hack"<br />
t=Test.new<br />
(1..3).each{|i| t.test}<br />
输出：<br />
before concat: str:0x40098a40, str.aux.shared:0x3, str.ptr:str<br />
after concat: str:0x40098a40, str.aux.shared:0x8, str.ptr:string<br />
before concat: str:0x40098a2c, str.aux.shared:0x3, str.ptr:str<br />
after concat: str:0x40098a2c, str.aux.shared:0x8, str.ptr:string<br />
before concat: str:0x40098a18, str.aux.shared:0x3, str.ptr:str<br />
after concat: str:0x40098a18, str.aux.shared:0x8, str.ptr:string<br />
从结果可以看出，在str concat之前之后，str指向的位置没有改变，改变的仅仅是str中ptr指向的字符串的值<br />
，看看rb_str_cat2函数的实现就一目了然了：<br />
VALUE rb_str_cat(str, ptr, len)<br />
&nbsp;&nbsp;&nbsp; VALUE str;<br />
&nbsp;&nbsp;&nbsp; const char *ptr;<br />
&nbsp;&nbsp;&nbsp; long len;<br />
{<br />
&nbsp;&nbsp;&nbsp; if (len &lt; 0) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rb_raise(rb_eArgError, "negative string size (or size too big)");<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; if (FL_TEST(str, STR_ASSOC)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rb_str_modify(str);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; REALLOC_N(RSTRING(str)-&gt;ptr, char, RSTRING(str)-&gt;len+len);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memcpy(RSTRING(str)-&gt;ptr + RSTRING(str)-&gt;len, ptr, len);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RSTRING(str)-&gt;len += len;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RSTRING(str)-&gt;ptr[RSTRING(str)-&gt;len] = '"0'; /* sentinel */<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return str;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; return rb_str_buf_cat(str, ptr, len);<br />
}<br />
VALUE rb_str_cat2(str, ptr)<br />
&nbsp;&nbsp;&nbsp; VALUE str;<br />
&nbsp;&nbsp;&nbsp; const char *ptr;<br />
{<br />
&nbsp;&nbsp;&nbsp; return rb_str_cat(str, ptr, strlen(ptr));<br />
}<br />
//string.c<br />
<br />
</pre>
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/144417.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-09-12 09:43 <a href="http://www.blogjava.net/killme2008/archive/2007/09/12/144417.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>对org.springframework.beans.CachedIntrospectionResults的再次解读</title><link>http://www.blogjava.net/killme2008/archive/2007/06/26/126282.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 26 Jun 2007 02:39:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/06/26/126282.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/126282.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/06/26/126282.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/126282.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/126282.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 这个类在spring2.01前没有被改写,spring2.06似乎已经改写了,还未看源码。不过这不是我所在意的问题。我在《<a id="viewpost1_TitleUrl" class="postTitle2" href="http://www.blogjava.net/killme2008/archive/2007/04/16/110889.html">org.springframework.beans简单解读</a>》中的对这个类的理解是不正确的。我们先看看Guillaume Poirier对这个类中为什么使用WeakHashMap的解释：<br><br>WeakHashMap
is implemented with WeakReference for keys, and strong reference for
values. That means if the value has a strong reference on the key, then
the key cannot be garbage collected until the WeakHashMap is ready for
collection. However, if the value has no strong reference on its key,
then being in the WeakHashMap won't prevent the key and value from
being garbage collected if it is otherwise ready. The WeakHashMap knows
when to remove the key (and the value with it) by using the
notification provided by the java.lang.ref package. For more
information on this, see: <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ref/package-summary.html" target="_blank" class="ilink">http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ref/package-summary.html</a><br><br>So
the problem here with the CachedIntrospectionResults is that it uses
BeanInfo and PropertyDescriptor that both have strong reference to the
class (indirectly by a reference on Methods of the class). That will be
solved with JDK 1.5 that uses a combinaison of Weak and Soft Reference
to the Class and Method objects, but for 1.4.2, there's not really any
better solution than to flush the Introspector's cache and/or use
WeakReference on CachedIntrospectionResults. Using WeakReference on the
CachedIntrospectionResults is safer, but decrease performance, and in
such case a manual Instrospector.flushFromCaches(Class) must be used,
so that the Instrospector does not keep a strong reference on the
BeanInfo.<br><br>When a webapp is hot-redeployed, a new ClassLoader is
created to load the webapp, and the old one is thrown away, expected to
be garbage collected. For the collection to happen, the server must
clear any strong reference to the ClassLoader or its classes, and also
the webapp must make sure that any code in parent ClassLoaders (or
siblings) clear any reference it might have to any of the webapp's
class.<br><br>&nbsp;&nbsp;&nbsp; 照他的说法和参考《深入JVM》一书，对Class有强引用的有：ClassLoader，java.beans.BeanInfo，java.beans.PropertyDescriptor,java.lang.reflect.Method。因为在这个缓存中使用Class作为key，而Value是CachedIntrospectionResults，CachedIntrospectionResults中持有BeanInfo和Method的引用，这两个都对Class对象有强引用（这一点据说在jdk5中已经修改，被改成软引用和弱引用的组合,而在jdk1.4.2需要这样的处理），导致在web应用关闭或者热部署的时候，旧的ClassLoader和它引用的类不能被回收，因此使用弱引用包装CachedIntrospectionResults对象作为Value。web应用关闭或者热部署的时候，会new新的ClassLoader用于装载类，这就是CachedIntrospectionResults判断缓存是否safe的根据所在，判断要缓存的Class引用的ClassLoader是否相同。<br>&nbsp;&nbsp;&nbsp; 当使用JavaBean的内省时，使用Introspector，jdk会自动缓存内省的信息（BeanInfo），这一点可以理解，因为内省通过反射的代价是高昂的。当ClassLoader关闭的时候，Introspector的缓存持有BeanInfo的信息，而BeanInfo持有Class的强引用，这将导致ClassLoader和它引用的Class等对象不能被垃圾收集器回收，因此在关闭前，需要手工清除Introspector中的缓存，调用Introspector.flushFromCaches，这就是CachedIntrospectionResults中当得到BeanInfo后为什么要执行下面这段代码的原因：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this</span><span style="color: #000000;">.beanInfo&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Introspector.getBeanInfo(clazz);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;Immediately&nbsp;remove&nbsp;class&nbsp;from&nbsp;Introspector&nbsp;cache,&nbsp;to&nbsp;allow&nbsp;for&nbsp;proper<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;garbage&nbsp;collection&nbsp;on&nbsp;class&nbsp;loader&nbsp;shutdown&nbsp;-&nbsp;we&nbsp;cache&nbsp;it&nbsp;here&nbsp;anyway,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;in&nbsp;a&nbsp;GC-friendly&nbsp;manner.&nbsp;In&nbsp;contrast&nbsp;to&nbsp;CachedIntrospectionResults,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;Introspector&nbsp;does&nbsp;not&nbsp;use&nbsp;WeakReferences&nbsp;as&nbsp;values&nbsp;of&nbsp;its&nbsp;WeakHashMap!</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;classToFlush&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;clazz;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">do</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Introspector.flushFromCaches(classToFlush);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classToFlush&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;classToFlush.getSuperclass();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(classToFlush&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);</span></div>
<br>说到这里，spring中有一个比较少人注意的Listener——org.springframework.web.util.IntrospectorCleanupListener,这个类的说明如下：<br><br>它是一个在web应用关闭的时候,清除JavaBeans Introspector缓存的监听器.在web.xml中注册这个listener.可以保证在web 应用关闭的时候释放与掉这个web 应用相关的class loader 和由它加载的类<br>&nbsp;<br>如果你使用了JavaBeans Introspector来分析应用中的类,系统级Introspector 缓冲中会保留这些类的hard引用。结果在你的web应用关闭的时候,这些类以及web 应用相关的class loader没有被垃圾收集器回收.<br>&nbsp;<br>不幸的是,清除Introspector的唯一方式是刷新整个缓存。这是因为我们没法判断哪些是属于你的应用的引用.所以删除被缓冲的introspection会导致把这台server上的所有应用的introspection（内省）结果都删掉.<br>&nbsp;<br>需要注意的是,<span style="font-weight: bold;">spring容器托管的bean不需要使用这个监听器.因为spring它自己的introspection所使用的缓冲在分析完一个类之后会被马上从javaBeans Introspector缓冲中清除掉(上面提到的代码说明了这一点）</span>。<br><br>一般的应用基本不会直接用到JavaBean的内省方法，所以一般不用考虑遇到此类内省资源泄露，但是，很多的类库或者框架（比如struts,Quartz）没有清除Introspector。这个Listener就是为它们&#8220;擦屁股&#8221;的。<span style="font-weight: bold;">请注意，这个监听器需要注册在web.xml中的所有应用监听器之前（比如ContentLoaderListener之前）</span>。<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">&lt;</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;">org.springframework.web.util.IntrospectorCleanupListener</span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener-class</span><span style="color: #0000ff;">&gt;</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">&lt;/</span><span style="color: #800000;">listener</span><span style="color: #0000ff;">&gt;</span></div>
<br>&nbsp;&nbsp;&nbsp; 参考资料：<br>&nbsp;《深入Java虚拟机》<br>&nbsp;《<a href="http://bbs.cjsdn.net/post/view?bid=1&amp;id=103188&amp;age=0">Class对象什么时候被回收？</a>》<br>&nbsp;《<a href="http://www.springframework.org/docs/api/org/springframework/web/util/IntrospectorCleanupListener.html">Spring API Doc</a>》<br>&nbsp; 《<a href="http://calvin.redsaga.com/viewthread.php?tid=391">ss目前的设计有引起内存泄露而导致down机的隐患</a>》
<br>&nbsp;以及一篇非常好的解释java引用类的文章《<a href="http://java.chinaitlab.com/oop/716371.html">Java对象的强、软、弱和虚引用</a>》<br><br><br><br><br>   <img src ="http://www.blogjava.net/killme2008/aggbug/126282.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-06-26 10:39 <a href="http://www.blogjava.net/killme2008/archive/2007/06/26/126282.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring源码分析：实现AOP（转载）</title><link>http://www.blogjava.net/killme2008/archive/2007/04/24/113094.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 24 Apr 2007 01:37:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/24/113094.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/113094.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/24/113094.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/113094.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/113094.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 这两天一直在读spring1.2的AOP实现源码，AOP实现原理说起来很简单，对于实现业务接口的对象使用java代理机制实现，而对于一般的类使用cglib库实现，但spring的实现还是比较复杂的，不过抓住了本质去看代码就容易多了。发现一篇04年写的<a href="http://starrynight.blogdriver.com/starrynight/162536.html">《spring源码分析：实现AOP》</a>，倒是不用自己再写了，04年的时候已经有很多人研读过spring的源码，而那时的我还在学校，对java半懂不懂的状态，就算到现在也不敢说真的懂了，继续学习、努力。文章如下：<br><br>&nbsp;&nbsp;&nbsp;
<div><strong> 我的问题</strong> </div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
为了完成公司应用开发平台的设计，这几天一直在研究Spring的扩展机制。Spring的核心无疑是BeanFactory，
ApplicationContext和AOP。在&#8220;Spring
AOP编程&#8221;教程的例子中，是由ProxyFactoryBean来实现的。问题来了，普通的bean和FactoryBean的配置完全是一样的。那
么，BeanFactory是如何区分普通的Bean和用作Proxy的FactoryBean的？ProxyFactoryBean又是怎样实现AOP
功能的？（本文还很不完善，我会继续修改。）</div>
<div>&nbsp;</div>
<div><strong> FactoryBean的职责</strong> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FactoryBean在Spring中被当成一种特殊的bean，通过实现FactoryBean接口进行扩展。FactoryBean的职责是：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; l.封装了创建对象或查找对象的逻辑。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2.提供了一个中间层，用于支持AOP。</div>
<div><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们来看一个LocalStatelessSessionProxyFactoryBean的例子。首先，定义Stateless EJB的代理，id为ejbServiceProxy：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean id="ejbServiceProxy" class="LocalStatelessSessionProxyFactoryBean"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="jndiName"&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;value&gt;myEjb&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="businessInterface"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;value&gt;com.mycompany.MyBusinessInterface&lt;/value&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</div>
<div>&nbsp;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 然后，再将这个业务逻辑服务对象注入客户程序：<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;bean id="myAction" class = "samples.myAction"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;property name="myService"&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&lt;ref bean="ejbServiceProxy"/&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &lt;/property&gt;<br>&nbsp;&nbsp;&nbsp;&nbsp; &lt;/bean&gt;</div>
<div><br>&nbsp;&nbsp;&nbsp;&nbsp; 这样，客户程序并不知道myService的实现细节，Spring使用FactoryBean完成了两者之间的解耦。</div>
<div>&nbsp;</div>
<div><strong> 准备代码分析环境</strong> </div>
<div>&nbsp;&nbsp;&nbsp;&nbsp; 1.&nbsp;安装Eclipse和Spring IDE。<br>&nbsp;&nbsp;&nbsp;&nbsp; 2.&nbsp;下载Spring framework源代码，并导入Eclipse。<br>&nbsp;&nbsp;&nbsp;&nbsp; 3.&nbsp;在类路径创建log4j.properties配置文件，设置如下：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.rootLogger=DEBUG, stdout<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.stdout=org.apache.log4j.ConsoleAppender<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;log4j.appender.stdout.layout=org.apache.log4j.PatternLayout<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; log4j.appender.stdout.layout.ConversionPattern=%d{SSS} %p %c{2} - %m%n<br>&nbsp;&nbsp;&nbsp;&nbsp; 4.&nbsp;编写TestCase，跟踪Console窗口的debug信息。</div>
<br>
<div><strong> FactoryBean源代码分析</strong> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
如果bean实现了FactoryBean接口，BeanFactory将把它作为一个bean工厂，而不是直接作为普通的bean。正常情况下，
BeanFactory的getBean（"bean"）返回FactoryBean生产的bean实例，如果要返回FactoryBean本身的实例，
使用getBean（"&amp;bean"）的调用方式。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 在分析ProxyFactoryBean之前，我们先分析BeanFactory，它是Spring Framework的基础。我们看看它是如何分别处理普通的Bean和FactoryBean的。</div>
<div>&nbsp;</div>
<div><strong> &nbsp;&nbsp;BeanFactory分析</strong> </div>
<div><strong> </strong> &nbsp;</div>
<div><strong> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BeanFactory类图</strong> <br></div>
<div align="center"><img src="http://starrynight.blogdriver.com/diary/starrynight/inc/spring_class1.gif" width="510"></div>
<div>&nbsp;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
如以上的类图所示，XmlBeanFactory继承了AbstactBeanFactory抽象类。AbstactBeanFactory类中使用了
Template
Method设计模式，其中的模板方法为getBeanDefinition（）和createBean（）两个抽象方法。其中
AbstractAutowireCapableBeanFactory类实现了getBeanDefinition（）方法，
DefaultAutowireCapableBeanFactory类实现了getBeanDefinition（）方法。当调用getBean（）方
法时，AbstractBeanFactory类定义的逻辑分别调用了这两个模板方法。</div>
<div><br><strong> &nbsp;&nbsp;&nbsp;&nbsp; BeanFactory类的调用顺序<br></strong> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 我们暂时不使用ApplicationContext，以简化分析过程。我在这里使用了&#8220;Spring AOP编程&#8221;的例子，请参照该教程阅读。首先，编写测试用例，代码如下：</div>
<div><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public class AopTest extends TestCase {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; XmlBeanFactory factory = null;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; protected void setUp() throws Exception {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; super.setUp();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InputStream is = new FileInputStream("testaop.xml");<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;factory = new XmlBeanFactory(is);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; public void testGetBean() {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Bean bean = (Bean)factory.getBean("bean");</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; assertNotNull(bean);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bean.theMethod();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</div>
<div>&nbsp;</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
1.&nbsp;首先，XmlBeanFactory使用XmlBeanDefinitionReader读入testaop.xml配置文件，后者用
XmlBeanDefinitionParser和DefaultXmlBeanDefinitionParser进行分析，从中得到
BeanDefinition的信息，并保存在XmlBeanDefinitionReader的BeanDefinitionRegistry变量里。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 2.&nbsp;客户程序调用getBean方法时，AbstractBeanFactory首先使用transFormedBeanName方法分析传入的Bean名称，判断客户程序需要FactoryBean本身，还是它所创建的Bean对象。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
3.&nbsp;接下来，如果bean被定义为singleton模式，AbstractBeanFactory调用createBean方法根据
BeanDefinition信息实例化bean类，然后将该bean实例传给getObjectForSharedInstance方法并返回
getObjectForSharedInstance的返回对象。GetObjectForSharedInstance方法摘要如类图所示，首先判断
bean是否继承了FactoryBean。如果是，返回FactoryBean的getObject方法（下节我将详细分析使用
ProxyFactoryBean如何实现AOP）；如果不是，返回bean对象。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 4.&nbsp;如果bean被定义为prototype模式，每次客户程序请求都会生成新的bean实例，因此，createBean方法直接实例化bean对象并返回。</div>
<div>&nbsp;</div>
<div><strong> &nbsp;&nbsp;ProxyFactoryBean如何实现AOP</strong> </div>
<strong> </strong>
<div><br>&nbsp;&nbsp;&nbsp;&nbsp; <strong> ProxyFactoryBean类图</strong> </div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FactoryBean接口如下图所示，共有三个方法getObject，getObjectType，和isSingleton。ProxyFactoryBean实现了FactoryBean接口，它的相关类图如下：</div>
<div>&nbsp;</div>
<div align="center"><img src="http://starrynight.blogdriver.com/diary/starrynight/inc/spring_class2.gif"></div>
<div align="center"><br>&nbsp;</div>
<div><strong> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;实现AOP的过程</strong> <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
如上图所示，ProxyFactoryBean类继承了AdvisedSupport类，后者继承了ProxyConfig类并定义了操作advisor
和interceptor的接口，以支持AOP。当BeanFactory实例化ProxyFactoryBean时，根据配置文件的定义将关于
advice，pointcut，advisor，所代理的接口和接口实现类的所有信息传给ProxyFactoryBean。</div>
<div>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
当客户程序调用BeanFactory的getBean方法时，ProxyFactory使用JdkDynamicAopProxy实例化
BeanImpl类，并用JdkDynamicAopProxy的invoke方法执行advice。至于执行advice的时机，由
ProxyFactoryBean调用RegexpMethodPointcutAdvisor进行判断。</div>
<br><br>  <img src ="http://www.blogjava.net/killme2008/aggbug/113094.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-24 09:37 <a href="http://www.blogjava.net/killme2008/archive/2007/04/24/113094.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>spring IOC容器实现探讨</title><link>http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 20 Apr 2007 03:59:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/112160.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/112160.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/112160.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp; spring IOC容器的实现，一开始我被复杂的接口和类所掩埋，看不清整体的思路和设计，踟蹰于代码丛林中，摸不清前进的方向。一开始我就决定只研读以xml文件做配置文件的XmlFactoryBean的具体实现为主要目标，渐渐地有了点感觉，用UML把spring中的bean工厂体系展现出来之后就更清晰了，让你不得不感叹设计的精巧和复杂。本文只是我个人对spring...&nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/112160.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-20 11:59 <a href="http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>org.springframework.beans简单解读</title><link>http://www.blogjava.net/killme2008/archive/2007/04/16/110889.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Mon, 16 Apr 2007 02:23:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/16/110889.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/110889.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/16/110889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/110889.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/110889.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 这个包的说明是说主要是包括用于操作JavaBean的类和接口，将被大部分spring包使用。在读这个包的代码前，我特意将JavaBean规范读了一遍。JavaBean规范不仅仅是getter、setter，定义了一个完整的轻量级组件模型，事件、方法、属性、持久化等等支持均包含在内。JavaBean规范很明显是学习Delphi的组件模型，sun希望通过它来形成一个java组件的市场，可惜结果不如人意，JavaBean在GUI方面并未形成一个类似delphi控件市场；随着spring等轻量级框架的流行，而EJB重量级的组件模型被越来越多的人放弃，JavaBean反而在服务端模型方面占据了主流
。废话不提，这个包的核心接口和类就是BeanWrapper和BeanWrapperImpl，顾名思义，这个接口就是用于包装JavaBean的行为，诸如设置和获取属性，设置属性编辑器等（PropertyEditor）。看下这个包的核心类图：<br><img src="http://www.blogjava.net/images/blogjava_net/killme2008/spring-bean.jpg" border="0"><br>BeanWrapper接口继承了PropertyAccessor（用于属性访问和设置）和PropertyEditorRegistry（属性编辑器的获取和设置）,而BeanWrapperImpl除了实现BeanWrapper接口外还继承自PropertyEditorRegistrySupport 类。在PropertyEditorRegistrySupport
类中可以看到spring默认设置的一系列自定义PropertyEditor。比如：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;registerDefaultEditors()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;HashMap(</span><span style="color: #000000;">32</span><span style="color: #000000;">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;Simple&nbsp;editors,&nbsp;without&nbsp;parameterization&nbsp;capabilities.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;The&nbsp;JDK&nbsp;does&nbsp;not&nbsp;contain&nbsp;a&nbsp;default&nbsp;editor&nbsp;for&nbsp;any&nbsp;of&nbsp;these&nbsp;target&nbsp;types.</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors.put(Class.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ClassEditor());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors.put(File.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;FileEditor());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors.put(InputStream.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;InputStreamEditor());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors.put(Locale.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;LocaleEditor());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors.put(Properties.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;PropertiesEditor());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors.put(Resource[].</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ResourceArrayPropertyEditor());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors.put(String[].</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;StringArrayPropertyEditor());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.defaultEditors.put(URL.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;URLEditor());<br><br>。。。。。。。</span></div>
<br>&nbsp;&nbsp;&nbsp; PropertyEditor的概念就是属性编辑器，或者说属性转换器，比如我们在spring的配置文件中设置某个bean的class，这是一个字符串，怎么转换为一个Class对象呢？通过上面注册的ClassEditor，看看这个类是怎么实现的：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ClassEditor&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;PropertyEditorSupport&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;ClassLoader&nbsp;classLoader;<br><br></span><span style="color: #008000;"></span><span style="color: #000000;"></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp; </span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Create&nbsp;a&nbsp;default&nbsp;ClassEditor,&nbsp;using&nbsp;the&nbsp;given&nbsp;ClassLoader.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;classLoader&nbsp;the&nbsp;ClassLoader&nbsp;to&nbsp;use<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;(or&nbsp;&lt;code&gt;null&lt;/code&gt;&nbsp;for&nbsp;the&nbsp;thread&nbsp;context&nbsp;ClassLoader)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;ClassEditor(ClassLoader&nbsp;classLoader)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.classLoader&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(classLoader&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;classLoader&nbsp;:&nbsp;Thread.currentThread().getContextClassLoader());<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setAsText(String&nbsp;text)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;IllegalArgumentException&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(StringUtils.hasText(text))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //调用辅助类，得到Class对象<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setValue(ClassUtils.forName(text.trim(),&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.classLoader));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(ClassNotFoundException&nbsp;ex)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;IllegalArgumentException(</span><span style="color: #000000;">"</span><span style="color: #000000;">Class&nbsp;not&nbsp;found:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;ex.getMessage());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setValue(</span><span style="color: #0000ff;">null</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;String&nbsp;getAsText()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class&nbsp;clazz&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(Class)&nbsp;getValue();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(clazz&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">""</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(clazz.isArray())&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;clazz.getComponentType().getName()&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;ClassUtils.ARRAY_SUFFIX;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;clazz.getName();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br></span></div>
&nbsp;&nbsp;&nbsp; 代码已经解释了一切，继承javabean的PropertyEditorSupport，自己实现转换即可。这个包另外就是定义了一个完整的异常体系，值的我们参考。另外一个值的注意的地方是CachedIntrospectionResults类的实现，这个类使用了单例模式，它的作用在于缓存JavaBean反省(Introspect）得到的信息，因为每次使用Introspector对获取JavaBean信息是个不小的性能开支。缓存使用的是WeakHashMap，而不是HashMap，看看spring的解释：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<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;&nbsp;&nbsp;&nbsp;*&nbsp;Map&nbsp;keyed&nbsp;by&nbsp;class&nbsp;containing&nbsp;CachedIntrospectionResults.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Needs&nbsp;to&nbsp;be&nbsp;a&nbsp;WeakHashMap&nbsp;with&nbsp;WeakReferences&nbsp;as&nbsp;values&nbsp;to&nbsp;allow<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;for&nbsp;proper&nbsp;garbage&nbsp;collection&nbsp;in&nbsp;case&nbsp;of&nbsp;multiple&nbsp;class&nbsp;loaders.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;Map&nbsp;classCache&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;Collections.synchronizedMap(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;WeakHashMap());</span></div>
<br>因为缓存使用的key是bean的Class对象（以保证唯一性），因此在应用存在多个class loaders的时候，为了保证垃圾收集的进行，不出现内存泄露而采用WeakHashMap，为了理解这一点，我用JProfiler测试了自定义ClassLoader情况下，内存堆的使用情况，从快照上看。在使用HashMap的情况下，因为测试的bean的Class对象被载入它的ClassLoader以及java.beans.BeanInfo，java.beans.PropertyDescriptor,java.lang.reflect.Method这四个对象强引用，而导致不可回收。而在使用WeakHashMap时，判断当载入bean的ClassLoader和载入CachedIntrospectionResults的ClassLoader是不同的时候，使用弱引用包装缓存对象，当垃圾收集起发现弱引用时将马上清除弱引用对象，该弱引用也将加入一个队列，而WeakHashMap将定时检查这个队列，当有新的弱引用达到时（意味着已经被回收）就清除相应的键值。请看：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;isCacheSafe(Class&nbsp;clazz)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">CachedIntrospectionResults的ClassLoader</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader&nbsp;cur&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;CachedIntrospectionResults.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">.getClassLoader();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">载入bean的ClassLoader</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClassLoader&nbsp;target&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;clazz.getClassLoader();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(target&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">||</span><span style="color: #000000;">&nbsp;cur&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;target)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;(cur&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cur&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;cur.getParent();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(cur&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;target)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;CachedIntrospectionResults&nbsp;forClass(Class&nbsp;beanClass)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;BeansException&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif"><br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;cacheSafe&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;isCacheSafe(beanClass);<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(cacheSafe)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;classCache.put(beanClass,&nbsp;results);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{<br></span><span style="color: #008000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</span><span style="color: #008000;">弱引用&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; classCache.put(beanClass,&nbsp;new&nbsp;WeakReference(results));</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif"></span></div>
<br>&nbsp;&nbsp;&nbsp; 不知道我的理解是否有误，如果有误，请不吝指出，谢谢。<br><br>    <img src ="http://www.blogjava.net/killme2008/aggbug/110889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-16 10:23 <a href="http://www.blogjava.net/killme2008/archive/2007/04/16/110889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>org.springframework.core.enums类图</title><link>http://www.blogjava.net/killme2008/archive/2007/04/11/109925.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Wed, 11 Apr 2007 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/11/109925.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/109925.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/11/109925.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/109925.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/109925.html</trackback:ping><description><![CDATA[&nbsp; &nbsp; 这个包按照说明是：Interfaces and classes for type-safe enum support on JDK &gt;= 1.3。提供类型安全的枚举类型。代码也是相当简单，枚举类型又分为静态类型和通用类型。静态类型其实跟jdk1.5引进的enum类型类似，都是以int类型做code，比如声明一个Dog类型：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Dog&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;StaticLabeledEnum&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #000000;"> </span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;Dog(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;code,&nbsp;String&nbsp;name)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">super</span><span style="color: #000000;">(code,&nbsp;name);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></span></div>
<br>然后就可以这样声明枚举类型了：<br><br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;Dog&nbsp;BORDER_COLLIE&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Dog(</span><span style="color: #000000;">13</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Border&nbsp;Collie</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;Dog&nbsp;WHIPPET&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Dog(</span><span style="color: #000000;">14</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Whippet</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;Dog&nbsp;GOLDEN_RETRIEVER&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Dog(</span><span style="color: #000000;">11</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;must&nbsp;set&nbsp;type&nbsp;to&nbsp;be&nbsp;recognized&nbsp;as&nbsp;a&nbsp;"Dog"</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Class&nbsp;getType()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;Dog.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;String&nbsp;getLabel()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Golden&nbsp;Retriever</span><span style="color: #000000;">"</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br></span></div>
<br>同时有一个静态枚举类型的处理类用于提取信息：StaticLabeledEnumResolver
——这个类继承自抽象类AbstractCachingLabeledEnumResolver，而抽象类实现了接口LabeledEnumResovler，看看这个接口就知道所谓处理类是干什么的了：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">interface</span><span style="color: #000000;">&nbsp;LabeledEnumResolver&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">获取某个类中声明的枚举类型，这些类型&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">必须是LabeledEnum的子类</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Set&nbsp;getLabeledEnumSet(Class&nbsp;type)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;IllegalArgumentException;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Map&nbsp;getLabeledEnumMap(Class&nbsp;type)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;IllegalArgumentException;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; //根据code获取枚举<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;LabeledEnum&nbsp;getLabeledEnumByCode(Class&nbsp;type,&nbsp;Comparable&nbsp;code)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;IllegalArgumentException;<br><br>&nbsp;&nbsp;&nbsp; //根据lable获取枚举<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;LabeledEnum&nbsp;getLabeledEnumByLabel(Class&nbsp;type,&nbsp;String&nbsp;label)&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;IllegalArgumentException;<br><br>}<br></span></div>
<br>StaticLabeledEnumResolver
使用了单例模式，同时AbstractCachingLabeledEnumResolver定义了一个模板法方法并使用：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">abstract</span><span style="color: #000000;">&nbsp;Set&nbsp;findLabeledEnums(Class&nbsp;type);</span></div>
也是一个Template Method模式应用的例子。<br><br>所谓通用性的枚举类型，是指不定义成static，并且可以灵活使用其他类型做code的枚举，比如spring已经内置的3种：ShortCodedLabeledEnum
,StringCodeLabeledEnum和LetterCodeLabeledEnum，这些类都继承自AbstractLabeledEnum,类名已经显示了它们的用途，不再细说。这个包完整的类图如下：<br><img  src="http://www.blogjava.net/images/blogjava_net/killme2008/spring-enum.jpg" border="0">&nbsp;<br><br><img src ="http://www.blogjava.net/killme2008/aggbug/109925.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-11 15:57 <a href="http://www.blogjava.net/killme2008/archive/2007/04/11/109925.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>org.springframework.core简单分析</title><link>http://www.blogjava.net/killme2008/archive/2007/04/10/109675.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 10 Apr 2007 08:56:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/10/109675.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/109675.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/10/109675.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/109675.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/109675.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 这个包的类主要用于spring框架的异常处理和一些核心的助手类（与框架具体部分无关的）。<br>&nbsp;&nbsp;&nbsp; 这个包中主要应用到了简单工厂模式，用于判断jdk版本，根据jdk版本不同提供不同的集合类、当前方法栈信息等。我们来看看是如何判断当前用户的jdk版本的：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<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;"></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;org.springframework.core;<br><br></span><span style="color: #008000;"></span><span style="color: #008000;"></span><span style="color: #000000;"></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;JdkVersion&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;JAVA_13&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;JAVA_14&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;JAVA_15&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;String&nbsp;javaVersion;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;majorJavaVersion&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;JAVA_13;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;javaVersion&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;System.getProperty(</span><span style="color: #000000;">"</span><span style="color: #000000;">java.version</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;should&nbsp;look&nbsp;like&nbsp;"1.4.1_02"</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(javaVersion.indexOf(</span><span style="color: #000000;">"</span><span style="color: #000000;">1.4.</span><span style="color: #000000;">"</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;majorJavaVersion&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;JAVA_14;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(javaVersion.indexOf(</span><span style="color: #000000;">"</span><span style="color: #000000;">1.5.</span><span style="color: #000000;">"</span><span style="color: #000000;">)&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;majorJavaVersion&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;JAVA_15;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;else&nbsp;leave&nbsp;as&nbsp;1.3&nbsp;default</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Return&nbsp;the&nbsp;full&nbsp;Java&nbsp;version&nbsp;string,&nbsp;as&nbsp;returned&nbsp;by<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&lt;code&gt;System.getProperty("java.version")&lt;/code&gt;.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;String&nbsp;getJavaVersion()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;javaVersion;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Get&nbsp;the&nbsp;major&nbsp;version&nbsp;code.&nbsp;This&nbsp;means&nbsp;we&nbsp;can&nbsp;do&nbsp;things&nbsp;like<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;&lt;code&gt;if&nbsp;(getMajorJavaVersion()&nbsp;&lt;&nbsp;JAVA_14)&lt;/code&gt;.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@return</span><span style="color: #008000;">&nbsp;a&nbsp;code&nbsp;comparable&nbsp;to&nbsp;the&nbsp;JAVA_XX&nbsp;codes&nbsp;in&nbsp;this&nbsp;class<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@see</span><span style="color: #008000;">&nbsp;#JAVA_13<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@see</span><span style="color: #008000;">&nbsp;#JAVA_14<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@see</span><span style="color: #008000;">&nbsp;#JAVA_15<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;getMajorJavaVersion()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;majorJavaVersion;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br></span></div>
<br>直接获取系统的java.version属性来进行jdk版本的判断。而CollectionFactory依据这个类来创建不同的集合类型，如果是jdk1.4就优先使用jdk1.4的集合框架，再次选择Commons Collections，最后才不得已就使用jdk1.3的集合框架，这里比较有趣的是判断Commons Collections的方法就是尝试Class.forName一个Commons集合框架中的对象，如果成功，当然证明classpath有commons-collections.jar包：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;Check&nbsp;whether&nbsp;JDK&nbsp;1.4+&nbsp;collections&nbsp;and/or<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;Commons&nbsp;Collections&nbsp;3.x&nbsp;are&nbsp;available.</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(JdkVersion.getMajorJavaVersion()&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;JdkVersion.JAVA_14)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(</span><span style="color: #000000;">"</span><span style="color: #000000;">JDK&nbsp;1.4+&nbsp;collections&nbsp;available</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Class.forName(COMMONS_COLLECTIONS_CLASS_NAME);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;commonsCollections3xAvailable&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.info(</span><span style="color: #000000;">"</span><span style="color: #000000;">Commons&nbsp;Collections&nbsp;3.x&nbsp;available</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(ClassNotFoundException&nbsp;ex)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;commonsCollections3xAvailable&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br>然后就是一系列的getXXXIfPossible（）方法用以获取最优版本的集合类型，比如getLinkedHashMapIfPossible()：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;Map&nbsp;createLinkedMapIfPossible(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;initialCapacity)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(JdkVersion.getMajorJavaVersion()&nbsp;</span><span style="color: #000000;">&gt;=</span><span style="color: #000000;">&nbsp;JdkVersion.JAVA_14)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">Creating&nbsp;[java.util.LinkedHashMap]</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;Jdk14CollectionFactory.createLinkedHashMap(initialCapacity);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(commonsCollections3xAvailable)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">Creating&nbsp;[org.apache.commons.collections.map.LinkedMap]</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;CommonsCollectionFactory.createLinkedMap(initialCapacity);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;logger.debug(</span><span style="color: #000000;">"</span><span style="color: #000000;">Falling&nbsp;back&nbsp;to&nbsp;[java.util.HashMap]&nbsp;for&nbsp;linked&nbsp;map</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;HashMap(initialCapacity);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
其中的Jdk14CollectionFactory
和CommonsCollectionFactory
也都是工厂类。可以看到，一个优秀的通用框架对于版本的兼容性非常重视。<br><br>&nbsp;&nbsp;&nbsp; 这个包中另外一个需要注意的就是用于spring AOP功能实现的辅助类——ControlFlow。ControlFlow按照rod johnson的说法就是用于获取当前调用的方法栈的具体信息。ControlFlow是一个接口，拥有3个方法用于判断当前方法栈的位置：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">interface</span><span style="color: #000000;">&nbsp;ControlFlow&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><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;clazz&nbsp;the&nbsp;clazz&nbsp;to&nbsp;look&nbsp;for<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;under(Class&nbsp;clazz);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;查找当前方法调用是否则在某类的某个方法中<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;according&nbsp;to&nbsp;the&nbsp;current&nbsp;stack&nbsp;trace.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;clazz&nbsp;the&nbsp;clazz&nbsp;to&nbsp;look&nbsp;for<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;methodName&nbsp;the&nbsp;name&nbsp;of&nbsp;the&nbsp;method&nbsp;to&nbsp;look&nbsp;for<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;under(Class&nbsp;clazz,&nbsp;String&nbsp;methodName);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><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;token&nbsp;the&nbsp;token&nbsp;to&nbsp;look&nbsp;for<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;underToken(String&nbsp;token);<br><br>}</span></div>
<br>然后根据jdk版本的不同采用不同的方式实现这个接口：Jdk14ControlFlow和Jdk13ControlFlow。这是典型的<span style="font-weight: bold;">策略模式</span>的应用。需要注意的是，这两个具体类的是放在工厂类ControlFlowFactory中作为内部类实现的:<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">abstract</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ControlFlowFactory&nbsp;{<br>&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif"><br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Jdk13ControlFlow&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;ControlFlow&nbsp;{<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif"><br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Jdk14ControlFlow&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;ControlFlow&nbsp;{<br>&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif"><br>}</span></div>
<br>在这里，我们可以学到的东西就如何去判断当前方法栈的信息？jdk1.4之前只能通过对StackTrace的字符串进行分析，而jdk1.4引入了java.lang.StackTraceElement用于获取当前方法调用所处的栈帧的信息，看看spring的使用方法，相当简单：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Jdk14ControlFlow&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;ControlFlow&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;StackTraceElement[]&nbsp;stack;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Jdk14ControlFlow()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.stack&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Throwable().getStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Searches&nbsp;for&nbsp;class&nbsp;name&nbsp;match&nbsp;in&nbsp;a&nbsp;StackTraceElement.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;under(Class&nbsp;clazz)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.notNull(clazz,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Class&nbsp;must&nbsp;not&nbsp;be&nbsp;null</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;className&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;clazz.getName();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;stack.length;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.stack[i].getClassName().equals(className))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Searches&nbsp;for&nbsp;class&nbsp;name&nbsp;match&nbsp;plus&nbsp;method&nbsp;name&nbsp;match<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;in&nbsp;a&nbsp;StackTraceElement.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;under(Class&nbsp;clazz,&nbsp;String&nbsp;methodName)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.notNull(clazz,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Class&nbsp;must&nbsp;not&nbsp;be&nbsp;null</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.notNull(methodName,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">Method&nbsp;name&nbsp;must&nbsp;not&nbsp;be&nbsp;null</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;className&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;clazz.getName();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.stack.length;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.stack[i].getClassName().equals(className)&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.stack[i].getMethodName().equals(methodName))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Leave&nbsp;it&nbsp;up&nbsp;to&nbsp;the&nbsp;caller&nbsp;to&nbsp;decide&nbsp;what&nbsp;matches.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Caller&nbsp;must&nbsp;understand&nbsp;stack&nbsp;trace&nbsp;format,&nbsp;so&nbsp;there's&nbsp;less&nbsp;abstraction.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;underToken(String&nbsp;token)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(token&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringWriter&nbsp;sw&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;StringWriter();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Throwable().printStackTrace(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;PrintWriter(sw));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;stackTrace&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;sw.toString();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;stackTrace.indexOf(token)&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></span></div>
<br>获取当前栈帧的信息，对于一般的java开发者没有什么意义，对于AOP的实现和框架开发者可能有比较重要的作用，我还未研读spring的aop部分，不敢妄言，留待以后解答，如果您已经研读过这部分代码，不吝赐教。<br><br>这个包另外的一个特点就是将java的反射API演示了一遍，特别是Constant.java（用于提取某个类public static final定义的常量）和ReflectiveVisitorHelper
（反射助手类），对于学习java反射技术也有不小的帮助。<br><br>  <img src ="http://www.blogjava.net/killme2008/aggbug/109675.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-10 16:56 <a href="http://www.blogjava.net/killme2008/archive/2007/04/10/109675.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>org.springframework.core.styler包解读</title><link>http://www.blogjava.net/killme2008/archive/2007/04/06/108946.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 06 Apr 2007 07:18:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/06/108946.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/108946.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/06/108946.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/108946.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/108946.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 这个包的说明是：Support for styling values as Strings, with ToStringCreator as central class.<br>这个包简单来说就是提供一个pretty-printing功能的辅助类，而ToStringCreator就是用于产生一个可以输出经过美化的value信息的toString()方法。使用方法参照spring的Test可以看到是这样：&nbsp;&nbsp;&nbsp;<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int</span><span style="color: #000000;">[]&nbsp;integers&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">[]&nbsp;{&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;str&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ToStringCreator(integers).toString();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span style="color: #000000;">"</span><span style="color: #000000;">[@</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;ObjectUtils.getIdentityHexString(integers)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;array&lt;Integer&gt;[0,&nbsp;1,&nbsp;2,&nbsp;3,&nbsp;4]]</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;str);</span></div>
或者写个简单例子感受下：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;[]&nbsp;a</span><span style="color: #000000;">=</span><span style="color: #000000;">{</span><span style="color: #000000;">1</span><span style="color: #000000;">,</span><span style="color: #000000;">2</span><span style="color: #000000;">,</span><span style="color: #000000;">3</span><span style="color: #000000;">,</span><span style="color: #000000;">4</span><span style="color: #000000;">,</span><span style="color: #000000;">5</span><span style="color: #000000;">,</span><span style="color: #000000;">6</span><span style="color: #000000;">,</span><span style="color: #000000;">7</span><span style="color: #000000;">,</span><span style="color: #000000;">8</span><span style="color: #000000;">,</span><span style="color: #000000;">9</span><span style="color: #000000;">};<br>System.out.println(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ToStringCreator(a).toString());</span></div>
&nbsp;&nbsp;&nbsp;&nbsp; <br>输出：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">[@18558d2&nbsp;array</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Integer</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">[</span><span style="color: #000000;">1</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">4</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">6</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">7</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">8</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">9</span><span style="color: #000000;">]]</span></div>
<br>&nbsp;&nbsp;&nbsp; 如果你接触过ruby，你应该很熟悉Object.inpsect这个功能，这里通过ToStringCreator包装的toString()方法也是产生类似的能够清晰显示对象内部结构信息的方法。spring应该是使用这些辅助类来报告清晰的错误信息或者提示信息。<br>&nbsp;&nbsp;&nbsp; 看看这个包的UML类图：<br><img src="http://www.blogjava.net/images/blogjava_net/killme2008/style.jpg" border="0"><br>&nbsp; &nbsp; 首先，你需要理解ToStringStyler和ValueStyle两个接口，ToStringStyler定义了描述一个输入的Value信息的基本模板方法：<br>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">interface</span><span style="color: #000000;">&nbsp;ToStringStyler&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Style&nbsp;a&nbsp;&lt;code&gt;toString()&lt;/code&gt;'ed&nbsp;object&nbsp;before&nbsp;its&nbsp;fields&nbsp;are&nbsp;styled.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;buffer&nbsp;the&nbsp;buffer&nbsp;to&nbsp;print&nbsp;to<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;obj&nbsp;the&nbsp;object&nbsp;to&nbsp;style<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;styleStart(StringBuffer&nbsp;buffer,&nbsp;Object&nbsp;obj);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Style&nbsp;a&nbsp;&lt;code&gt;toString()&lt;/code&gt;'ed&nbsp;object&nbsp;after&nbsp;it's&nbsp;fields&nbsp;are&nbsp;styled.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;buffer&nbsp;the&nbsp;buffer&nbsp;to&nbsp;print&nbsp;to<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;obj&nbsp;the&nbsp;object&nbsp;to&nbsp;style<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;styleEnd(StringBuffer&nbsp;buffer,&nbsp;Object&nbsp;obj);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Style&nbsp;a&nbsp;field&nbsp;value&nbsp;as&nbsp;a&nbsp;string.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;buffer&nbsp;the&nbsp;buffer&nbsp;to&nbsp;print&nbsp;to<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;fieldName&nbsp;the&nbsp;he&nbsp;name&nbsp;of&nbsp;the&nbsp;field<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;value&nbsp;the&nbsp;field&nbsp;value<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;styleField(StringBuffer&nbsp;buffer,&nbsp;String&nbsp;fieldName,&nbsp;Object&nbsp;value);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Style&nbsp;the&nbsp;given&nbsp;value.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;buffer&nbsp;the&nbsp;buffer&nbsp;to&nbsp;print&nbsp;to<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;value&nbsp;the&nbsp;field&nbsp;value<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;styleValue(StringBuffer&nbsp;buffer,&nbsp;Object&nbsp;value);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Style&nbsp;the&nbsp;field&nbsp;separator.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;buffer&nbsp;buffer&nbsp;to&nbsp;print&nbsp;to<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;styleFieldSeparator(StringBuffer&nbsp;buffer);<br><br>}</span></div>
&nbsp;&nbsp;&nbsp; 这是典型的Template Method模式，而两个接口ToStringStyler、ValueStyler和它们的相应实现DefaultToStringStyler、DefaultValueStyler又是策略模式(Strategy)的应用体现。ValueStyler和DefaultValueStyler之间不仅仅是策略模式，同时也是visitor模式，请看DefaultValueStyler中一系列重载的visit方法，这些visit方法访问不同类型Value的内部结构并构造pretty格式的String返回，提供给ToStringStyler使用。<br>&nbsp;&nbsp;&nbsp; ToStringCreator是ToStringStyler的客户，它使用ToStringStyler调用产生优美格式打印，而ToStringStyler
其实又是使用ValueStyler是访问每个不同类型的子元素并返回优美格式的String。实现的相当精巧和灵活：<br>&nbsp;&nbsp;&nbsp;
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;ToStringCreator(Object&nbsp;obj,&nbsp;ToStringStyler&nbsp;styler)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Assert.notNull(obj,&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">The&nbsp;object&nbsp;to&nbsp;be&nbsp;styled&nbsp;is&nbsp;required</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.object&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;obj;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.styler&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(styler&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;styler&nbsp;:&nbsp;DEFAULT_TO_STRING_STYLER);<br></span><span style="color: #008000;">//</span><span style="color: #008000;">开始&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.styler.styleStart(this.buffer,&nbsp;this.object);</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;}<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;ToStringCreator&nbsp;append(String&nbsp;fieldName,&nbsp;</span><span style="color: #0000ff;">byte</span><span style="color: #000000;">&nbsp;value)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;append(fieldName,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Byte(value));<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif">一系列不同类型的append方法<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;String&nbsp;toString()&nbsp;{<br></span><span style="color: #008000;">//</span><span style="color: #008000;">结束，并返回优美格式的String&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.styler.styleEnd(this.buffer,&nbsp;this.object);</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.buffer.toString();<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br> <img src ="http://www.blogjava.net/killme2008/aggbug/108946.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-06 15:18 <a href="http://www.blogjava.net/killme2008/archive/2007/04/06/108946.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit源码分析(四)——从Decorator模式说起</title><link>http://www.blogjava.net/killme2008/archive/2007/04/06/108894.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 06 Apr 2007 04:39:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/06/108894.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/108894.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/06/108894.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/108894.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/108894.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 其实我这系列小文，名为源码分析，其实是自己读《设计模式》的读书笔记。Decorator模式在java的IO库中得到应用，java的IO库看起来复杂，其实理解了Decorator模式再回头看可以很好理解并使用。<br>&nbsp;&nbsp;&nbsp; Decorator模式，也就是装饰器模式，是对象结构型模式之一。<br><br>1.意图：动态地给一个对象添加一些额外的职责。给对象添加功能，我们首先想到