<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>涂0实验室</title>
	<atom:link href="http://www.sulong.info/feed" rel="self" type="application/rss+xml" />
	<link>http://www.sulong.info</link>
	<description>java, j2ee, Java EE, spring, hibernate, python, ruby ...</description>
	<pubDate>Mon, 05 Jan 2009 12:22:25 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>JavaEE组件的并发与无状态</title>
		<link>http://www.sulong.info/archives/146</link>
		<comments>http://www.sulong.info/archives/146#comments</comments>
		<pubDate>Mon, 05 Jan 2009 12:22:00 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[程序]]></category>

		<category><![CDATA[java EE]]></category>

		<category><![CDATA[skill]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=146</guid>
		<description><![CDATA[并发与线程安全
串行运行时正确的程序在并发运行时可能会出错，这是由于并发运行的多个任务（进程或线程）之间共享了变量。在Java EE环境下很多的组件最终都是在多线程环境下并发运行的，应该牢记住这一点，避免发生诡异的错误。在上个项目中，我们的程序就出现过诡异的错误，在并发量小的测试环境下，它很少出现，但是随着并发量的增大，它出现的次数增多。经查，发现如下类似代码:

    public class SomeServlet extends HttpServlet &#123;
        private SomeType someVariable;
&#160;
        public void doPost&#40;HttpServletRequest req, HttpServletRespons rsp&#41; &#123;
            method1&#40;&#41;;
         [...]]]></description>
			<content:encoded><![CDATA[<h3>并发与线程安全</h3>
<p>串行运行时正确的程序在并发运行时可能会出错，这是由于并发运行的多个任务（进程或线程）之间共享了变量。在Java EE环境下很多的组件最终都是在多线程环境下并发运行的，应该牢记住这一点，避免发生诡异的错误。在上个项目中，我们的程序就出现过诡异的错误，在并发量小的测试环境下，它很少出现，但是随着并发量的增大，它出现的次数增多。经查，发现如下类似代码:<br/></p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> SomeServlet <span style="color: #000000; font-weight: bold;">extends</span> HttpServlet <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">private</span> SomeType someVariable;
&nbsp;
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doPost<span style="color: #009900;">&#40;</span>HttpServletRequest req, HttpServletRespons rsp<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            method1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
            method2<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000066; font-weight: bold;">void</span> method1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            ...
            <span style="color: #006633;">someVariable</span> <span style="color: #339933;">=</span> someValue;
            ...
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000066; font-weight: bold;">void</span> method2<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            ...
            <span style="color: #006633;">someVariable</span> <span style="color: #339933;">=</span> someValue;
            ...
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>method1() 和method2()都访问到了someVariable，而且程序员的本意是想在method2()使用由method1()产生的 someVariable，但是Servlet可能被多个线程共享，上面的代码不能正常工作。当Servlet容器用thread1和thread2两个线程来服务两个请求request1和request2，而thread1和thread2使用了同一个SomeServlet对象，如果JVM在 SomeServlet在执行到method1()后和method2()前时发生线程间的切换，那么就很可能导致出错，比如：thread1.method1()->thread2.method1()->thread1.method2()->thread2.method2()。实例变量和类变量都是在线程间共享的，而方法内的局部变量和参数是不会被共享的，所以要处理这个问题，最简单的方法是通过方法参数来传递 someVariable，而不是通过实例变量。所以这段程序改成这样就可以了：<br/></p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> SomeServlet <span style="color: #000000; font-weight: bold;">extends</span> HttpServlet <span style="color: #009900;">&#123;</span>
&nbsp;
        <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> doPost<span style="color: #009900;">&#40;</span>HttpServletRequest req, HttpServletRespons rsp<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            SomeType someVariable <span style="color: #339933;">=</span> method1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>;
            method2<span style="color: #009900;">&#40;</span>someVariable <span style="color: #009900;">&#41;</span>;
        <span style="color: #009900;">&#125;</span>
&nbsp;
        SomeType someVariablemethod1<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            ...
            <span style="color: #000000; font-weight: bold;">return</span> someValue;
        <span style="color: #009900;">&#125;</span>
&nbsp;
        <span style="color: #000066; font-weight: bold;">void</span> method2<span style="color: #009900;">&#40;</span>SomeType someVariable<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
            ...
            <span style="color: #006633;">someVariable</span> <span style="color: #339933;">=</span> someValue;
            ...
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>通过synchronized等并发访问控制机制也可以解决这个问题，但是我觉得上面的方式是最直观的。也许有人会说后面的代码比前面的看起来要难看，不够面向对象。这里不讨论怎样才是面向对象，或者面向对象好不好。总之后者是正确的，前者是错误的，没有正确性的程序是没有意义的。<br/></p>
<p>被过线程共享而不会出错的对象，被称之为线程安全的。显然Servlet不是线程安全的，而且还有很多组件也不是线程安全的，比如HttpSession。在上个项目中，我们使用JAXB来处理XML，每次使用时都创建一个JAXBContext对象，后来发现创建JAXBContext的代价是相当的高，于是我们想把它缓存起来在整个应用程序范围内使用，幸好我们使用的JAXBContext的实现是线程安全的，可以放心的被多个线程共享。<br/></p>
<h3>有状态与无状态</h3>
<p>有状态组件是这样一种组件，组件调用者的返回结果会依赖于这个组件之前或正在受到的调用。无状态的组件则相反，调用者的返回结果只和本次调用相关，所有调用者的调用过程不会影响到其他调用者。举例来说，someComponent组件的getLatestCaller()返回上一次的调用者，这个行为的返回值总会和上一次的调用者相关，这样的组件就是有状态的。假如有个组件math有个方法为add(x,y)，返回x+y的值，那么无论之前被哪个调用者调用过，math.add()的返回值只和本次调用的参数相关，这样的组件是无状态的。无状态的组件是线程安全的，因为被别的调用者调用并不会影响到本次的调用结果。</p>
<p>除非有必要，否则应当尽量把你的程序组件实现成无状态的。在spring, seam, ejb里都有无状态的组件。不同的框架在如何实现无状态方面各不相同。最简单的实现方法就是为无状态组件做一个包装，每次调用组件的方法时，都由包装类生成一个新的对象来处理，这样实际上就不再任何的调用者之间共享被调用者的实例，实现了无状态。比如：<br/></p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">interface</span> SomeInterface <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">public</span> SomeType doMyBusinness<span style="color: #009900;">&#40;</span>SomeArg arg<span style="color: #009900;">&#41;</span>;
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> SomeStatlessComponent <span style="color: #000000; font-weight: bold;">implements</span> SomeInterface <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">public</span> SomeType doMyBusinness<span style="color: #009900;">&#40;</span>SomeArg arg<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
           ...
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span>
&nbsp;
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> SomeStatlessComponentWrapper <span style="color: #000000; font-weight: bold;">implements</span> SomeInterface <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">public</span> SomeType doMyBusinness<span style="color: #009900;">&#40;</span>SomeArg arg<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
           <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000000; font-weight: bold;">new</span> SomeStatlessComponent<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">doMyBusinness</span><span style="color: #009900;">&#40;</span>arg<span style="color: #009900;">&#41;</span>;
        <span style="color: #009900;">&#125;</span>
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p>如果实例化组件的代价是昂贵的，用一个对象池缓存组件实例，并在每次从池中取对象时清空对象的状态可能是个更好的办法。其实只要遵循简单的原则，就很容易实现无状态，就是不使用实例变量或类变量，或者只使用只读的实例变量或只读类变量。这样的组件用单例就可以实先无状态。<br/></p>
<p>由于实现上的差别，有些框架根本就不会做过多的努力来保证组件的无状态性，相反他们把责任交给了程序员。作为组件的创作者，如果你确定你要的是无状态的组件，那么只使用只读的实例变量或类变量，是个明智的选择。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=JavaEE%E7%BB%84%E4%BB%B6%E7%9A%84%E5%B9%B6%E5%8F%91%E4%B8%8E%E6%97%A0%E7%8A%B6%E6%80%81&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F146"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/146/feed</wfw:commentRss>
		</item>
		<item>
		<title>王者归来之Seam ?!</title>
		<link>http://www.sulong.info/archives/135</link>
		<comments>http://www.sulong.info/archives/135#comments</comments>
		<pubDate>Thu, 18 Dec 2008 04:58:38 +0000</pubDate>
		<dc:creator>imlsq</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[jboss]]></category>

		<category><![CDATA[seam]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=135</guid>
		<description><![CDATA[王者归来之Seam??!!!
前言：
seam :  以前在项目开发的过程中，你需要引入很多框架（比如：hibernate, jsf , 工作流引擎&#8230;.) ,  JBOSS说，你们自己做整合，不专业，我来帮你们做了这个工作吧，我来整合，肯定比你们自己整合要好。于此，JBOSS招兵买马，把hibernate的核心团队，JSF规范制定核心团队，EJB3规范制定核心团队等等，都找来当咨询顾问，共讨整合之事，如此诞生了一个新宝宝,取名为SEAM
使用Seam已经有1个多月的时间了，对Seam有一些简单的了解，谈谈我对Seam的一点感想吧。Seam的目标就是把各种优秀的开源系统，J2EE规范，都通过seam这个框架整合起来，从而简化开发工作，提高开发效率。我想这是seam的目标。
seam亮点：
1  JSF和EJB3.0规范实现与整合是亮点之一。
seam实现了SUN公司JSF规范做了不错的工作，在开发JSF应用时，简化了一些JSF。 Seam框架试图简化JSF的开发比如JSF的异常处理，XML配置，JSF组件的调用等等，在开发的时候让JSF和后端的业务逻辑组件(business service bean)达到紧凑，易用的效果。
2 Seam 很有意思的组件管理
我没有去看seam的源代码，但是从seam的介绍文档里有一些简要的介绍，如果有说得不对的地方，仅为交流。
Seam有2种方式来管理组件，一种为了跟JSF，JSP, servlet 等接口，seam 在web.xml 里添加了一个SeamListener，把JSF所需要的组件实例缓存到ServletContext或者HttpSession中，当请求完成或者Session失效时销毁组件实例.
另一种方式是Seam业务组件，这个组件的生命周期管理，类似EJB3规范里规定的方式,Seam业务组件的生命周期管理是否就是EJB3组件规范的实现，还是有自己的管理方式，这些方面的问题，将在以后再去深入了解。
总之，有了对组件的生命周期管理，您不需要去关心事务，并发，同步等问题。我一直都觉得EJB3的组件生命周期管理，比Spring的实现要舒服很多(Spring的组件生命周期管理，还要实现Spring 的InitializingBean,DisposableBean 这2个类,EJB3的组件就是一个很干净的POJO)。
3 Hibernate，Seam中集成的经典JPA
EJB3的JPA规范，作为EJB3的重要组成部分，Seam中对此规范的实现，整合了Hibernate3. 在使用的过程中，好像针对Hibernate3做了一些优化,让您在开发过程中，使用hibernate3更加简单一些了。
EJB2的持久化方案，在过去的几年，被hibernate3之前的版本彻底打败，EJB3开始, 这2家冤家对头，居然走到了一起。在ejb3的JPA规范发布不久，Hibernate就开始支持这一规范, 以前的相互指责，现在变成相互吹捧。
(题外话：其实我在做项目的过程中是很不喜欢hibernate的，不是因为他能提高效率的话，早就抛弃它了。我更喜欢ibatis一些，都是手工写的SQL代码做成映射关系，效率提高很多，可惜他现在对ejb3规范还不支持。虽然开发的时候会多写一点代码，那可是值得的)
Seam真的是王者归来，我见未必。让我们跳出SEAM看seam。
不要看seam的介绍文档说得多好听，好比一个人自己说自己多厉害一样，没用，还是要人家去评价才行。 在你使用seam之前，请仔细评估自己的需求，是否需要使用他。
1，你的项目是否需要使用EJB？
SEAM 在文档里有说明，SEAM也可以开发类似struts+spring+hibernate一样的轻量级架构的系统，但是那是胡说八道。我可以负责任的告诉 你，seam是一个很重的架构，他大多数的技术体系都是偏重于EJB，用他开发SSH类似的系统，只会误事误工。
2, JSF是否适合你的项目？
JSF 是SUN公司主推的一种表示层解决方案。可惜生不逢时，用JSF做企业应用，有Flex,Silverlight等技术比他强。 用JSF做WEB网页方向的应用，JSF更是滑稽可笑。也许有人说，JSF跟Seam有什么关系？但是我告诉你,seam核心目标之一就是整合JSF做表 示层开发，是他整合目标的重要组成部分。如果你打算应用seam，那么表示层的开发就一定绕不过JSF这一关。尽管seam说，他不用JSF也可以，但是 不用JSF，用什么！！ 没有其它好的选择了。
3,开发效率低
呵呵，seam说我的开发效率很高嘛，但那是他自己说的嘛，seam开发环境只能在Jboss里运行才有良好的表现，Jboss在开发,调试,部署还是非常麻烦，和tomcat比效率低很多。
4,学习成本
seam引入了很多相关的其它框架包，假设你有良好的JAVA基础，一个未使用过seam的开发团队，熟悉seam起码也要3周以上的时间，这是我见过的学习成本最高的框架,他整合的框架很多，技术面很广.
5，大型系统的解决方案，seam还是无法提供
一个大型的系统，核心的关键点是：负载均衡，集中缓存处理，并行计算， 分布式存取等， seam面对这些问题，一样显得力不从心，这些问题还是需要架构师自己动手解决。而且seam中有一个web beans的技术(我在想，他使用这个是否考虑到整合JSF才这么做呢！)，给负载均衡, session的处理还不及其它框架灵活。
Seam是否是归来的王者？ 让我们拭目以待！
文章内容只是个人之见，肤浅之处，意在交流。

    

	]]></description>
			<content:encoded><![CDATA[<p>王者归来之Seam??!!!</p>
<p>前言：<br />
seam :  以前在项目开发的过程中，你需要引入很多框架（比如：hibernate, jsf , 工作流引擎&#8230;.) ,  JBOSS说，你们自己做整合，不专业，我来帮你们做了这个工作吧，我来整合，肯定比你们自己整合要好。于此，JBOSS招兵买马，把hibernate的核心团队，JSF规范制定核心团队，EJB3规范制定核心团队等等，都找来当咨询顾问，共讨整合之事，如此诞生了一个新宝宝,取名为SEAM</p>
<p>使用Seam已经有1个多月的时间了，对Seam有一些简单的了解，谈谈我对Seam的一点感想吧。Seam的目标就是把各种优秀的开源系统，J2EE规范，都通过seam这个框架整合起来，从而简化开发工作，提高开发效率。我想这是seam的目标。</p>
<p>seam亮点：</p>
<p>1  JSF和EJB3.0规范实现与整合是亮点之一。</p>
<p>seam实现了SUN公司JSF规范做了不错的工作，在开发JSF应用时，简化了一些JSF。 Seam框架试图简化JSF的开发比如JSF的异常处理，XML配置，JSF组件的调用等等，在开发的时候让JSF和后端的业务逻辑组件(business service bean)达到紧凑，易用的效果。</p>
<p>2 Seam 很有意思的组件管理</p>
<p>我没有去看seam的源代码，但是从seam的介绍文档里有一些简要的介绍，如果有说得不对的地方，仅为交流。<br />
Seam有2种方式来管理组件，一种为了跟JSF，JSP, servlet 等接口，seam 在web.xml 里添加了一个SeamListener，把JSF所需要的组件实例缓存到ServletContext或者HttpSession中，当请求完成或者Session失效时销毁组件实例.</p>
<p>另一种方式是Seam业务组件，这个组件的生命周期管理，类似EJB3规范里规定的方式,Seam业务组件的生命周期管理是否就是EJB3组件规范的实现，还是有自己的管理方式，这些方面的问题，将在以后再去深入了解。<br />
总之，有了对组件的生命周期管理，您不需要去关心事务，并发，同步等问题。我一直都觉得EJB3的组件生命周期管理，比Spring的实现要舒服很多(Spring的组件生命周期管理，还要实现Spring 的InitializingBean,DisposableBean 这2个类,EJB3的组件就是一个很干净的POJO)。</p>
<p>3 Hibernate，Seam中集成的经典JPA</p>
<p>EJB3的JPA规范，作为EJB3的重要组成部分，Seam中对此规范的实现，整合了Hibernate3. 在使用的过程中，好像针对Hibernate3做了一些优化,让您在开发过程中，使用hibernate3更加简单一些了。</p>
<p>EJB2的持久化方案，在过去的几年，被hibernate3之前的版本彻底打败，EJB3开始, 这2家冤家对头，居然走到了一起。在ejb3的JPA规范发布不久，Hibernate就开始支持这一规范, 以前的相互指责，现在变成相互吹捧。</p>
<p>(题外话：其实我在做项目的过程中是很不喜欢hibernate的，不是因为他能提高效率的话，早就抛弃它了。我更喜欢ibatis一些，都是手工写的SQL代码做成映射关系，效率提高很多，可惜他现在对ejb3规范还不支持。虽然开发的时候会多写一点代码，那可是值得的)</p>
<p>Seam真的是王者归来，我见未必。让我们跳出SEAM看seam。</p>
<p>不要看seam的介绍文档说得多好听，好比一个人自己说自己多厉害一样，没用，还是要人家去评价才行。 在你使用seam之前，请仔细评估自己的需求，是否需要使用他。</p>
<p>1，你的项目是否需要使用EJB？</p>
<p>SEAM 在文档里有说明，SEAM也可以开发类似struts+spring+hibernate一样的轻量级架构的系统，但是那是胡说八道。我可以负责任的告诉 你，seam是一个很重的架构，他大多数的技术体系都是偏重于EJB，用他开发SSH类似的系统，只会误事误工。</p>
<p>2, JSF是否适合你的项目？</p>
<p>JSF 是SUN公司主推的一种表示层解决方案。可惜生不逢时，用JSF做企业应用，有Flex,Silverlight等技术比他强。 用JSF做WEB网页方向的应用，JSF更是滑稽可笑。也许有人说，JSF跟Seam有什么关系？但是我告诉你,seam核心目标之一就是整合JSF做表 示层开发，是他整合目标的重要组成部分。如果你打算应用seam，那么表示层的开发就一定绕不过JSF这一关。尽管seam说，他不用JSF也可以，但是 不用JSF，用什么！！ 没有其它好的选择了。</p>
<p>3,开发效率低</p>
<p>呵呵，seam说我的开发效率很高嘛，但那是他自己说的嘛，seam开发环境只能在Jboss里运行才有良好的表现，Jboss在开发,调试,部署还是非常麻烦，和tomcat比效率低很多。</p>
<p>4,学习成本</p>
<p>seam引入了很多相关的其它框架包，假设你有良好的JAVA基础，一个未使用过seam的开发团队，熟悉seam起码也要3周以上的时间，这是我见过的学习成本最高的框架,他整合的框架很多，技术面很广.</p>
<p>5，大型系统的解决方案，seam还是无法提供</p>
<p>一个大型的系统，核心的关键点是：负载均衡，集中缓存处理，并行计算， 分布式存取等， seam面对这些问题，一样显得力不从心，这些问题还是需要架构师自己动手解决。而且seam中有一个web beans的技术(我在想，他使用这个是否考虑到整合JSF才这么做呢！)，给负载均衡, session的处理还不及其它框架灵活。</p>
<p>Seam是否是归来的王者？ 让我们拭目以待！</p>
<p>文章内容只是个人之见，肤浅之处，意在交流。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E7%8E%8B%E8%80%85%E5%BD%92%E6%9D%A5%E4%B9%8BSeam%20%3F%21&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F135"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/135/feed</wfw:commentRss>
		</item>
		<item>
		<title>如何让jboss下的消息驱动bean消费远程JMS消息</title>
		<link>http://www.sulong.info/archives/130</link>
		<comments>http://www.sulong.info/archives/130#comments</comments>
		<pubDate>Wed, 10 Dec 2008 11:44:58 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[jboss]]></category>

		<category><![CDATA[jms]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=130</guid>
		<description><![CDATA[用消息驱动bean来处理本地的JMS消息太容易不过了，但是如何处理远程的消息呢？翻遍了Java EE手册和API也找不到。原来各种应用服务器都有各自的实现。那么如何让jboss下的消息驱动bean消费远程JMS消息呢？把下面的代码复制到一个文件里，并重名为以-service.xml结尾的文件，放到jboss的deploy目录，就可以在本地得到一个从远程获取消息的JMS provider。

    &#60;mbean code=&#34;org.jboss.jms.jndi.JMSProviderLoader&#34; 
name=&#34;jboss.mq:service=JMSProviderLoader,name=RemoteJMSProvider,server=remotehost&#34;&#62;
        &#60;attribute name=&#34;ProviderName&#34;&#62;RemoteJMSProvider&#60;/attribute&#62;
        &#60;attribute name=&#34;ProviderAdapterClass&#34;&#62;org.jboss.jms.jndi.JNDIProviderAdapter&#60;/attribute&#62;
        &#60;!-- The connection factory --&#62;
        &#60;attribute name=&#34;FactoryRef&#34;&#62;UIL2XAConnectionFactory&#60;/attribute&#62;
        [...]]]></description>
			<content:encoded><![CDATA[<p>用消息驱动bean来处理本地的JMS消息太容易不过了，但是如何处理远程的消息呢？翻遍了Java EE手册和API也找不到。原来各种应用服务器都有各自的实现。那么如何让jboss下的消息驱动bean消费远程JMS消息呢？把下面的代码复制到一个文件里，并重名为以-service.xml结尾的文件，放到jboss的deploy目录，就可以在本地得到一个从远程获取消息的JMS provider。<br/></p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">    <span style="color: #339933;">&lt;</span>mbean code<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;org.jboss.jms.jndi.JMSProviderLoader&quot;</span> 
name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;jboss.mq:service=JMSProviderLoader,name=RemoteJMSProvider,server=remotehost&quot;</span><span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;</span>attribute name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;ProviderName&quot;</span><span style="color: #339933;">&gt;</span>RemoteJMSProvider<span style="color: #339933;">&lt;/</span>attribute<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;</span>attribute name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;ProviderAdapterClass&quot;</span><span style="color: #339933;">&gt;</span>org.<span style="color: #006633;">jboss</span>.<span style="color: #006633;">jms</span>.<span style="color: #006633;">jndi</span>.<span style="color: #006633;">JNDIProviderAdapter</span><span style="color: #339933;">&lt;/</span>attribute<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;!--</span> The connection factory <span style="color: #339933;">--&gt;</span>
        <span style="color: #339933;">&lt;</span>attribute name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;FactoryRef&quot;</span><span style="color: #339933;">&gt;</span>UIL2XAConnectionFactory<span style="color: #339933;">&lt;/</span>attribute<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;!--</span> The queue connection factory <span style="color: #339933;">--&gt;</span>
        <span style="color: #339933;">&lt;</span>attribute name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;QueueFactoryRef&quot;</span><span style="color: #339933;">&gt;</span>UIL2XAConnectionFactory<span style="color: #339933;">&lt;/</span>attribute<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;!--</span> The topic factory <span style="color: #339933;">--&gt;</span>
        <span style="color: #339933;">&lt;</span>attribute name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;TopicFactoryRef&quot;</span><span style="color: #339933;">&gt;</span>UIL2XAConnectionFactory<span style="color: #339933;">&lt;/</span>attribute<span style="color: #339933;">&gt;</span>
        <span style="color: #339933;">&lt;!--</span> Connect to JNDI on the host <span style="color: #0000ff;">&quot;the-remote-host-name&quot;</span> port <span style="color: #cc66cc;">1099</span><span style="color: #339933;">--&gt;</span>
        <span style="color: #339933;">&lt;</span>attribute name<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;Properties&quot;</span><span style="color: #339933;">&gt;</span>
            java.<span style="color: #006633;">naming</span>.<span style="color: #006633;">factory</span>.<span style="color: #006633;">initial</span><span style="color: #339933;">=</span>org.<span style="color: #006633;">jnp</span>.<span style="color: #006633;">interfaces</span>.<span style="color: #006633;">NamingContextFactory</span>
            java.<span style="color: #006633;">naming</span>.<span style="color: #006633;">factory</span>.<span style="color: #006633;">url</span>.<span style="color: #006633;">pkgs</span><span style="color: #339933;">=</span>org.<span style="color: #006633;">jnp</span>.<span style="color: #006633;">interfaces</span>
            java.<span style="color: #006633;">naming</span>.<span style="color: #006633;">provider</span>.<span style="color: #006633;">url</span><span style="color: #339933;">=</span>the<span style="color: #339933;">-</span>remote<span style="color: #339933;">-</span>host<span style="color: #339933;">-</span>name<span style="color: #339933;">:</span><span style="color: #cc66cc;">1099</span>
        <span style="color: #339933;">&lt;/</span>attribute<span style="color: #339933;">&gt;</span>
    <span style="color: #339933;">&lt;/</span>mbean<span style="color: #339933;">&gt;</span></pre></div></div>

<p><br/><br />
注意，你要把上面的 the-remote-host-name 改成你的。部署完成后，确认在jboss的JndiViewer里能不能看到 java:/RemoteJMSProvider 。然后再MDB类上加上：<br/></p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">    @MessageDriven<span style="color: #009900;">&#40;</span>activateConfig <span style="color: #339933;">=</span> <span style="color: #009900;">&#123;</span>
        @ActivationConfigProperty<span style="color: #009900;">&#40;</span>propertyName<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;destinationType&quot;</span>, propertyValue<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;javax.jms.Queue&quot;</span><span style="color: #009900;">&#41;</span>,
        @ActivationConfigProperty<span style="color: #009900;">&#40;</span>propertyName<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;destination&quot;</span>, propertyValue<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;queue/testQueue&quot;</span><span style="color: #009900;">&#41;</span>,
        @ActivationConfigProperty<span style="color: #009900;">&#40;</span>propertyName<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;providerAdapterJNDI&quot;</span>, propertyValue<span style="color: #339933;">=</span><span style="color: #0000ff;">&quot;java:/RemoteJMSProvider&quot;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span>
    <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MDB <span style="color: #000000; font-weight: bold;">implements</span> MessageListener <span style="color: #009900;">&#123;</span>
        ...
    <span style="color: #009900;">&#125;</span></pre></div></div>

<p><br/><br />
providerAdapterJNDI属性使这个MDB从刚才部署好的JMS provider那里读取消息。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E5%A6%82%E4%BD%95%E8%AE%A9jboss%E4%B8%8B%E7%9A%84%E6%B6%88%E6%81%AF%E9%A9%B1%E5%8A%A8bean%E6%B6%88%E8%B4%B9%E8%BF%9C%E7%A8%8BJMS%E6%B6%88%E6%81%AF&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F130"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/130/feed</wfw:commentRss>
		</item>
		<item>
		<title>jboss集群的Barrier mbean是个好东西</title>
		<link>http://www.sulong.info/archives/125</link>
		<comments>http://www.sulong.info/archives/125#comments</comments>
		<pubDate>Tue, 09 Dec 2008 13:38:06 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[cluster]]></category>

		<category><![CDATA[jboss]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=125</guid>
		<description><![CDATA[在jboss集群时，有一种服务被称为高可用单例服务，意思是指在集群中同时肯定有且只会有一个节点提供这个服务。换句话说这种服务只会在一个节点上启动，并且当这个节点不可用时，集群中会有另一个节点代替它，它是一个具有故障恢复能力的单例服务。要实现这种服务，最简单的方法就是把部署单元，如war, ear, jar，等放到jboss/server/all/deploy-hasingleton/ 目录下。但是放在这个目录下的应用是不能热部署，也不具有farm deploy功能的。还好jboss里有一个很特殊的mbean叫 jboss.ha:service=HASingletonDeployer,type=Barrier，利用它可以很容易的实现高可用单例服务。这个bean很特殊，只有在集群的master节点上它才会被启动，而一旦master节点不再是master，它又会停止。所以一个普通的部署单元，只要依赖上了barrier，就会具有高可用单例服务的能力。下面举一个例子。
现在要实现一个高可用的消息驱动bean，监听远程机器上的消息topic/a。如果只在集群中的一个节点上部署这个MDB，一旦这个节点不可用，消息处理就停止了。为了提高可用性，可以在每个节点上部署这个MDB，但这时同一个消息会被每个MDB收到和处理，这不是我们想要的，因为同一个消息应该只被一个 MDB处理。这个时候只要让这个MDB对barrier依赖，再把它部署在所有节点上，那么就只有主节点上的MDB会运行，并且当主节点完蛋时，其他节点变成主节点时，那个节点上的MDB会自动运行。这样我们就实现了高可用单例消息驱动bean服务。
要让mbean对barrier依赖，只要在它的部署文件里填上一行，例如:

    &#60;server&#62;
        &#60;mbean name=&#34;xx&#34; code=&#34;xx.xx.xxx&#34;&#62;
            &#60;depends&#62;jboss.ha:service=HASingletonDeployer,type=Barrier&#60;/depends&#62;
        &#60;/mbean&#62;
    &#60;/server&#62;

对于war,jar,ear，可以在jboss.xml里添加，具体见jboss文档。对于ejb3，加上下面的annotation就好了：

@org.jboss.annotation.ejb.Depends&#40;&#34;jboss.ha:service=HASingletonDeployer,type=Barrier&#34;&#41;


    

	]]></description>
			<content:encoded><![CDATA[<p>在jboss集群时，有一种服务被称为高可用单例服务，意思是指在集群中同时肯定有且只会有一个节点提供这个服务。换句话说这种服务只会在一个节点上启动，并且当这个节点不可用时，集群中会有另一个节点代替它，它是一个具有故障恢复能力的单例服务。要实现这种服务，最简单的方法就是把部署单元，如war, ear, jar，等放到jboss/server/all/deploy-hasingleton/ 目录下。但是放在这个目录下的应用是不能热部署，也不具有farm deploy功能的。还好jboss里有一个很特殊的mbean叫 jboss.ha:service=HASingletonDeployer,type=Barrier，利用它可以很容易的实现高可用单例服务。这个bean很特殊，只有在集群的master节点上它才会被启动，而一旦master节点不再是master，它又会停止。所以一个普通的部署单元，只要依赖上了barrier，就会具有高可用单例服务的能力。下面举一个例子。<br/></p>
<p>现在要实现一个高可用的消息驱动bean，监听远程机器上的消息topic/a。如果只在集群中的一个节点上部署这个MDB，一旦这个节点不可用，消息处理就停止了。为了提高可用性，可以在每个节点上部署这个MDB，但这时同一个消息会被每个MDB收到和处理，这不是我们想要的，因为同一个消息应该只被一个 MDB处理。这个时候只要让这个MDB对barrier依赖，再把它部署在所有节点上，那么就只有主节点上的MDB会运行，并且当主节点完蛋时，其他节点变成主节点时，那个节点上的MDB会自动运行。这样我们就实现了高可用单例消息驱动bean服务。<br/></p>
<p>要让mbean对barrier依赖，只要在它的部署文件里填上一行，例如:<br/></p>

<div class="wp_syntax"><div class="code"><pre class="xml xml" style="font-family:monospace;">    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;server<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;mbean</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;xx&quot;</span> <span style="color: #000066;">code</span>=<span style="color: #ff0000;">&quot;xx.xx.xxx&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
            <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;depends<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>jboss.ha:service=HASingletonDeployer,type=Barrier<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/depends<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/mbean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/server<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>对于war,jar,ear，可以在jboss.xml里添加，具体见jboss文档。对于ejb3，加上下面的annotation就好了：<br/></p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;">@org.<span style="color: #006633;">jboss</span>.<span style="color: #006633;">annotation</span>.<span style="color: #006633;">ejb</span>.<span style="color: #006633;">Depends</span><span style="color: #009900;">&#40;</span><span style="color: #0000ff;">&quot;jboss.ha:service=HASingletonDeployer,type=Barrier&quot;</span><span style="color: #009900;">&#41;</span></pre></div></div>

<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=jboss%E9%9B%86%E7%BE%A4%E7%9A%84Barrier%20mbean%E6%98%AF%E4%B8%AA%E5%A5%BD%E4%B8%9C%E8%A5%BF&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F125"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/125/feed</wfw:commentRss>
		</item>
		<item>
		<title>Java EE的不足</title>
		<link>http://www.sulong.info/archives/123</link>
		<comments>http://www.sulong.info/archives/123#comments</comments>
		<pubDate>Sun, 07 Dec 2008 15:10:12 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[java EE]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=123</guid>
		<description><![CDATA[Java EE的发布，尤其是ejb3，让我高兴了一把。改进是显而易见的，但是还不够，经过一年的多的使用，我今天忍不住要发发牢骚。
混乱的jndi
把对象绑定到树形结构的目录上，易于查找和使用，这本来是一个非常好的想法，但是偏偏被搞的非常复杂。在同一个服务器内，你能看到的jndi的形式可能有 /a/b, java:a/b,java:com/env/a/b, 甚至a/b。为什么JCP那帮人就不能把这个名称统一一下呢？部署在应用服务器上的组件，可以有一个jndi，但是Java EE偏偏没有定义将组件映射到一个什么样的jndi名字上，于是在glassfish下，默认的数据源的jndi名是java:/jdbc/db，在 jboss下则是java:/db，就算是ejb，在不同的应用服务器上被部署后都会被分配给不同的名字。@Resource可以把jndi资源注入到组件中，但是在引用组件时却可以通过两个名字，如：@Resource(name=&#8221;a/b&#8221;) @Resource(mappedName=&#8221;a/b&#8221;)，好讨厌！什么时候jndi能够被统一起来，java EE在易用性上一定会进一大步！
半吊子的依赖注入
当我听到可以通过@Resource @EJB注入资源时，我非常高兴，那岂不是意味着Java 应用服务器，一下子就变成了个spring bean容器了？但是最终的结果很令人失望，因为你只能注入有jndi名字的东西，而且只能将它注入到指定的几种组件中，这样的限制一下子把好好的依赖注入给废了。通过jndi去找组件，比通过spring bean的名字找bean要难多了，而且我们确实需要将组件注入到某个普通的类里面。这样的限制最终导致了在实际项目中，很少会用到Java EE本身的依赖注入功能。
classloader的噩梦
相同的一个类，被不同的classloader载入，那么在jvm中这两个类就不是同一个类。classloader的这一机制有它的道理，比如提高安全性，但是会产生一些很奇怪的问题。假设有两个classloader, cl1和cl2，这两个classloader都载入了同一个class，比如 A.class，其中cl1的A.class实例化了一个对象a1, 那么，当你试图把a1 cast成 cl2的A.class的类型的时候，就会发生ClassCastException，尽管cl1的A.class和cl2的A.class是同一个 class。J2ee规定了每个ear内的library必须能被ear内的每个成员共享，容器生成的ejb的stub也必须能在ear内被共享。通常要实现这个功能，只要给这个ear分配一个classloader，并由这个classloader载入需要被整个ear内共享的class，而ear内的 war,和ejb-jar则由这个ear的classloader的子classloader载入。有了这一机制，在ear内部，ejb的local接口可以被正常的使用而不会出现问题。但是如果跨越ear调用ejb的local接口，就会出现诸如ClassloaderException的异常。跨越 ear使用jpa也会遇到类似的问题。Java EE没有给出统一的解决方案，不同的服务器给出了不同的方案，但还没有一个解决方案算是真正的优美。
MDB不能消费远程的消息
ejb2的时代，同样作为ejb，message driven bean 远不像会话bean和实体bean那样有那么多负面评论。MDB确实很好用，唯一的不足就是没有统一和简单的方法可以让mdb监听远程的jms消息。我对此感到非常纳闷，既然Java EE的标准已经统一了那么多，为何不多进一步，也统一一下如何让MDB访问远程JMS？
或许Java EE标准的制定有太多的政治因素了，那些专家们总是再制造一些半成品。

    

	]]></description>
			<content:encoded><![CDATA[<p>Java EE的发布，尤其是ejb3，让我高兴了一把。改进是显而易见的，但是还不够，经过一年的多的使用，我今天忍不住要发发牢骚。</p>
<h2>混乱的jndi</h2>
<p>把对象绑定到树形结构的目录上，易于查找和使用，这本来是一个非常好的想法，但是偏偏被搞的非常复杂。在同一个服务器内，你能看到的jndi的形式可能有 /a/b, java:a/b,java:com/env/a/b, 甚至a/b。为什么JCP那帮人就不能把这个名称统一一下呢？部署在应用服务器上的组件，可以有一个jndi，但是Java EE偏偏没有定义将组件映射到一个什么样的jndi名字上，于是在glassfish下，默认的数据源的jndi名是java:/jdbc/db，在 jboss下则是java:/db，就算是ejb，在不同的应用服务器上被部署后都会被分配给不同的名字。@Resource可以把jndi资源注入到组件中，但是在引用组件时却可以通过两个名字，如：@Resource(name=&#8221;a/b&#8221;) @Resource(mappedName=&#8221;a/b&#8221;)，好讨厌！什么时候jndi能够被统一起来，java EE在易用性上一定会进一大步！</p>
<h2>半吊子的依赖注入</h2>
<p>当我听到可以通过@Resource @EJB注入资源时，我非常高兴，那岂不是意味着Java 应用服务器，一下子就变成了个spring bean容器了？但是最终的结果很令人失望，因为你只能注入有jndi名字的东西，而且只能将它注入到指定的几种组件中，这样的限制一下子把好好的依赖注入给废了。通过jndi去找组件，比通过spring bean的名字找bean要难多了，而且我们确实需要将组件注入到某个普通的类里面。这样的限制最终导致了在实际项目中，很少会用到Java EE本身的依赖注入功能。</p>
<h2>classloader的噩梦</h2>
<p>相同的一个类，被不同的classloader载入，那么在jvm中这两个类就不是同一个类。classloader的这一机制有它的道理，比如提高安全性，但是会产生一些很奇怪的问题。假设有两个classloader, cl1和cl2，这两个classloader都载入了同一个class，比如 A.class，其中cl1的A.class实例化了一个对象a1, 那么，当你试图把a1 cast成 cl2的A.class的类型的时候，就会发生ClassCastException，尽管cl1的A.class和cl2的A.class是同一个 class。J2ee规定了每个ear内的library必须能被ear内的每个成员共享，容器生成的ejb的stub也必须能在ear内被共享。通常要实现这个功能，只要给这个ear分配一个classloader，并由这个classloader载入需要被整个ear内共享的class，而ear内的 war,和ejb-jar则由这个ear的classloader的子classloader载入。有了这一机制，在ear内部，ejb的local接口可以被正常的使用而不会出现问题。但是如果跨越ear调用ejb的local接口，就会出现诸如ClassloaderException的异常。跨越 ear使用jpa也会遇到类似的问题。Java EE没有给出统一的解决方案，不同的服务器给出了不同的方案，但还没有一个解决方案算是真正的优美。</p>
<h2>MDB不能消费远程的消息</h2>
<p>ejb2的时代，同样作为ejb，message driven bean 远不像会话bean和实体bean那样有那么多负面评论。MDB确实很好用，唯一的不足就是没有统一和简单的方法可以让mdb监听远程的jms消息。我对此感到非常纳闷，既然Java EE的标准已经统一了那么多，为何不多进一步，也统一一下如何让MDB访问远程JMS？</p>
<p>或许Java EE标准的制定有太多的政治因素了，那些专家们总是再制造一些半成品。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=Java%20EE%E7%9A%84%E4%B8%8D%E8%B6%B3&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F123"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/123/feed</wfw:commentRss>
		</item>
		<item>
		<title>我不想在重启中浪费生命</title>
		<link>http://www.sulong.info/archives/121</link>
		<comments>http://www.sulong.info/archives/121#comments</comments>
		<pubDate>Thu, 04 Dec 2008 13:21:13 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[开发效率]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=121</guid>
		<description><![CDATA[php比java的开发效率高几乎成了大家的共识了。为什么php开发起来会比java快很多呢？频繁的服务重启是众多原因之一。php开发者们编辑完了 php代码，只要刷新一下浏览器，就可以看到运行的效果了，从来没有编译和重启apache的问题。尽管现在的IDE能够自动编译部署和打包应用程序，但 是还是没有php便捷。这一年来一直在使用jboss 4.2 做开发，jboss号称有很强的热部署能力，但是更新一个应用后还是要等上一两分钟的时间让jboss重新部署应用，而且这种热部署时间一长就会发生内存 耗尽的错误。如果是用tomcat+spring这种轻量级解决方案，重启一次十几秒钟，还可以接受，但是jboss+seam要一两分钟，而且吃掉百兆 内存，实在让人受不了。有的时候感觉一天之中没有在专心写多少代码，都是在等待jboss重启中度过。我现在对这种工作方式越来越不满，我想要更好性能的 开发机器，使用更轻量的框架，更轻量的服务器。现在使用的seam相对spring+hibernate+struts来说，还是重量的多，而jboss 也没有tomcat那样轻巧。如果能够不用等待就可以看到程序运行的效果，java在开发效率上会离php更近一步。
jboss的热部署，是指不重启jboss的情况下部署应用，比如ear, war等。虽然不重启jboss，但是还是要卸载和装载应用，还是慢。
如何热部署jboss应用呢？如果应用是用打包方式部署的，更新一下包的修改时间就可以了。如果是以目录的方式部署的，对于ear，更新一下META-INF/application.xml的修改时间，对于war，则更新WEB-INF/web.xml的修改时间。更新修改时间，最方便的就是用touch命令了，如果你用的是windows，没有touch命令，你可以装一个cygwin，或者用ant的touch任务来代替。

    

	]]></description>
			<content:encoded><![CDATA[<p>php比java的开发效率高几乎成了大家的共识了。为什么php开发起来会比java快很多呢？频繁的服务重启是众多原因之一。php开发者们编辑完了 php代码，只要刷新一下浏览器，就可以看到运行的效果了，从来没有编译和重启apache的问题。尽管现在的IDE能够自动编译部署和打包应用程序，但 是还是没有php便捷。这一年来一直在使用jboss 4.2 做开发，jboss号称有很强的热部署能力，但是更新一个应用后还是要等上一两分钟的时间让jboss重新部署应用，而且这种热部署时间一长就会发生内存 耗尽的错误。如果是用tomcat+spring这种轻量级解决方案，重启一次十几秒钟，还可以接受，但是jboss+seam要一两分钟，而且吃掉百兆 内存，实在让人受不了。有的时候感觉一天之中没有在专心写多少代码，都是在等待jboss重启中度过。我现在对这种工作方式越来越不满，我想要更好性能的 开发机器，使用更轻量的框架，更轻量的服务器。现在使用的seam相对spring+hibernate+struts来说，还是重量的多，而jboss 也没有tomcat那样轻巧。如果能够不用等待就可以看到程序运行的效果，java在开发效率上会离php更近一步。</p>
<p>jboss的热部署，是指不重启jboss的情况下部署应用，比如ear, war等。虽然不重启jboss，但是还是要卸载和装载应用，还是慢。</p>
<p>如何热部署jboss应用呢？如果应用是用打包方式部署的，更新一下包的修改时间就可以了。如果是以目录的方式部署的，对于ear，更新一下META-INF/application.xml的修改时间，对于war，则更新WEB-INF/web.xml的修改时间。更新修改时间，最方便的就是用touch命令了，如果你用的是windows，没有touch命令，你可以装一个cygwin，或者用ant的touch任务来代替。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E6%88%91%E4%B8%8D%E6%83%B3%E5%9C%A8%E9%87%8D%E5%90%AF%E4%B8%AD%E6%B5%AA%E8%B4%B9%E7%94%9F%E5%91%BD&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F121"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/121/feed</wfw:commentRss>
		</item>
		<item>
		<title>你喜欢写程序吗？</title>
		<link>http://www.sulong.info/archives/118</link>
		<comments>http://www.sulong.info/archives/118#comments</comments>
		<pubDate>Tue, 18 Nov 2008 02:27:02 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[工作]]></category>

		<category><![CDATA[生活]]></category>

		<category><![CDATA[感想]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=118</guid>
		<description><![CDATA[你喜欢写程序吗？我问过同行很多次，但是还没有碰到过哪个人干脆的回答：我喜欢。相反，说不喜欢的却有很多人。我有个大学同学说：我不喜欢计算机，不喜欢写程序，是爸妈让我来学计算机的。有的同行说：没办法，在大学学了这个专业，所以就做这一行了，其实我不喜欢写程序。我得到的最多的答案是：程序员工资高呀，我才不喜欢写程序，如果我有其他方式挣钱，我就不做程序员了。我知道我接触到的这些人是这个行业的极小部分，我期望剩下的那绝大部分中能有很多人会喜欢写程序，否则，我们这个国家的软件行业就永远没有出头之日。我们这个国家的程序员中不缺少梦想一夜暴富的投机者，也不缺少沽名钓誉的学术骗子，更不缺少为求生计混日子的人，但我们非常缺少充满激情热爱写程序的人。
不能选择自己的生活是可怜的，为了点钱把每天三分之一的时间用来做自己不喜欢做的是事是可悲的。如果你是个程序员，却并不能再程序代码中找到快乐，我劝你还是做些别的吧，你的人生不应该在这里。
而我要自豪的说，我热爱我的行业，我喜欢让指尖在键盘上跳动，让思维在代码间流动，让创造力在CPU的脉动中体现。

    

	]]></description>
			<content:encoded><![CDATA[<p>你喜欢写程序吗？我问过同行很多次，但是还没有碰到过哪个人干脆的回答：我喜欢。相反，说不喜欢的却有很多人。我有个大学同学说：我不喜欢计算机，不喜欢写程序，是爸妈让我来学计算机的。有的同行说：没办法，在大学学了这个专业，所以就做这一行了，其实我不喜欢写程序。我得到的最多的答案是：程序员工资高呀，我才不喜欢写程序，如果我有其他方式挣钱，我就不做程序员了。我知道我接触到的这些人是这个行业的极小部分，我期望剩下的那绝大部分中能有很多人会喜欢写程序，否则，我们这个国家的软件行业就永远没有出头之日。我们这个国家的程序员中不缺少梦想一夜暴富的投机者，也不缺少沽名钓誉的学术骗子，更不缺少为求生计混日子的人，但我们非常缺少充满激情热爱写程序的人。</p>
<p>不能选择自己的生活是可怜的，为了点钱把每天三分之一的时间用来做自己不喜欢做的是事是可悲的。如果你是个程序员，却并不能再程序代码中找到快乐，我劝你还是做些别的吧，你的人生不应该在这里。</p>
<p>而我要自豪的说，我热爱我的行业，我喜欢让指尖在键盘上跳动，让思维在代码间流动，让创造力在CPU的脉动中体现。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E4%BD%A0%E5%96%9C%E6%AC%A2%E5%86%99%E7%A8%8B%E5%BA%8F%E5%90%97%EF%BC%9F&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F118"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/118/feed</wfw:commentRss>
		</item>
		<item>
		<title>数据迁移经验</title>
		<link>http://www.sulong.info/archives/116</link>
		<comments>http://www.sulong.info/archives/116#comments</comments>
		<pubDate>Thu, 25 Sep 2008 17:01:07 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[工作]]></category>

		<category><![CDATA[程序]]></category>

		<category><![CDATA[database]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=116</guid>
		<description><![CDATA[做关系型数据库数据迁移的时候，为了加快速度，要注意以下几点。
充分利用数据库的能力
关系型数据库被设计成善于做查找，比较，排序等操作。在大数据量的时候，重新写个程序去对数据做查找排序等，效率往往比不过数据库。所以在数据迁移的时 候，应该尽量将此类操作交给数据库来完成。另外数据库往往都有自己的一些工具，比如导入导出工具，如果你的迁移过程要做类似的工作，也应当交给数据库来完 成。假如你要取出数据库里的一些数据，将格式做些转换，再插入到另一个数据库。你可以写个程序读一条，转换一条，写一条，但是这样很慢，还不如把数据导出 成csv等文件，然后再对文本处理生成新的另一个数据库的导入文件，然后再用另一个数据库的导入工具导入。我曾经做过这样的工作，将数据从sql server 2000迁移到 mysql，要对数据做些简单的格式转换，前一种方案用时40分钟，而后一种只要一分钟。
减少IO操作
现代计算机的CPU，总线和内存的速度都远超过各种IO的速度，所以减少IO操作就可以大幅提升数据迁移时的速度。使用连接池重复使用连接，减少新建连接 的次数可以减少IO操作。使用缓存将可能会被多次查询的数据缓存起来，减少查询数据库次数，可以显著减少IO操作。将中间结果缓存到内存或临时表中，非常 有用。最近在工作中遇到的数据迁移，通过大量的应用内存缓存，成功的将数据迁移时间有原来的近一周缩短到一个小时。
注意索引
也许你在做数据迁移时的很多查询操作是平时用不到的，所以并没有适合于做迁移查询的索引，那么你一定要记得在迁移前加上它。同样，需要被插入数据的表的索引还是先删掉吧，迁移完后再加上。
经常维护数据
不完整的数据，在迁移过程中是最让人头痛的。平时经常清理数据中的垃圾，如果垃圾成山了，数据迁移将是恶梦。

    

	]]></description>
			<content:encoded><![CDATA[<p>做关系型数据库数据迁移的时候，为了加快速度，要注意以下几点。</p>
<h3>充分利用数据库的能力</h3>
<p>关系型数据库被设计成善于做查找，比较，排序等操作。在大数据量的时候，重新写个程序去对数据做查找排序等，效率往往比不过数据库。所以在数据迁移的时 候，应该尽量将此类操作交给数据库来完成。另外数据库往往都有自己的一些工具，比如导入导出工具，如果你的迁移过程要做类似的工作，也应当交给数据库来完 成。假如你要取出数据库里的一些数据，将格式做些转换，再插入到另一个数据库。你可以写个程序读一条，转换一条，写一条，但是这样很慢，还不如把数据导出 成csv等文件，然后再对文本处理生成新的另一个数据库的导入文件，然后再用另一个数据库的导入工具导入。我曾经做过这样的工作，将数据从sql server 2000迁移到 mysql，要对数据做些简单的格式转换，前一种方案用时40分钟，而后一种只要一分钟。</p>
<h3>减少IO操作</h3>
<p>现代计算机的CPU，总线和内存的速度都远超过各种IO的速度，所以减少IO操作就可以大幅提升数据迁移时的速度。使用连接池重复使用连接，减少新建连接 的次数可以减少IO操作。使用缓存将可能会被多次查询的数据缓存起来，减少查询数据库次数，可以显著减少IO操作。将中间结果缓存到内存或临时表中，非常 有用。最近在工作中遇到的数据迁移，通过大量的应用内存缓存，成功的将数据迁移时间有原来的近一周缩短到一个小时。</p>
<h3>注意索引</h3>
<p>也许你在做数据迁移时的很多查询操作是平时用不到的，所以并没有适合于做迁移查询的索引，那么你一定要记得在迁移前加上它。同样，需要被插入数据的表的索引还是先删掉吧，迁移完后再加上。</p>
<h3>经常维护数据</h3>
<p>不完整的数据，在迁移过程中是最让人头痛的。平时经常清理数据中的垃圾，如果垃圾成山了，数据迁移将是恶梦。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E6%95%B0%E6%8D%AE%E8%BF%81%E7%A7%BB%E7%BB%8F%E9%AA%8C&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F116"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/116/feed</wfw:commentRss>
		</item>
		<item>
		<title>jboss下通过本地接口访问ejb3遇到的问题</title>
		<link>http://www.sulong.info/archives/109</link>
		<comments>http://www.sulong.info/archives/109#comments</comments>
		<pubDate>Mon, 08 Sep 2008 10:27:42 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[deploy]]></category>

		<category><![CDATA[ejb]]></category>

		<category><![CDATA[jar]]></category>

		<category><![CDATA[jboss]]></category>

		<category><![CDATA[war]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=109</guid>
		<description><![CDATA[在jboss下，如果包含ejb的jar，和要通过local接口访问ejb的war不被打包成一个ear来部署，会遇到问题。如果你的war中包含了ejb3的local接口的class，那么war在通过jndi取得ejb的引用试图将其转化成接口类型时会抛ClassCastException。而如果war中不包含local接口的class，则会抛class not found的异常。这都是由讨厌的classloader问题导致的。每个放到jboss的deploy目录里的部署单元都有自己的独立的classloader树，这两棵树在jvm的classloader里是平级的。如果war和ejb jar里都包含了某个ejb的local接口的class时，那么同一个类就分别存在于两棵classloader树中。通过jndi取得的引用的类型是ejb jar中的local接口的类型，将其转化成war里的那个local接口类型时就出错了，因为它们不是同一个类。而classloader是不能访问同级的其他的classloader下的类的，所以如果war里不包含接口的class，有会因找不到class而出错。
这种时候就是使用ear的时候，位于同一个ear里ejb jar的classloader是war的classloader的父classloader。这样，只需要部署一份接口类，war也能访问到它，因为子classloader能访问父classloader载入的类。

    

	]]></description>
			<content:encoded><![CDATA[<p>在jboss下，如果包含ejb的jar，和要通过local接口访问ejb的war不被打包成一个ear来部署，会遇到问题。如果你的war中包含了ejb3的local接口的class，那么war在通过jndi取得ejb的引用试图将其转化成接口类型时会抛ClassCastException。而如果war中不包含local接口的class，则会抛class not found的异常。这都是由讨厌的classloader问题导致的。每个放到jboss的deploy目录里的部署单元都有自己的独立的classloader树，这两棵树在jvm的classloader里是平级的。如果war和ejb jar里都包含了某个ejb的local接口的class时，那么同一个类就分别存在于两棵classloader树中。通过jndi取得的引用的类型是ejb jar中的local接口的类型，将其转化成war里的那个local接口类型时就出错了，因为它们不是同一个类。而classloader是不能访问同级的其他的classloader下的类的，所以如果war里不包含接口的class，有会因找不到class而出错。</p>
<p>这种时候就是使用ear的时候，位于同一个ear里ejb jar的classloader是war的classloader的父classloader。这样，只需要部署一份接口类，war也能访问到它，因为子classloader能访问父classloader载入的类。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=jboss%E4%B8%8B%E9%80%9A%E8%BF%87%E6%9C%AC%E5%9C%B0%E6%8E%A5%E5%8F%A3%E8%AE%BF%E9%97%AEejb3%E9%81%87%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F109"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/109/feed</wfw:commentRss>
		</item>
		<item>
		<title>使用seam时，注意实体的equals方法</title>
		<link>http://www.sulong.info/archives/104</link>
		<comments>http://www.sulong.info/archives/104#comments</comments>
		<pubDate>Fri, 08 Aug 2008 02:47:12 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[程序]]></category>

		<category><![CDATA[jsf]]></category>

		<category><![CDATA[seam]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=104</guid>
		<description><![CDATA[当你用jsf的&#60;h:selectOneMenu /&#62;之类的控件选择实体时，小心你的实体的equals方法，否则你可能就会遇到&#8221;value is not valid&#8221;的验证错误。比如，如果你的页面里有这样一段:

&#60;h:selectOneMenu value=&#34;#{fooAction.foo}&#34;&#62;
    &#60;s:selectItems value=&#34;#{fooList.resultList}&#34; var=&#34;foo&#34; label=&#34;#{foo.name}&#34;/&#62;
    &#60;s:convertEntity /&#62;
&#60;/h:selectOneMenu&#62;

你的Foo实体类的equals方法又是这样写的：

public boolean equals&#40;Object obj&#41; &#123;
    if &#40;this == obj&#41;
        return true;
    if &#40;obj == null&#41;
        return false;
  [...]]]></description>
			<content:encoded><![CDATA[<p>当你用jsf的&lt;h:selectOneMenu /&gt;之类的控件选择实体时，小心你的实体的equals方法，否则你可能就会遇到&#8221;value is not valid&#8221;的验证错误。比如，如果你的页面里有这样一段:<br id="fp1h" /></p>

<div class="wp_syntax"><div class="code"><pre class="xml xml" style="font-family:monospace;"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;h:selectOneMenu</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;#{fooAction.foo}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:selectItems</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;#{fooList.resultList}&quot;</span> <span style="color: #000066;">var</span>=<span style="color: #ff0000;">&quot;foo&quot;</span> <span style="color: #000066;">label</span>=<span style="color: #ff0000;">&quot;#{foo.name}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:convertEntity</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/h:selectOneMenu<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>你的Foo实体类的equals方法又是这样写的：<br id="o.l5" /></p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> equals<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> obj<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span> <span style="color: #339933;">==</span> obj<span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span>;
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>obj <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>getClass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> obj.<span style="color: #006633;">getClass</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
    <span style="color: #000000; font-weight: bold;">final</span> Foo other <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Area</span><span style="color: #009900;">&#41;</span> obj;
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>id <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>other.<span style="color: #006633;">id</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>id.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>other.<span style="color: #006633;">id</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span>;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>很好，你很可能就有机会遭遇seam下这个神奇的value is not valid验证问题了。到底原因何在？原因就在于seam不仅使用了jsf还使用了hibernate，而你的equals方法没有考虑到被对比的双方可 能一个是实体类，另一个可能是被hibernate动态增强过的类。JSF在客户端提交表单后，会验证客户端选中的元素是否是当初服务端给他的那些元素。 所以，JSF会拿经converter得到的实体与当初的集合里的实体一一调用equals方法对比，如果找不到一个在集合中的实体与提交来的一样，就报 错。如果集合里的对象是hibernate 延迟加载时的一个stub，那正常的对象和这个stub对比时就可能出错。对于上面的例子，getClass() != obj.getClass() 会为真，而 other.id != null 也可能为真。怎么办？改写equals方法，如下：<br id="we70" /></p>

<div class="wp_syntax"><div class="code"><pre class="java java" style="font-family:monospace;"><span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">boolean</span> equals<span style="color: #009900;">&#40;</span><span style="color: #003399;">Object</span> obj<span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #000000; font-weight: bold;">this</span> <span style="color: #339933;">==</span> obj<span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span>;
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>obj <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>getClass<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span>.<span style="color: #006633;">isAssignableFrom</span><span style="color: #009900;">&#40;</span>obj.<span style="color: #006633;">getClass</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
    <span style="color: #000000; font-weight: bold;">final</span> <span style="color: #003399;">Area</span> other <span style="color: #339933;">=</span> <span style="color: #009900;">&#40;</span><span style="color: #003399;">Area</span><span style="color: #009900;">&#41;</span> obj;
    <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>id <span style="color: #339933;">==</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
        <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span>other.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #339933;">!=</span> <span style="color: #000066; font-weight: bold;">null</span><span style="color: #009900;">&#41;</span>
            <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
    <span style="color: #009900;">&#125;</span> <span style="color: #000000; font-weight: bold;">else</span> <span style="color: #000000; font-weight: bold;">if</span> <span style="color: #009900;">&#40;</span><span style="color: #339933;">!</span>id.<span style="color: #006633;">equals</span><span style="color: #009900;">&#40;</span>other.<span style="color: #006633;">getId</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>
        <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">false</span>;
    <span style="color: #000000; font-weight: bold;">return</span> <span style="color: #000066; font-weight: bold;">true</span>;
<span style="color: #009900;">&#125;</span></pre></div></div>

<p>isAssignableFrom方法对子类调用时一样为真。other.getId()时，则会初始化stub，取出id的值。<br id="w_0b" /><br id="ie81" />还有一种更简单的方法，那就是不要让用户选择实体，而是选择实体的id，那就没这个问题了。<br id="g64l15" /></p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E4%BD%BF%E7%94%A8seam%E6%97%B6%EF%BC%8C%E6%B3%A8%E6%84%8F%E5%AE%9E%E4%BD%93%E7%9A%84equals%E6%96%B9%E6%B3%95&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F104"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/104/feed</wfw:commentRss>
		</item>
		<item>
		<title>Qclub杭州活动——当SOA遭遇internet</title>
		<link>http://www.sulong.info/archives/101</link>
		<comments>http://www.sulong.info/archives/101#comments</comments>
		<pubDate>Sat, 26 Jul 2008 16:17:39 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[程序]]></category>

		<category><![CDATA[SOA]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=101</guid>
		<description><![CDATA[InfoQ是一个很不错的技术网站，内容不是很多，但是都很精。前两天头看到InfoQ的Qclub要在杭州和支付宝联合搞一次活动。主讲人是支付宝的首席架构师程立。抱着讨教经验的想法，我们决定参加这次活动。  活动在7月26日下午在杭州支付宝的一个会议室内举行。来得人不多，只有五十来人，但是气氛非常好。最重头的，也是此行的目的就是要听程立介绍关于支付宝的架构和如何实现SOA。听了之后觉得不虚此行，非常有借鉴意义。  从程立的表述来看，SOA不是空洞的哲学，而是实在的准则。支付宝的面向服务不仅体现在企业信息系统内部，也体现在每一个企业应用。他把一个支付宝的企业系统的发展分为三个阶段。  第一个阶段他们以少数的人，从做应用的角度来做支付宝。早先他们选用spring来做中间的业务层，将业务层再细分为很多层次，这些层次的功能都由 spring bean来提供。后来，spring beans的数量太多，达到数千个，不仅难以管理，也难以使用。尽管开发者可以完全遵循分层的规则把beans分成一组组的，但是由于系统上并没有提供杜 绝开发人员自由调用bean的能力，还是会发生成有些开发人员把层次搞乱的事情。所以在应用级别上，他们提出把beans组成组件，让组件提供服务，把不 能被直接调用的beans隐藏起来。在应用级别上，这也是SOA的一种思想。他们最终采用了OSGI来做为组件基础。  第二个阶段，就是做企业级的平台。一个企业可能有很多的业务模块，一个业务流程可能就要很多的业务模块参与进去。运用SOA的方式，就是把各个相对独立的 业务模块以服务的方式暴露出去，再用ESB来把所有的服务集成起来供上层的企业应用使用，在一个企业之内实现各个业务模块之间的SOA。  第三个阶段，是做开放的面向行业的平台。为了和其他的企业和作，为了给培养整个行业生态圈，最终支付宝走向了开放。这个时候，支付宝以REST或WS方式将支付宝的服务暴露出去。  如果以这三个阶段来评估我现在公司的状况的话，我们正处在第一个阶段，还有很长的路要走。  支付宝的SOA实践并非是死板的照抄SOA标准做法，其中最引人注目的就是他们对事务的处理。如果完全按照WS-Transaction的方式来做，性能 达不到需求，他们就根据业务需要自定义了一套事务管理机制。一个业务流程里的事务原则上来说要满足ACID原则，但是实际中可以根据业务功能的重要度，把 某些功能做成不满足ACID只要满足BaSE就可以。这里的BASE的英文描述我记不得了，意思就是在满足基本业务可用的条件下，在某些业务流程上放宽对 隔离性和一致性的要求，实现最终一致性。如果把满足ACID的叫刚性事务，那么BaSE就是柔性事务。支付宝做到可以通过配置指定一个流程中哪些服务时要 在刚性事务中的，哪些是柔性事务的。估计这个要深入研究事务，才能实现这样的功能。  讨论的时候，还有人提到支付宝如何处理有状态服务在分布式环境下一致性问题，结果程立给出的答案是，支付宝的服务没有状态。看来REST里的服务端无状态原则在SOA中也非常有用，可以简化服务。  这次活动很有收获，看到支付宝在SOA上面的成功，给了我们信心。

    

	]]></description>
			<content:encoded><![CDATA[<p>InfoQ是一个很不错的技术网站，内容不是很多，但是都很精。前两天头看到InfoQ的Qclub要在杭州和支付宝联合搞一次活动。主讲人是支付宝的首席架构师程立。抱着讨教经验的想法，我们决定参加这次活动。<br id="pguy" /> <br id="pguy0" /> 活动在7月26日下午在杭州支付宝的一个会议室内举行。来得人不多，只有五十来人，但是气氛非常好。最重头的，也是此行的目的就是要听程立介绍关于支付宝的架构和如何实现SOA。听了之后觉得不虚此行，非常有借鉴意义。<br id="tnst" /> <br id="tnst0" /> 从程立的表述来看，SOA不是空洞的哲学，而是实在的准则。支付宝的面向服务不仅体现在企业信息系统内部，也体现在每一个企业应用。他把一个支付宝的企业系统的发展分为三个阶段。<br id="npx_" /> <br id="uthf" /> 第一个阶段他们以少数的人，从做应用的角度来做支付宝。早先他们选用spring来做中间的业务层，将业务层再细分为很多层次，这些层次的功能都由 spring bean来提供。后来，spring beans的数量太多，达到数千个，不仅难以管理，也难以使用。尽管开发者可以完全遵循分层的规则把beans分成一组组的，但是由于系统上并没有提供杜 绝开发人员自由调用bean的能力，还是会发生成有些开发人员把层次搞乱的事情。所以在应用级别上，他们提出把beans组成组件，让组件提供服务，把不 能被直接调用的beans隐藏起来。在应用级别上，这也是SOA的一种思想。他们最终采用了OSGI来做为组件基础。<br id="z1b0" /> <br id="z1b00" /> 第二个阶段，就是做企业级的平台。一个企业可能有很多的业务模块，一个业务流程可能就要很多的业务模块参与进去。运用SOA的方式，就是把各个相对独立的 业务模块以服务的方式暴露出去，再用ESB来把所有的服务集成起来供上层的企业应用使用，在一个企业之内实现各个业务模块之间的SOA。<br id="ar9y" /> <br id="ar9y0" /> 第三个阶段，是做开放的面向行业的平台。为了和其他的企业和作，为了给培养整个行业生态圈，最终支付宝走向了开放。这个时候，支付宝以REST或WS方式将支付宝的服务暴露出去。<br id="fm5y" /> <br id="fm5y0" /> 如果以这三个阶段来评估我现在公司的状况的话，我们正处在第一个阶段，还有很长的路要走。<br id="umrk" /> <br id="umrk0" /> 支付宝的SOA实践并非是死板的照抄SOA标准做法，其中最引人注目的就是他们对事务的处理。如果完全按照WS-Transaction的方式来做，性能 达不到需求，他们就根据业务需要自定义了一套事务管理机制。一个业务流程里的事务原则上来说要满足ACID原则，但是实际中可以根据业务功能的重要度，把 某些功能做成不满足ACID只要满足BaSE就可以。这里的BASE的英文描述我记不得了，意思就是在满足基本业务可用的条件下，在某些业务流程上放宽对 隔离性和一致性的要求，实现最终一致性。如果把满足ACID的叫刚性事务，那么BaSE就是柔性事务。支付宝做到可以通过配置指定一个流程中哪些服务时要 在刚性事务中的，哪些是柔性事务的。估计这个要深入研究事务，才能实现这样的功能。<br id="xcd:" /> <br id="xcd:0" /> 讨论的时候，还有人提到支付宝如何处理有状态服务在分布式环境下一致性问题，结果程立给出的答案是，支付宝的服务没有状态。看来REST里的服务端无状态原则在SOA中也非常有用，可以简化服务。<br id="mh7l" /> <br id="mh7l0" /> 这次活动很有收获，看到支付宝在SOA上面的成功，给了我们信心。<br id="xqgv" /></p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=Qclub%E6%9D%AD%E5%B7%9E%E6%B4%BB%E5%8A%A8%E2%80%94%E2%80%94%E5%BD%93SOA%E9%81%AD%E9%81%87internet&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F101"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/101/feed</wfw:commentRss>
		</item>
		<item>
		<title>软件开发真理之关注点分离</title>
		<link>http://www.sulong.info/archives/99</link>
		<comments>http://www.sulong.info/archives/99#comments</comments>
		<pubDate>Fri, 25 Jul 2008 10:04:06 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[程序]]></category>

		<category><![CDATA[心得]]></category>

		<category><![CDATA[感想]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=99</guid>
		<description><![CDATA[如果说软件开发有什么真理的话，我想，那一定就是SOC（Separation of concerns，中文翻译叫关注点分离）。SOC原则，就是在软件开发中，通过各种手段，将问题的各个关注点分开。我已经记不得第一次在什么时候什么地方听说这一原则的，当时看一下就忘掉了。可是随着对软件开发的体会的加深，SOC这个概念不断的在我的脑海中浮现，以致于我把它当作软件开发的真理！
问题太过于复杂，要解决问题需要关注的点太多，而程序员的能力是有限的，不能同时关注于问题的各个方面。正如程序员的记忆力相对于计算机知识来说那么有限一样，程序员解决问题的能力相对于要解决的问题的复杂性也是一样的非常有限。计算机知识太多而且不断进化，计算机程序也太复杂，而且还在不断的复杂化。记得有一本记算机图书中，用这样一个例子来对比程序和传统行业复杂性的差别有多大，说一架精密的波音客机，所有的部件加在一起，总共只有2万个，而GCC编译器，光全局变量就有40万之多，可见程序有多复杂。另一方面，人类的注意力所能同时关注的点又是相当的少的。举个简单的例子，一般人很难同时左右手分别划圆划方，就是因为我们的大脑很难同时关注于两只手，让两只手分别做自己的事。因此，做为普通人的程序员面对这种复杂性时，必须采用某些方法把问题分解成若干部分，这样程序员可以同一时刻只关注于问题的某些方面或部分，如果分解后的部分还是太复杂，那就再划分下去，直到使复杂问题变成一个个的简单问题。这就是关注点分离原则。这一准则，并不是计算机界的发明，只不过在计算机界显得更加的重要。
实现关注点分离的方法主要有两种，一种是标准化，另一种是抽象与包装。
标准化就是制定一套标准，让使用者都遵守它，将人们的行为统一起来，这样使用标准的人就不用担心别人会有很多种不同的实现，使自己的程序不能和别人的配合。Java EE就是一个标准的大集合。如果所有的应用服务器的开发者和应用的开发者都按照标准来做，那么应用开发者就不用关心不同的应用服务器有什么差别，服务器的开发者也不用担心应用开发者开发的应用有什么差别。每个开发都只需要关注于标准本身和他所在做的事情就行了。就像是开发镙丝钉的人只专注于开发镙丝钉就行了，而不用关注镙帽是怎么生产的，反正镙帽和镙丝钉按标来就一定能合得上。也就是因为标准具有这样的威力，所有计算机界有很多标准。
不断地把程序的某些部分抽像差包装起来，也是实现关注点分离的好方法。一旦一个函数被抽像出来并实现了，那么使用函数的人就不用关心这个函数是如何实现的，同样的，一旦一个类被抽像并实现了，类的使用者也不用再关注于这个类的内部是如何实现的。诸如组件，分层，面向服务，等等这些概念都是在不同的层次上做抽像和包装，以使得使用者不用关心它的内部实现细节。
每一个程序员都应当理解SOC，并在实践中遵循这一真理。当你在编程的过程中，一时搞不清程序的每一个细节，你可以只关注于主干，把程序的主干写出来，再逐一关注没个分支。这是一种自上而下的方法。如果主干也搞不清，那可以先关注于分支，写出分支，再不断地组合这些分支成为主干，这是一种自下而上的方法。时刻考虑着，是不是要把这一段程序抽像成一个方法，或者类，是不是那样会更好。如果不这样去想去做，要么面对问题无从下手，写不出什么来，要么只会写出面条似的拖沓冗长的代码。不会用SOC，摆在面前的永远是复杂得不能解决的问题。

    

	]]></description>
			<content:encoded><![CDATA[<p>如果说软件开发有什么真理的话，我想，那一定就是SOC（Separation of concerns，中文翻译叫关注点分离）。SOC原则，就是在软件开发中，通过各种手段，将问题的各个关注点分开。我已经记不得第一次在什么时候什么地方听说这一原则的，当时看一下就忘掉了。可是随着对软件开发的体会的加深，SOC这个概念不断的在我的脑海中浮现，以致于我把它当作软件开发的真理！</p>
<p>问题太过于复杂，要解决问题需要关注的点太多，而程序员的能力是有限的，不能同时关注于问题的各个方面。正如程序员的记忆力相对于计算机知识来说那么有限一样，程序员解决问题的能力相对于要解决的问题的复杂性也是一样的非常有限。计算机知识太多而且不断进化，计算机程序也太复杂，而且还在不断的复杂化。记得有一本记算机图书中，用这样一个例子来对比程序和传统行业复杂性的差别有多大，说一架精密的波音客机，所有的部件加在一起，总共只有2万个，而GCC编译器，光全局变量就有40万之多，可见程序有多复杂。另一方面，人类的注意力所能同时关注的点又是相当的少的。举个简单的例子，一般人很难同时左右手分别划圆划方，就是因为我们的大脑很难同时关注于两只手，让两只手分别做自己的事。因此，做为普通人的程序员面对这种复杂性时，必须采用某些方法把问题分解成若干部分，这样程序员可以同一时刻只关注于问题的某些方面或部分，如果分解后的部分还是太复杂，那就再划分下去，直到使复杂问题变成一个个的简单问题。这就是关注点分离原则。这一准则，并不是计算机界的发明，只不过在计算机界显得更加的重要。</p>
<p>实现关注点分离的方法主要有两种，一种是标准化，另一种是抽象与包装。</p>
<p>标准化就是制定一套标准，让使用者都遵守它，将人们的行为统一起来，这样使用标准的人就不用担心别人会有很多种不同的实现，使自己的程序不能和别人的配合。Java EE就是一个标准的大集合。如果所有的应用服务器的开发者和应用的开发者都按照标准来做，那么应用开发者就不用关心不同的应用服务器有什么差别，服务器的开发者也不用担心应用开发者开发的应用有什么差别。每个开发都只需要关注于标准本身和他所在做的事情就行了。就像是开发镙丝钉的人只专注于开发镙丝钉就行了，而不用关注镙帽是怎么生产的，反正镙帽和镙丝钉按标来就一定能合得上。也就是因为标准具有这样的威力，所有计算机界有很多标准。</p>
<p>不断地把程序的某些部分抽像差包装起来，也是实现关注点分离的好方法。一旦一个函数被抽像出来并实现了，那么使用函数的人就不用关心这个函数是如何实现的，同样的，一旦一个类被抽像并实现了，类的使用者也不用再关注于这个类的内部是如何实现的。诸如组件，分层，面向服务，等等这些概念都是在不同的层次上做抽像和包装，以使得使用者不用关心它的内部实现细节。</p>
<p>每一个程序员都应当理解SOC，并在实践中遵循这一真理。当你在编程的过程中，一时搞不清程序的每一个细节，你可以只关注于主干，把程序的主干写出来，再逐一关注没个分支。这是一种自上而下的方法。如果主干也搞不清，那可以先关注于分支，写出分支，再不断地组合这些分支成为主干，这是一种自下而上的方法。时刻考虑着，是不是要把这一段程序抽像成一个方法，或者类，是不是那样会更好。如果不这样去想去做，要么面对问题无从下手，写不出什么来，要么只会写出面条似的拖沓冗长的代码。不会用SOC，摆在面前的永远是复杂得不能解决的问题。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91%E7%9C%9F%E7%90%86%E4%B9%8B%E5%85%B3%E6%B3%A8%E7%82%B9%E5%88%86%E7%A6%BB&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F99"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/99/feed</wfw:commentRss>
		</item>
		<item>
		<title>不读不是好程序员</title>
		<link>http://www.sulong.info/archives/97</link>
		<comments>http://www.sulong.info/archives/97#comments</comments>
		<pubDate>Wed, 23 Jul 2008 13:36:15 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[程序]]></category>

		<category><![CDATA[编程感想]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=97</guid>
		<description><![CDATA[在大学的时候开始学编程，做程序员这行当也不过三年，但是多少还是有一些对这个行当的感想。我想，如果说我比和我同时起步的同行们在这一行当做得要好一些的话，那就是因为我读过的计算机的资料在数量和质量上要比别人多一些。要想做程序员这一行当，一定要多读资料。
日常的软件开发任务，很少是重复的，因为需求和软件技术都是在不断的变化。这个行业不能像传统行业那样，一旦找到了解决问题的好办法，就可以如何炮制一千遍。比方说，木匠学会做一种椅子，那么以后他再做同样的椅子，只要严格按照之前成功的方式来做就行了。人们对软件的需求和对椅子的需求要多样化得多。而用来解决问题的软件技术，也在不断的推陈出新，飞速地变化。一个程序员，无论他的记忆力多么好，也不可能记得下所有软件开发工具的使用方法，所有程序库的API，所有标准协议的细节，等等。一个程序员，总是要面对自己的未知领域，所以当面对未知时，最快捷的方式，就是直接读书，读文档，学习前人的经验。
然而，可供我们读的资料的质量，也是参差不齐，不加选择的读，不仅进步得慢，还有可能会读到错语的信息。有一类书，一定要读，就是计算机领域里的哲学一样的书，它们研讨的是这个行当里可能再过数十年也不会过时的学问。在这里我严重推荐《代码大全》，非常的棒。你可以找到很多教习具体技术的书，却很少有专注于编码这门技术本身的书，而它就是其中之一，而且是相当的优秀的。还有一类资料，也是一定要读的，就算不能完全理解，不能读得完，但是寻找到自己感兴趣的看一看，也会让你受益匪浅，比如HTTP协议的RFC等。众多的网络编程书藉都会说到GET POST的差别，说GET时参数放到地址栏中，POST的时参数不会出现在地址栏中，但是却不会告诉你到底这些参数被放到了什么地方，等等。研读这些行业的经典资料，虽然乏味，却大有裨益！再有一类，就是那些具体技术本身的文档资料，在使用到的时候，也是要读的。比如, spring的自带的手册，非常的出色，比很多的入门资料写得都要好。不仅介绍了spring本身的东西，还会简单明了的介绍诸如AOP， 事务，等相关和知识。看到论坛上很多人发贴和spring hibernate等相关的问题，我就会想，他们一定没有读过这些软件的自带的手册。如果一个程序员所读的东西，都是别人在论坛里的只言片语，那永远都没有机会系统地认识技术，快速成长。
英语阅读能力影响程序员能力。唉，我也不愿下这样的结论，但是目前的情况来看，这个地球上的大部分的计算机技术资料确实都是英文的。如果不提升英语能力，想在这个行业赶到世界的水来，永远不可能。
我还会在这个行业做下去，所以，我还得读。

    

	]]></description>
			<content:encoded><![CDATA[<p>在大学的时候开始学编程，做程序员这行当也不过三年，但是多少还是有一些对这个行当的感想。我想，如果说我比和我同时起步的同行们在这一行当做得要好一些的话，那就是因为我读过的计算机的资料在数量和质量上要比别人多一些。要想做程序员这一行当，一定要多读资料。</p>
<p>日常的软件开发任务，很少是重复的，因为需求和软件技术都是在不断的变化。这个行业不能像传统行业那样，一旦找到了解决问题的好办法，就可以如何炮制一千遍。比方说，木匠学会做一种椅子，那么以后他再做同样的椅子，只要严格按照之前成功的方式来做就行了。人们对软件的需求和对椅子的需求要多样化得多。而用来解决问题的软件技术，也在不断的推陈出新，飞速地变化。一个程序员，无论他的记忆力多么好，也不可能记得下所有软件开发工具的使用方法，所有程序库的API，所有标准协议的细节，等等。一个程序员，总是要面对自己的未知领域，所以当面对未知时，最快捷的方式，就是直接读书，读文档，学习前人的经验。</p>
<p>然而，可供我们读的资料的质量，也是参差不齐，不加选择的读，不仅进步得慢，还有可能会读到错语的信息。有一类书，一定要读，就是计算机领域里的哲学一样的书，它们研讨的是这个行当里可能再过数十年也不会过时的学问。在这里我严重推荐《代码大全》，非常的棒。你可以找到很多教习具体技术的书，却很少有专注于编码这门技术本身的书，而它就是其中之一，而且是相当的优秀的。还有一类资料，也是一定要读的，就算不能完全理解，不能读得完，但是寻找到自己感兴趣的看一看，也会让你受益匪浅，比如HTTP协议的RFC等。众多的网络编程书藉都会说到GET POST的差别，说GET时参数放到地址栏中，POST的时参数不会出现在地址栏中，但是却不会告诉你到底这些参数被放到了什么地方，等等。研读这些行业的经典资料，虽然乏味，却大有裨益！再有一类，就是那些具体技术本身的文档资料，在使用到的时候，也是要读的。比如, spring的自带的手册，非常的出色，比很多的入门资料写得都要好。不仅介绍了spring本身的东西，还会简单明了的介绍诸如AOP， 事务，等相关和知识。看到论坛上很多人发贴和spring hibernate等相关的问题，我就会想，他们一定没有读过这些软件的自带的手册。如果一个程序员所读的东西，都是别人在论坛里的只言片语，那永远都没有机会系统地认识技术，快速成长。</p>
<p>英语阅读能力影响程序员能力。唉，我也不愿下这样的结论，但是目前的情况来看，这个地球上的大部分的计算机技术资料确实都是英文的。如果不提升英语能力，想在这个行业赶到世界的水来，永远不可能。</p>
<p>我还会在这个行业做下去，所以，我还得读。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E4%B8%8D%E8%AF%BB%E4%B8%8D%E6%98%AF%E5%A5%BD%E7%A8%8B%E5%BA%8F%E5%91%98&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F97"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/97/feed</wfw:commentRss>
		</item>
		<item>
		<title>wordpress 升级到 2.6 有点失望</title>
		<link>http://www.sulong.info/archives/95</link>
		<comments>http://www.sulong.info/archives/95#comments</comments>
		<pubDate>Wed, 23 Jul 2008 03:03:29 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[网络]]></category>

		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=95</guid>
		<description><![CDATA[2.6版本的wordpress出现有好久了，一直等c-panel里的那个fantasito什么的出现可以升级wordpress的链接，可是至今还没有出现。昨晚终于忍不住要手动升级了。吸引我去升级wordpress的原因很简单，因为听说它支持google gears了！太棒了，可以离线写blog 了吗？ 花了那么久才装好，但是发现，我错了，原来wordpress 2.6只是用google gears来减少后台下载文件，根本不能离线编辑，很失望。加速不是我想要的，能够自由的离线编辑和同步才是重要的。唉，不知道下一个版本会不会有这样的功能。

    

	]]></description>
			<content:encoded><![CDATA[<p>2.6版本的wordpress出现有好久了，一直等c-panel里的那个fantasito什么的出现可以升级wordpress的链接，可是至今还没有出现。昨晚终于忍不住要手动升级了。吸引我去升级wordpress的原因很简单，因为听说它支持google gears了！太棒了，可以离线写blog 了吗？ 花了那么久才装好，但是发现，我错了，原来wordpress 2.6只是用google gears来减少后台下载文件，根本不能离线编辑，很失望。加速不是我想要的，能够自由的离线编辑和同步才是重要的。唉，不知道下一个版本会不会有这样的功能。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=wordpress%20%E5%8D%87%E7%BA%A7%E5%88%B0%202.6%20%E6%9C%89%E7%82%B9%E5%A4%B1%E6%9C%9B&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F95"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/95/feed</wfw:commentRss>
		</item>
		<item>
		<title>在seam中使用spring</title>
		<link>http://www.sulong.info/archives/94</link>
		<comments>http://www.sulong.info/archives/94#comments</comments>
		<pubDate>Thu, 17 Jul 2008 14:44:07 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[seam]]></category>

		<category><![CDATA[spring]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=94</guid>
		<description><![CDATA[选择seam并不代表要放弃spring, 两者并不互斥，相反，可以很好的协作。seam对spring提供了很好的兼容性。那么在seam里如何使用spring里的代码呢？ 
POJO代码的重用
正如spring管理的bean是POJO一样，seam管理的组件，也是POJO的，而且连ejb3也是POJO的，所以直接的重用以前用在 spring里的代码的方法，就是直接重用POJO了。以前我们就applicationContext.xml来配置bean，现在只需要换一个语法就 能把spring的POJO bean变成seam的component。例如，对于spring的bean:
&#60;bean id=&#8221;testBean&#8221; class=&#8221;org.test.TestBean&#8221;&#62; &#60;property name=&#8221;stringProperty&#8221; value=&#8221;this is a string&#8221; /&#62; &#60;property name=&#8221;intProperty&#8221; value=&#8221;3&#8243; /&#62; &#60;property name=&#8221;anotherBean&#8221; ref=&#8221;anotherBean&#8221; /&#62; &#60;/bean&#62;
对应到seam里就是：
&#60;component name=&#8221;testBean&#8221; class=&#8221;org.test.TestBean&#8221;&#62; &#60;property name=&#8221;stringProperty&#8221;&#62;this is a string&#60;/property&#62; &#60;property name=&#8221;intProperty&#8221;&#62;3&#60;/property&#62; &#60;property name=&#8221;anotherBean&#8221;&#62;#{anotherBean}&#60;/property&#62; &#60;/component&#62;
大部分的POJO可能这就可以搞定了。但是要注意： 假如这个POJO依赖于spring容器，比如它实现了spring的bean生命周期回调方法，类似于  afterPropertiesSet() , 那么你也得让seam去模仿spring容器，在适应的时候，去调用这些回调方法。比如：
public class TestBeanAdapter extends TestBean {  @Create  public void afterPropertiesSet() {  super.afterPropertiesSet();  [...]]]></description>
			<content:encoded><![CDATA[<p>选择seam并不代表要放弃spring, 两者并不互斥，相反，可以很好的协作。seam对spring提供了很好的兼容性。那么在seam里如何使用spring里的代码呢？<br id="z0yk" /> <br id="z0yk0" /></p>
<h2 id="ce_y">POJO代码的重用</h2>
<p>正如spring管理的bean是POJO一样，seam管理的组件，也是POJO的，而且连ejb3也是POJO的，所以直接的重用以前用在 spring里的代码的方法，就是直接重用POJO了。以前我们就applicationContext.xml来配置bean，现在只需要换一个语法就 能把spring的POJO bean变成seam的component。例如，对于spring的bean:<br id="hv1c" /></p>
<blockquote id="w_km"><p>&lt;bean id=&#8221;testBean&#8221; class=&#8221;org.test.TestBean&#8221;&gt;<br id="hv1c0" /> &lt;property name=&#8221;stringProperty&#8221; value=&#8221;this is a string&#8221; /&gt;<br id="csrw" /> &lt;property name=&#8221;intProperty&#8221; value=&#8221;3&#8243; /&gt;<br id="csrw0" /> &lt;property name=&#8221;anotherBean&#8221; ref=&#8221;anotherBean&#8221; /&gt;<br id="hv1c1" /> &lt;/bean&gt;<br id="w_km0" /></p></blockquote>
<p>对应到seam里就是：<br id="w_km1" /></p>
<blockquote id="j95e"><p>&lt;component name=&#8221;testBean&#8221; class=&#8221;org.test.TestBean&#8221;&gt;<br id="vru:" /> &lt;property name=&#8221;stringProperty&#8221;&gt;this is a string&lt;/property&gt;<br id="vru:0" /> &lt;property name=&#8221;intProperty&#8221;&gt;3&lt;/property&gt;<br id="vru:1" /> &lt;property name=&#8221;anotherBean&#8221;&gt;#{anotherBean}&lt;/property&gt;<br id="dc9i" /> &lt;/component&gt;<br id="vqap" /></p></blockquote>
<p>大部分的POJO可能这就可以搞定了。但是要注意：<br id="j95e0" /> 假如这个POJO依赖于spring容器，比如它实现了spring的bean生命周期回调方法，类似于  afterPropertiesSet() , 那么你也得让seam去模仿spring容器，在适应的时候，去调用这些回调方法。比如：<br id="fqjv" /></p>
<blockquote id="razp"><p>public class TestBeanAdapter extends TestBean { <br id="razp0" /> @Create <br id="razp1" /> public void afterPropertiesSet() { <br id="razp2" /> super.afterPropertiesSet(); <br id="razp3" /> } <br id="razp4" /> }<br id="vqap0" /></p></blockquote>
<p><br id="vr__" /></p>
<h2 id="z_o3">通JSF EL Resolver来桥接</h2>
<p>只要实现了EL Resolver, 并在faces-config.xml里注册它，那么在JSF里使用EL表达式时，就会自动地调用EL Resolver来寻找这个EL表达式对应的对象等。seam当然实现了它自己的Resolver，而spring也实了这个Resolver，如果把它 们都注册上，那么JSF EL 将变成seam与spring的一座桥梁。用下面代码注册spring EL Resolver:<br id="yn_2" /></p>
<blockquote id="yn_20"><p>&lt;faces-config&gt; <br id="yn_21" /> &lt;application&gt;          <br id="yn_22" /> &lt;el-resolver&gt; <br id="yn_23" /> org.springframework.web.jsf.el.SpringBeanFacesELResolver  <br id="yn_24" /> &lt;/el-resolver&gt; <br id="yn_25" /> &lt;/application&gt; <br id="yn_26" /> &lt;/faces-config&gt;<br id="razp5" /></p></blockquote>
<p>如果你定义了spring bean testBean, 那么在seam组件里，你就可以通过 @In(&#8221;#{testBean}&#8221;) 来注入spring的bean。但是要记住，这种方法获得的对象，完全是由spring负责组装的地地道道的spring的bean, 所以它不具有seam component具有功能，比如双向注入，和seam的上下文完美一体，延长的持久化上下文(extended persistence context)。<br id="lc:7" /> <br id="lc:70" /></p>
<h2 id="n_-i">seam里的spring</h2>
<p>最完美的方案，我想你也想到了，就是让seam来管理spring容器，并加入seam的增强功能。这是可以做得到的，并且已经做到了，感谢spring的灵活性，和seam开发者们的努力。像下面那样在conponents.xml里加入spring名称空间：<br id="bqfx" /></p>
<blockquote id="bqfx0"><p>&lt;components xmlns=&#8221;http://jboss.com/products/seam/components&#8221; <br id="bqfx1" /> xmlns:xsi=&#8221;http://www.w3.org/2001/XMLSchema-instance&#8221; <br id="bqfx2" /> xmlns:spring=&#8221;http://jboss.com/products/seam/spring&#8221; <br id="bqfx3" /> xsi:schemaLocation=&#8221; <br id="bqfx4" /> http://jboss.com/products/seam/components <br id="bqfx5" /> http://jboss.com/products/seam/components-2.0.xsd <br id="bqfx6" /> http://jboss.com/products/seam/spring <br id="bqfx7" /> http://jboss.com/products/seam/spring-2.0.xsd&#8221;&gt; <br id="bqfx8" /> &lt;!&#8211; component declarations &#8211;&gt; <br id="bqfx9" /> &lt;/components&gt;<br id="n_-i0" /></p></blockquote>
<p>现在你可以在components.xml里使用&lt;spring:context-loader /&gt;了：<br id="w1r1" /></p>
<blockquote id="qnk4"><p>&lt;spring:context-loader&gt; <br id="qnk40" /> &lt;spring:config-locations&gt; <br id="qnk41" /> &lt;value&gt;classpath:spring-beans-persistence.xml&lt;/value&gt; <br id="qnk42" /> &lt;value&gt;classpath:spring-beans-service.xml&lt;/value&gt; <br id="qnk43" /> &lt;/spring:config-locations&gt; <br id="qnk44" /> &lt;/spring:context-loader&gt; <br id="n_-i1" /></p></blockquote>
<p>好了，现在当你启动seam时，seam便会到你指定的位置去寻找spring的配置，并起动一个spring容器。为了能让seam知道要如何增强 spring里的bean，我们需要在spring那边做一些手脚。在spring的配置文件里加入seam的名称空间如下：<br id="quq8" /></p>
<blockquote id="quq80"><p>&lt;beans xmlns=&#8221;http://www.springframework.org/schema/beans&#8221; <br id="quq81" /> xmlns:xsi=&#8221;http://www.w3.org/2001/XMLSchema-instance&#8221; <br id="quq82" /> xmlns:seam=&#8221;http://jboss.com/products/seam/spring-seam&#8221; <br id="quq83" /> xsi:schemaLocation=&#8221; <br id="quq84" /> http://www.springframework.org/schema/beans <br id="quq85" /> http://www.springframework.org/schema/beans/spring-beans-2.0.xsd <br id="quq86" /> http://jboss.com/products/seam/spring-seam <br id="quq87" /> http://jboss.com/products/seam/spring-seam-2.0.xsd&#8221;&gt; <br id="quq88" /> &lt;!&#8211; bean definitions &#8211;&gt; <br id="quq89" /> &lt;/bean&gt;</p></blockquote>
<p>这样，你就可以在spring的配置文件里使用以下三种元素来定义如何增强spring bean了：<br id="i9z0" /></p>
<blockquote id="khfz">
<ol id="i9z00">
<li id="i9z01">&lt;seam:conponent /&gt;  把一个spring bean变成seam component<br id="k_m3" /></li>
<li id="khfz0">&lt;seam:instance&gt; 向一个spring bean里注入seam component<br id="k_m30" /></li>
<li id="khfz1">&lt;seam:configure-scopes&gt; 定义一些默认的配置<br id="khfz2" /></li>
</ol>
</blockquote>
<p>看看下面的使用举例，我想你根本不需要解释就明白了：<br id="vtpp" /></p>
<blockquote id="f3xw"><p>&lt;bean id=&#8221;aBean&#8221; class=&#8221;org.test.TestBean&#8221; scope=&#8221;prototype&#8221;&gt;<br id="mbf0" /> &lt;property name=&#8221;aString&#8221; value=&#8221;a string&#8221; /&gt;<br id="mbf00" /> &lt;seam:component name=&#8221;testBean&#8221; scope=&#8221;CONVERSATION&#8221; auto-create=&#8221;true&#8221; /&gt;<br id="nxdp" /> &lt;/bean&gt;<br id="nxdp0" /> <br id="nxdp1" /> &lt;bean id=&#8221;anotherBean&#8221; class=&#8221;org.test.AnotherBean&#8221; scope=&#8221;prototype&#8221;&gt;<br id="nxdp2" /> &lt;property name=&#8221;aBean&#8221;&gt;<br id="h14h" /> &lt;seam:instance name=&#8221;testBean&#8221; /&gt;<br id="h14h0" /> &lt;/property&gt;<br id="kdxo" /> &lt;/bean&gt;<br id="kdxo0" /> <br id="kdxo1" /> &lt;seam:configure-scopes default-auto-create=&#8221;true&#8221;/&gt;<br id="khfz3" /></p></blockquote>
<p>spring的 aBean在seam里被叫做 testBean, 并且它在 conversation scope里，spring的anotherBean在创建它时，会把testBean注入进去。非常简单吧？<br id="c95t" /> <br id="c95t0" /> 但是，在使用过程中，要注意，seam不能对spring通过jdk 动态代理增强过的类进行再增强，所以如果要让一个spring的bean参予到seam里来，就不要对它使用动态代理的方式来实现AOP，你需要在spring的配置文件里做如下配置：<br id="fyth" /></p>
<blockquote id="w:2q"><p>&lt;aop:config <span id="w:2q0" style="color: #ff0000;">proxy-target-class=&#8221;true&#8221;</span>&gt; <br id="w:2q1" /> &#8230;&#8230;<br id="w:2q2" /> &lt;/aop:config&gt;<br id="f3xw0" /></p></blockquote>
<p>好了，至此，在seam中使用spring的方法就介绍完了。<br id="w:2q3" /></p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=%E5%9C%A8seam%E4%B8%AD%E4%BD%BF%E7%94%A8spring&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F94"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/94/feed</wfw:commentRss>
		</item>
		<item>
		<title>Seam增强了JSF</title>
		<link>http://www.sulong.info/archives/93</link>
		<comments>http://www.sulong.info/archives/93#comments</comments>
		<pubDate>Sat, 12 Jul 2008 07:33:04 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[jsf]]></category>

		<category><![CDATA[seam]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=93</guid>
		<description><![CDATA[Seam采用的JSF作为表现层技术，但是标准的jsf有很多的不足之处。
1. JSF对POST方法的http request的依赖太强了，只有POST请求的数据才能直接绑定到后台的组件上，GET方法的则不可以。
2. 根据JSF的规范，当收到一个GET请求后，JSF走完RESTORE VIEW PHARSE 就会直接到RENDER RESPONSE PHARSE，而不会做INVOKE APPLICATION，所以GET方法的请求不能触发业务逻辑。
这些限定让JSF在某些方面不太方便，比如书签功能。因为浏览器的书签都是记下当前页的URL，而不会记下POST请求里的参数。SEAM虽然采用了JSF，但是加入了Page parameter 和 page action，弥补了JSF在这方面的缺陷。
Page parameter是将GET请求时的参数直接绑定到组件上的技术。Page action则是在生成页面之前调用业务逻辑的技术。这两者的配置都可以在WEB-INF/pages.xml或者 *.page.xml里完成。比如：

    &#60;page view-id=&#34;/calculator.jsp&#34; action=&#34;#{calculator.calculate}&#34;&#62;
       &#60;param name=&#34;x&#34; value=&#34;#{calculator.lhs}&#34;/&#62;
       &#60;param name=&#34;y&#34; value=&#34;#{calculator.rhs}&#34;/&#62;
       &#60;param name=&#34;op&#34; converter=&#34;#{operatorConverter}&#34; value=&#34;#{calculator.op}&#34;/&#62;
    &#60;/page&#62;

上 [...]]]></description>
			<content:encoded><![CDATA[<p>Seam采用的JSF作为表现层技术，但是标准的jsf有很多的不足之处。</p>
<p>1. JSF对POST方法的http request的依赖太强了，只有POST请求的数据才能直接绑定到后台的组件上，GET方法的则不可以。<br />
2. 根据JSF的规范，当收到一个GET请求后，JSF走完RESTORE VIEW PHARSE 就会直接到RENDER RESPONSE PHARSE，而不会做INVOKE APPLICATION，所以GET方法的请求不能触发业务逻辑。</p>
<p>这些限定让JSF在某些方面不太方便，比如书签功能。因为浏览器的书签都是记下当前页的URL，而不会记下POST请求里的参数。SEAM虽然采用了JSF，但是加入了Page parameter 和 page action，弥补了JSF在这方面的缺陷。</p>
<p>Page parameter是将GET请求时的参数直接绑定到组件上的技术。Page action则是在生成页面之前调用业务逻辑的技术。这两者的配置都可以在WEB-INF/pages.xml或者 *.page.xml里完成。比如：</p>

<div class="wp_syntax"><div class="code"><pre class="xml xml" style="font-family:monospace;">    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;page</span> <span style="color: #000066;">view-id</span>=<span style="color: #ff0000;">&quot;/calculator.jsp&quot;</span> <span style="color: #000066;">action</span>=<span style="color: #ff0000;">&quot;#{calculator.calculate}&quot;</span><span style="color: #000000; font-weight: bold;">&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;x&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;#{calculator.lhs}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;y&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;#{calculator.rhs}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;op&quot;</span> <span style="color: #000066;">converter</span>=<span style="color: #ff0000;">&quot;#{operatorConverter}&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;#{calculator.op}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>上 面的配置，会让用GET方法访问/calculator.jsp时的参数x, y, op分别绑定到calculator的lhs, rhs和op属性上，然后执行calculator的calculate()方法。如果你只需要在页面上传递参数，而并不需要绑定到某个组件上，只需要写成：</p>

<div class="wp_syntax"><div class="code"><pre class="xml xml" style="font-family:monospace;">    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;page</span> <span style="color: #000066;">view-id</span>=<span style="color: #ff0000;">&quot;/calculator.jsp&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span></span>
        <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;result&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>这样以GET方法传来的名为result的参数将继续以result为名字在Page Scope内传递下去。</p>
<p>Page action 还可以按条件执行：</p>

<div class="wp_syntax"><div class="code"><pre class="xml xml" style="font-family:monospace;">    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;page</span> <span style="color: #000066;">view-id</span>=<span style="color: #ff0000;">&quot;/calculator.jsp&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;x&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;#{calculator.lhs}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;y&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;#{calculator.rhs}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;param</span> <span style="color: #000066;">name</span>=<span style="color: #ff0000;">&quot;op&quot;</span> <span style="color: #000066;">converter</span>=<span style="color: #ff0000;">&quot;#{operatorConverter}&quot;</span> <span style="color: #000066;">value</span>=<span style="color: #ff0000;">&quot;#{calculator.op}&quot;</span><span style="color: #000000; font-weight: bold;">/&gt;</span></span>
       <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;action</span> <span style="color: #000066;">execute</span>=<span style="color: #ff0000;">&quot;#{calculator.calculate}&quot;</span> <span style="color: #000066;">if</span>=<span style="color: #ff0000;">&quot;#{calculator.op != null}&quot;</span> <span style="color: #000000; font-weight: bold;">/&gt;</span></span>
    <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/page<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>除了在pages.xml, *.page.xml里配置，还可以用seam的组件s:link s:button来实现指定page action，例如：</p>

<div class="wp_syntax"><div class="code"><pre class="xml xml" style="font-family:monospace;">     <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;s:link</span> <span style="color: #000066;">view</span>=<span style="color: #ff0000;">&quot;/calculator.jsp&quot;</span> <span style="color: #000066;">action</span>=<span style="color: #ff0000;">&quot;#{calculator.calculate}&quot;</span> <span style="color: #000000; font-weight: bold;">&gt;</span><span style="color: #000000; font-weight: bold;">&lt;/s:link<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></pre></div></div>

<p>这 样，当这个链接被点击后，会引发一个对/calculator.jsp的GET请求，并且在生成/calculator.jsp页面之前执行 #{calculator.calculate} 方法。如果用普通的h:commandLink的话，则会提交表单，引发POST请求。</p>
<p>使用page action时要注意，在处理POST请求的时候，page action会在INVOKE APPLICATION PHARSE之后执行。</p>
<p class="addtoany_share_save_container">
    <a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save?sitename=%E6%B6%820%E5%AE%9E%E9%AA%8C%E5%AE%A4&amp;siteurl=http%3A%2F%2Fwww.sulong.info%2F&amp;linkname=Seam%E5%A2%9E%E5%BC%BA%E4%BA%86JSF&amp;linkurl=http%3A%2F%2Fwww.sulong.info%2Farchives%2F93"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Save/Bookmark"/></a>

	</p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/93/feed</wfw:commentRss>
		</item>
		<item>
		<title>会struts+spring+hibernate就可以做java架构师了吗？</title>
		<link>http://www.sulong.info/archives/92</link>
		<comments>http://www.sulong.info/archives/92#comments</comments>
		<pubDate>Wed, 09 Jul 2008 09:42:28 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
		
		<category><![CDATA[java]]></category>

		<category><![CDATA[工作]]></category>

		<category><![CDATA[architect]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=92</guid>
		<description><![CDATA[最近公司又在招人，头安排我对一些应聘者做电话面试，让我遇到了不少华而不实的家伙。这些家伙的简历上密密麻麻会写了很多项目经验，都说自己做过需求做过架构，有项目管理经验。但是细细问下去，你会很失望，有些人会把hibernate 一级缓存和二级缓存搞混，有些人声称自己从来没有用过hibernate的二级缓