<?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/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>涂0实验室 &#187; 经验</title>
	<atom:link href="http://www.sulong.info/archives/category/%e7%a8%8b%e5%ba%8f/%e7%bb%8f%e9%aa%8c/feed" rel="self" type="application/rss+xml" />
	<link>http://www.sulong.info</link>
	<description>一个程序员的成长之路</description>
	<lastBuildDate>Fri, 27 Aug 2010 01:54:11 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>异步调用</title>
		<link>http://www.sulong.info/archives/360</link>
		<comments>http://www.sulong.info/archives/360#comments</comments>
		<pubDate>Tue, 29 Jun 2010 15:28:36 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[异步]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=360</guid>
		<description><![CDATA[1 什么是异步 异步显然是和同步相对应的。同步调用，被调用者要执行完所有的代码才将执行流程交给调用者，在被调用者执行的过程中，调用者只能被动的等待；而异步，则是被调用先将执行流程转给调用者，然后自己再继续执行。如果调用者必须在得到被调用者的所有执行结果才能确定下一步该做什么的话，那么这种情况就该使用同步调用；相反，如果调用者不需要被调用者的执行结果，那么就可以使用异步。 2 怎样异步 在单线程或单进程等单一执行流程的情况下，实现不了能让被调用者个调用者并发执行的异步调用，这种情况下被调用者只能先将要执行的任务环境记录下来，带调用者执行完成后，再回头来执行之前要执行的任务，这样的方式其实算不上是异步，称之为推迟执行更贴切。 在多线程或多进程环境里，才能真正的实现异步，实现调用者和被调用者并发执行的异步调用。被调用者只要开启一个新的线程在新线程里执行任务，而立刻返回让调用者在当前线程继续执行，这样就可以实现异步调用了。 借助于ejb 3.1 , spring 3, seam这样的容器和框架，实现异步调用的方法非常简单，只需要再方法上加上指定的Annotation就可以了。使用spring 2的时候，可以注入taskExecutor，用taskExecutor.execute(Runnable r) 方法来实现异步。另外，通过JMS也可以实现异步。 3 异步有什么好处 说异步比同步调用性能好并不准确。假设 被调用方法里面要完成两个任务，分别耗时 t1和t2，从开始调用到调用返回的耗时，即响应时间，同步调用的时候，Rs = t1 + t2，异步调用的时候Ra = t1 + a1，其中a1代表为了异步调用开启新线程或新进程的耗时，如果要Ra &#60; Rs，显然要求a1 &#60; t2，可见如果异步执行的任务并不比启用异步执行耗时太多的话，异步执行也不会缩短响应时间。如果计算完成同等任务的总耗时的话，同步的时候 Ts = t1 + t2，异步的时候 Ta = t1 + a1 + t2，可见Ts &#60; Ta，此时异步没有任何好处。在要求响应时间非常短的互联网应用中，合理的采用异步可以提高响应速度，提升程序的负载能力。快速的响应用户的请求，将耗时多而用户不急于知道结果的任务交给有限的线程来执行。 然而，对于Java EE这样的环境，一个事务的边界往往是在一个线程里的，所以使用异步之后，就失去了事务的保护，异常后的数据补偿工作增加了程序的复杂性，也让程序更容易出错。一个不好的异步实现机制，往往给程序带来更多的隐患。比如，为每一个异步执行的任务都新建一个线程，很可能在并发数到一定程度的时候，由于创建过多的线程，达到性能瓶颈，甚至于导致程序崩溃。 4 什么时候用异步 首先只有调用者不需要立刻知道结果的任务才能被异步执行；其次被异步执行的任务耗时多于使用异步执行本身的时候，采用异步才值得；再次，要求响应时间短的时候采用异步才有意义。 典型的例子：用户支付订单后要立刻告知用户支付是否成功，并给用户发送邮件，通知仓库发货，告知物流送货。这种情况下，用户只要知道支付成功就行了，发送邮件等任务用户可以过会再感知到，而且发送邮件等任务很耗时，用户肯定不愿意等待完成所有一切之后才知道支付结果。这种情况下，将发送邮件等任务异步执行就很合适。 另外一个例子，A，B两个系统每隔一个小时对一次账，如果B发现账户和A系统不一样，则自动调整。尽管A不需要知道B的调整结果，但是A完全可以等待B执行，反正也没人等也没人急，而且对账频率低负载低，这种情况下就没有必要异步执行调整动作。]]></description>
			<content:encoded><![CDATA[<h1>1 什么是异步</h1>
<p>异步显然是和同步相对应的。同步调用，被调用者要执行完所有的代码才将执行流程交给调用者，在被调用者执行的过程中，调用者只能被动的等待；而异步，则是被调用先将执行流程转给调用者，然后自己再继续执行。如果调用者必须在得到被调用者的所有执行结果才能确定下一步该做什么的话，那么这种情况就该使用同步调用；相反，如果调用者不需要被调用者的执行结果，那么就可以使用异步。</p>
<h1>2 怎样异步</h1>
<p>在单线程或单进程等单一执行流程的情况下，实现不了能让被调用者个调用者并发执行的异步调用，这种情况下被调用者只能先将要执行的任务环境记录下来，带调用者执行完成后，再回头来执行之前要执行的任务，这样的方式其实算不上是异步，称之为推迟执行更贴切。</p>
<p>在多线程或多进程环境里，才能真正的实现异步，实现调用者和被调用者并发执行的异步调用。被调用者只要开启一个新的线程在新线程里执行任务，而立刻返回让调用者在当前线程继续执行，这样就可以实现异步调用了。</p>
<p>借助于ejb 3.1 , spring 3, seam这样的容器和框架，实现异步调用的方法非常简单，只需要再方法上加上指定的Annotation就可以了。使用spring 2的时候，可以注入taskExecutor，用taskExecutor.execute(Runnable r) 方法来实现异步。另外，通过JMS也可以实现异步。</p>
<h1>3 异步有什么好处</h1>
<p>说异步比同步调用性能好并不准确。假设 被调用方法里面要完成两个任务，分别耗时 t1和t2，从开始调用到调用返回的耗时，即响应时间，同步调用的时候，Rs = t1 + t2，异步调用的时候Ra = t1 + a1，其中a1代表为了异步调用开启新线程或新进程的耗时，如果要Ra &lt; Rs，显然要求a1 &lt; t2，可见如果异步执行的任务并不比启用异步执行耗时太多的话，异步执行也不会缩短响应时间。如果计算完成同等任务的总耗时的话，同步的时候 Ts = t1 + t2，异步的时候 Ta = t1 + a1 + t2，可见Ts &lt; Ta，此时异步没有任何好处。在要求响应时间非常短的互联网应用中，合理的采用异步可以提高响应速度，提升程序的负载能力。快速的响应用户的请求，将耗时多而用户不急于知道结果的任务交给有限的线程来执行。</p>
<p>然而，对于Java EE这样的环境，一个事务的边界往往是在一个线程里的，所以使用异步之后，就失去了事务的保护，异常后的数据补偿工作增加了程序的复杂性，也让程序更容易出错。一个不好的异步实现机制，往往给程序带来更多的隐患。比如，为每一个异步执行的任务都新建一个线程，很可能在并发数到一定程度的时候，由于创建过多的线程，达到性能瓶颈，甚至于导致程序崩溃。</p>
<h1>4 什么时候用异步</h1>
<p>首先只有调用者不需要立刻知道结果的任务才能被异步执行；其次被异步执行的任务耗时多于使用异步执行本身的时候，采用异步才值得；再次，要求响应时间短的时候采用异步才有意义。</p>
<p>典型的例子：用户支付订单后要立刻告知用户支付是否成功，并给用户发送邮件，通知仓库发货，告知物流送货。这种情况下，用户只要知道支付成功就行了，发送邮件等任务用户可以过会再感知到，而且发送邮件等任务很耗时，用户肯定不愿意等待完成所有一切之后才知道支付结果。这种情况下，将发送邮件等任务异步执行就很合适。</p>
<p>另外一个例子，A，B两个系统每隔一个小时对一次账，如果B发现账户和A系统不一样，则自动调整。尽管A不需要知道B的调整结果，但是A完全可以等待B执行，反正也没人等也没人急，而且对账频率低负载低，这种情况下就没有必要异步执行调整动作。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/360/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>招聘程序员感受</title>
		<link>http://www.sulong.info/archives/345</link>
		<comments>http://www.sulong.info/archives/345#comments</comments>
		<pubDate>Tue, 13 Apr 2010 14:56:41 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[生活]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[职业]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=345</guid>
		<description><![CDATA[这已经不是第一次招聘程序员了，每一次都很痛苦。以前只知道找工作不容易，现在发现招工也不容易。招聘就像找对象一样，明明满世界的男人女人，就是找不到你合适的人。 合适的人不是牛人，对于我们这样一个不算太有钱的普通电子商务私营企业，不需要那么多的牛人，也养不起那么多的牛人。除非有非常牛的领导，否则一堆牛人在一起可能只会做出烂事。而且牛人们要做牛的项目，否则没有满足感，会离职的。我就遇到过一个毕业生，觉得自己牛，要做“高并发，高访问量”的程序，才来几天就走了。所以如果你被招聘方拒绝了，也许是因为你太优秀了。 招聘的效率太低了。每次发出招聘启事，都可以收到大量的，不对，是巨量的简历。尽管人力资源部的同事们已经依据其它条件过滤掉了大量不合格简历，仍有数十倍于目标招聘人数的简历到我这里来。经过精心过滤后，去掉近四分之三的简历后，剩下四分之一的要面试的人还是很多。假如要招聘2个人，人力资源部的人过滤后剩100人，再过滤后剩20人面试，只有4人能通过，2人薪资谈不拢，只有2人留下，一年后可能有一人离职。招聘就是这样低效率。 因此，我很希望能招聘到能安心工作的程序员。如果一个程序员的简历里，工作时间不长，却去过很多公司，每家都工作时间不长，那我一定不要他；相反，如果有人能在一家公司里安心做过很多年，那我一定要给他个面试机会 面对众多的简历，我到底要面试那些人呢？我一般是按以下步骤筛选的： 先去掉不满足硬性条件的，比如薪资要求过高，学历过低，工作经验太少。 去掉一看就觉得不想要的，比如跳槽频繁的，经历过于复杂的，一看就狗屁不通的。 挑出一看就喜欢的，比如项目经历很符合我的要求，简历中有闪光点的。 去掉平庸的简历。 最后从剩下的简历中选出几个较好的凑数。 所以，为了以后简历好点，要慎重对待现在的工作，不要给以后的简历留下污点。然后努力在自己平日的工作中寻找闪光点，计入将来的简历。如果没有污点，也没有闪光点，那就要让自己的简历不平庸。什么样的简历是平庸的？冗长而空洞，短小而无物。简单说，简历的目的是要让招聘者看了后想应聘你，而不能说明为什么人家要录用你的简历，不论多长多短多夸张多好看，都是空洞无物的。如何让招聘者想录用你？首先，要体现你渴望得到这份工作；其次，要说明你如何能胜任这份工作。要做到这两点，就要重视每一次应聘，最好对你要应聘的公司做事前的了解，为要应聘的职位定制简历。一份简历，巨量投放，随叫随到，即时发挥，成功率肯定很低，失败多次后就没有底气，越来越不行。我看了大量的简历，把以前做的项目的模块功能罗列了一番，对自己在项目做过什么，得到什么，有什么想法，寥寥数语，甚至只字不提，这样的简历如何能让我了解你做过什么，能做什么，想做什么？我又如何敢录用你？ 我真希望每位应聘者都能认真对待自己的工作和简历，那样无论是应聘者还是招聘者都会方便很多。]]></description>
			<content:encoded><![CDATA[<p>这已经不是第一次招聘程序员了，每一次都很痛苦。以前只知道找工作不容易，现在发现招工也不容易。招聘就像找对象一样，明明满世界的男人女人，就是找不到你合适的人。<br/><br />
合适的人不是牛人，对于我们这样一个不算太有钱的普通电子商务私营企业，不需要那么多的牛人，也养不起那么多的牛人。除非有非常牛的领导，否则一堆牛人在一起可能只会做出烂事。而且牛人们要做牛的项目，否则没有满足感，会离职的。我就遇到过一个毕业生，觉得自己牛，要做“高并发，高访问量”的程序，才来几天就走了。所以如果你被招聘方拒绝了，也许是因为你太优秀了。<br/><br />
招聘的效率太低了。每次发出招聘启事，都可以收到大量的，不对，是巨量的简历。尽管人力资源部的同事们已经依据其它条件过滤掉了大量不合格简历，仍有数十倍于目标招聘人数的简历到我这里来。经过精心过滤后，去掉近四分之三的简历后，剩下四分之一的要面试的人还是很多。假如要招聘2个人，人力资源部的人过滤后剩100人，再过滤后剩20人面试，只有4人能通过，2人薪资谈不拢，只有2人留下，一年后可能有一人离职。招聘就是这样低效率。<br/><br />
因此，我很希望能招聘到能安心工作的程序员。如果一个程序员的简历里，工作时间不长，却去过很多公司，每家都工作时间不长，那我一定不要他；相反，如果有人能在一家公司里安心做过很多年，那我一定要给他个面试机会<br/><br />
面对众多的简历，我到底要面试那些人呢？我一般是按以下步骤筛选的：</p>
<ol>
<li>先去掉不满足硬性条件的，比如薪资要求过高，学历过低，工作经验太少。</li>
<li>去掉一看就觉得不想要的，比如跳槽频繁的，经历过于复杂的，一看就狗屁不通的。</li>
<li>挑出一看就喜欢的，比如项目经历很符合我的要求，简历中有闪光点的。</li>
<li>去掉平庸的简历。</li>
<li>最后从剩下的简历中选出几个较好的凑数。</li>
</ol>
<p><br/><br />
所以，为了以后简历好点，要慎重对待现在的工作，不要给以后的简历留下污点。然后努力在自己平日的工作中寻找闪光点，计入将来的简历。如果没有污点，也没有闪光点，那就要让自己的简历不平庸。什么样的简历是平庸的？冗长而空洞，短小而无物。简单说，简历的目的是要让招聘者看了后想应聘你，而不能说明为什么人家要录用你的简历，不论多长多短多夸张多好看，都是空洞无物的。如何让招聘者想录用你？首先，要体现你渴望得到这份工作；其次，要说明你如何能胜任这份工作。要做到这两点，就要重视每一次应聘，最好对你要应聘的公司做事前的了解，为要应聘的职位定制简历。一份简历，巨量投放，随叫随到，即时发挥，成功率肯定很低，失败多次后就没有底气，越来越不行。我看了大量的简历，把以前做的项目的模块功能罗列了一番，对自己在项目做过什么，得到什么，有什么想法，寥寥数语，甚至只字不提，这样的简历如何能让我了解你做过什么，能做什么，想做什么？我又如何敢录用你？<br/><br />
我真希望每位应聘者都能认真对待自己的工作和简历，那样无论是应聘者还是招聘者都会方便很多。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/345/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>JAXB中如何利用继承生成XML</title>
		<link>http://www.sulong.info/archives/326</link>
		<comments>http://www.sulong.info/archives/326#comments</comments>
		<pubDate>Sat, 14 Nov 2009 13:39:32 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[jaxb]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=326</guid>
		<description><![CDATA[问题 JAXB是我用过的java处理XML的方法中做方便的一个，在jaxb中如何使用类的集成关系有一个小小的需要注意的地方。看下面的两端XML。 XML 示例1： &#60;a&#62; &#160; &#160; &#60;b&#62;&#60;/b&#62; &#160; &#160; &#60;c&#62;&#60;/c&#62; &#60;a&#62; XML示例2： &#60;a&#62; &#160; &#160; &#60;b&#62;&#60;/b&#62; &#160; &#160; &#60;d&#62;&#60;/d&#62; &#60;a&#62; 这两段XML的唯一差别就在c元素与d元素。为了生成这两个XML，有几种方案。 方案一 不利用类的继承来重用代码，写两套Java代码, 如： @XmlRootElement&#40;name = a&#41; public class A &#123; &#160; &#160; B b; &#160; &#160; C c: &#125; @XmlRootElement&#40;name = a&#41; public class A2 &#123; &#160; &#160; B b; &#160; &#160; D [...]]]></description>
			<content:encoded><![CDATA[<h3>问题</h3>
<p>JAXB是我用过的java处理XML的方法中做方便的一个，在jaxb中如何使用类的集成关系有一个小小的需要注意的地方。看下面的两端XML。<br />
XML 示例1：</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;b<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/b<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;c<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/c<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
</pre>
<p>XML示例2：</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;b<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/b<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;d<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/d<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
</pre>
<p>这两段XML的唯一差别就在c元素与d元素。为了生成这两个XML，有几种方案。</p>
<h3>方案一</h3>
<p>不利用类的继承来重用代码，写两套Java代码, 如：</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@XmlRootElement<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> a<span style="color: #009900;">&#41;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> A <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; B b<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; C c<span style="color: #339933;">:</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
@XmlRootElement<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> a<span style="color: #009900;">&#41;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> A2 <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; B b<span style="color: #339933;">;</span><br />
&nbsp; &nbsp; D d<span style="color: #339933;">:</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> B <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> D <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span></div></div>
</pre>
<p>这一方案不是我们想要的，虽然可以解决问题，但是不能重用两个XML中共有的结构。</p>
<h3>方案二</h3>
<p>利用一个父类表示两个XML之间的共同的结构，用两个子类扩展这个父类，分别添加 C 和 D 元素。<br />
代码如下：</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@XmlRootElement<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;a&quot;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> A <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; B b<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> B <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> C <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> D <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> E <span style="color: #000000; font-weight: bold;">extends</span> A <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; C c<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> F <span style="color: #000000; font-weight: bold;">extends</span> A <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; D d<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span></div></div>
</pre>
<p>这一方案看似很直观，但是实践中却发现 E 和 F 却都只能生成 父类的 部分，如下的XML：</p>
<pre>
<div class="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap"><span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;b<span style="color: #000000; font-weight: bold;">&gt;</span></span><span style="color: #000000; font-weight: bold;">&lt;/b<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
<span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;a<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
</pre>
<p>即使把 @XmlRootElement(name = &#8220;a&#8221;) 移到 E 和 F类上也行不通。</p>
<h3>方案三</h3>
<p>用一个类代表共同的结构，用一个父类代表C和D元素，在用两个类代表具体化的C和D类，如：</p>
<pre>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@XmlRootEelemnt<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;a&quot;</span><span style="color: #009900;">&#41;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> A <span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; B b<span style="color: #339933;">;</span><br />
<br />
&nbsp; &nbsp; @XmlElements<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#123;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; @XmlElement<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;c&quot;</span>, type<span style="color: #339933;">=</span>C.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span>,<br />
&nbsp; &nbsp; &nbsp; &nbsp; @XmlElement<span style="color: #009900;">&#40;</span>name <span style="color: #339933;">=</span> <span style="color: #0000ff;">&quot;d&quot;</span>, type<span style="color: #339933;">=</span>D.<span style="color: #000000; font-weight: bold;">class</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; <span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><br />
&nbsp; &nbsp; E e<span style="color: #339933;">;</span><br />
<span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> B <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> E <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> C <span style="color: #000000; font-weight: bold;">extends</span> E <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span><br />
<span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000000; font-weight: bold;">class</span> D <span style="color: #000000; font-weight: bold;">extends</span> E <span style="color: #009900;">&#123;</span><span style="color: #009900;">&#125;</span></div></div>
</pre>
<p>这样做才最终达到目的。关键点就是@XmlElements的使用。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/326/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>web服务器集群</title>
		<link>http://www.sulong.info/archives/312</link>
		<comments>http://www.sulong.info/archives/312#comments</comments>
		<pubDate>Mon, 03 Aug 2009 06:34:04 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[理论]]></category>
		<category><![CDATA[经验]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=312</guid>
		<description><![CDATA[什么是集群 计算机集群（以下简称集群）在维基百科上被定义为一组相互连接的计算机，紧密的工作在一起，以至于在很多方面看来，它们都像是一台机器。 集群的好处 集群可能能给我们带来很多好处，其中负载均衡(loadbalance)和故障恢复(failover)一般是最常用的。负载均衡是将系统的负载分派到集群内不同的计算机上，让每个节点都不至于太忙或太闲，通过增加集群中计算机的数量，可以提升整体的负载能力。故障恢复是指在集群中某个节点发生故障时，其它的节点代替它们继续工作，这样整个系统依旧能对外提供服务。 web服务器集群的特点 对于web服务器来说，集群就是让一组计算机对外像一台web服务器一样运行。web服务器的特点是它通过http协议与客户端交互，而http协议的工作机制是请求响应模式的。web服务器的集群要能把客户端的http请求发送到集群内各个节点上，实现loadbalance，并能探测到各节点的工作情况，在某个节点失效的时候，不再把http请求发送到该节点上。 有状态与无状态 web程序本身是否有状态对实现集群的方法和难以度有很大的影响。如果web程序和客户端交互的记录下了一些状态信息，并在处理之后的请求时需要知道这样的信息，那么这个程序就是有状态的。比如，登录功能，当用户正确登录后，web程序会记录下用户的登录状态，当用户访问其它的页面时，web程序会参照用户的登录信息做不同的处理。在实现集群的时候，有状态的程序要复杂些，因为必须保证处理请求的节点上能有该用户的状态信息。对于无状态的程序，则没有这个问题，请求被分发到任何节点都是一样的，没有额外的维护状态的工作。 为了保证处理请求的节点上能有状态信息，要么在多个节点上复制程序的状态，要么采用否种策略保证将请求正确的发送到具有相应状态的节点上。如上面的例子，要么把用户登录的信息复制到集群的所有节点上，以保证无论之后请求发送到哪个节点上，都能够找得到登录信息，要么每次都把这个用户的请求发送到同一个节点上，就像mod_jk的sticky_session那样。 多线程与多进程 php,ruby,python等脚本语言往往采用无状态的结构，而java往往采用有状态的结构。并非语言决定了它们的工作方式，更多的是一种习惯。 java web服务在运行时是一个常驻内存的进程，用不同的线程处理用户请求。当处理一个http请求的线程结束后，保留在该进程内的信息并没有消失，因为进程还在。因此，可以很方便的把一些交互信息放到java进程的内存中，在多个线程间共享。在加上又有好用的HttpSession类，这样在java ee里把用户信息保存到session中，是一件非常容易的事，程序员们也自然的就采用的，导致了java web程序成了有状态的。如果完全不用session等，java web程序也能做到无状态。 和java的单进程，多线程工作方式不同，php等脚本语言采用了多进程的工作方式。当有一个http请求到来时，web服务器开启一个新的进程，这个进程调用脚本语言的解释器来运行脚本处理请求，处理结束后进程退出。如果要在多个进程间共享信息，就得采用外部的介质，DB就成了最好的选择。 本质上来说，只要需要记录会话的状态，就肯定有状态，差别只是把状态放到什么地方。java ee里往往把它放到应用程序的内存里，而php等则往往放到db里。]]></description>
			<content:encoded><![CDATA[<h3>什么是集群</h3>
<p><a href="http://en.wikipedia.org/wiki/Cluster_%28computing%29">计算机集群</a>（以下简称集群）在维基百科上被定义为一组相互连接的计算机，紧密的工作在一起，以至于在很多方面看来，它们都像是一台机器。</p>
<h3>集群的好处</h3>
<p>集群可能能给我们带来很多好处，其中负载均衡(loadbalance)和故障恢复(failover)一般是最常用的。负载均衡是将系统的负载分派到集群内不同的计算机上，让每个节点都不至于太忙或太闲，通过增加集群中计算机的数量，可以提升整体的负载能力。故障恢复是指在集群中某个节点发生故障时，其它的节点代替它们继续工作，这样整个系统依旧能对外提供服务。</p>
<h3>web服务器集群的特点</h3>
<p>对于web服务器来说，集群就是让一组计算机对外像一台web服务器一样运行。web服务器的特点是它通过http协议与客户端交互，而http协议的工作机制是请求响应模式的。web服务器的集群要能把客户端的http请求发送到集群内各个节点上，实现loadbalance，并能探测到各节点的工作情况，在某个节点失效的时候，不再把http请求发送到该节点上。</p>
<h3>有状态与无状态</h3>
<p>web程序本身是否有状态对实现集群的方法和难以度有很大的影响。如果web程序和客户端交互的记录下了一些状态信息，并在处理之后的请求时需要知道这样的信息，那么这个程序就是有状态的。比如，登录功能，当用户正确登录后，web程序会记录下用户的登录状态，当用户访问其它的页面时，web程序会参照用户的登录信息做不同的处理。在实现集群的时候，有状态的程序要复杂些，因为必须保证处理请求的节点上能有该用户的状态信息。对于无状态的程序，则没有这个问题，请求被分发到任何节点都是一样的，没有额外的维护状态的工作。</p>
<p>为了保证处理请求的节点上能有状态信息，要么在多个节点上复制程序的状态，要么采用否种策略保证将请求正确的发送到具有相应状态的节点上。如上面的例子，要么把用户登录的信息复制到集群的所有节点上，以保证无论之后请求发送到哪个节点上，都能够找得到登录信息，要么每次都把这个用户的请求发送到同一个节点上，就像mod_jk的sticky_session那样。</p>
<h3>多线程与多进程</h3>
<p>php,ruby,python等脚本语言往往采用无状态的结构，而java往往采用有状态的结构。并非语言决定了它们的工作方式，更多的是一种习惯。</p>
<p>java web服务在运行时是一个常驻内存的进程，用不同的线程处理用户请求。当处理一个http请求的线程结束后，保留在该进程内的信息并没有消失，因为进程还在。因此，可以很方便的把一些交互信息放到java进程的内存中，在多个线程间共享。在加上又有好用的HttpSession类，这样在java ee里把用户信息保存到session中，是一件非常容易的事，程序员们也自然的就采用的，导致了java web程序成了有状态的。如果完全不用session等，java web程序也能做到无状态。</p>
<p>和java的单进程，多线程工作方式不同，php等脚本语言采用了多进程的工作方式。当有一个http请求到来时，web服务器开启一个新的进程，这个进程调用脚本语言的解释器来运行脚本处理请求，处理结束后进程退出。如果要在多个进程间共享信息，就得采用外部的介质，DB就成了最好的选择。</p>
<p>本质上来说，只要需要记录会话的状态，就肯定有状态，差别只是把状态放到什么地方。java ee里往往把它放到应用程序的内存里，而php等则往往放到db里。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/312/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>TemplateServlet的局限性</title>
		<link>http://www.sulong.info/archives/299</link>
		<comments>http://www.sulong.info/archives/299#comments</comments>
		<pubDate>Fri, 10 Jul 2009 09:38:09 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[程序]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[groovy]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=299</guid>
		<description><![CDATA[我想利用TemplateServlet，像使用php那样使用groovy。只要设置好了，就可以在web目录下写gsp文件，就像写php那样，即时写即时看到效果。 但是我错了，目前的TemplateServlet非常简陋，远不能达到要求。问题主要发生在include功能。php的inclue require等功能，可以把页面变成方法库，或类库，但是在TemplateServlet的gsp里不行。我无法访问被包含的页面里的方法，闭包等。想想也很自然，每个gsp文件都有自己的名称空间。 另外，不能在gsp里定义类，这个太伤了～～～ 如果能解决以上两个问题，TemplateServlet就可以让groovy像php那样使用了。唉，那些做grails的家伙真的应该先把这块搞好，再搞重量级的东西，毕竟不是所有人都想用spring　hibernate的。 看了看gails的roadmap，今年9月的1.2版本里将有standalone gsp module，那是真正的gsp，而不是现在的简单的TemplateServlet。Grails里的gsp支持页面片段和非常方便的自定义标签，前者便于共享页面展示，后者便于共享页面行为，那么处理页面的是什么呢？还要写controller吗？到时候看吧，还是很令人期待的。]]></description>
			<content:encoded><![CDATA[<p>我想利用TemplateServlet，像使用php那样使用groovy。只要设置好了，就可以在web目录下写gsp文件，就像写php那样，即时写即时看到效果。</p>
<p>但是我错了，目前的TemplateServlet非常简陋，远不能达到要求。问题主要发生在include功能。php的inclue require等功能，可以把页面变成方法库，或类库，但是在TemplateServlet的gsp里不行。我无法访问被包含的页面里的方法，闭包等。想想也很自然，每个gsp文件都有自己的名称空间。</p>
<p>另外，不能在gsp里定义类，这个太伤了～～～</p>
<p>如果能解决以上两个问题，TemplateServlet就可以让groovy像php那样使用了。唉，那些做grails的家伙真的应该先把这块搞好，再搞重量级的东西，毕竟不是所有人都想用spring　hibernate的。</p>
<p>看了看gails的roadmap，今年9月的1.2版本里将有standalone gsp module，那是真正的gsp，而不是现在的简单的TemplateServlet。Grails里的gsp支持页面片段和非常方便的自定义标签，前者便于共享页面展示，后者便于共享页面行为，那么处理页面的是什么呢？还要写controller吗？到时候看吧，还是很令人期待的。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/299/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IO和性能</title>
		<link>http://www.sulong.info/archives/232</link>
		<comments>http://www.sulong.info/archives/232#comments</comments>
		<pubDate>Fri, 03 Jul 2009 08:16:03 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[理论]]></category>
		<category><![CDATA[程序]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[IO]]></category>
		<category><![CDATA[性能]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=232</guid>
		<description><![CDATA[最近几天看了几家互联网公司的和架构有关的PPT，有支付宝，linkedin，douban等。这些公司所使用的具体的技术有差别，但是为了能做到支持大规模访问，他们都在与缓慢的IO做斗争！ 比如说豆瓣网的历次架构变迁，不是因为磁盘IO成为瓶颈，就是因为网络IO成为瓶颈。如果能把IO的问题解决掉，那么对于互联网企业来说，性能问题就解决掉一半了，我想。 与飞速的CPU和内存相比，磁盘和网络的IO慢如蜗牛，这是问题的根源。如果没有大规模廉价而又足够快的存储方案出现的话，这个问题还将继续下去。我们只能期待这一革命性的技术出现来从根本上解决这一问题吧！ 那对于现在的我们该怎么办呢？大家的想法可能都是一样的，一是加快IO速度，二是避免不必要的IO。豆瓣曾经通过购买更高性能的硬盘来解决这个问题，如果想要更好的效果，需要投入更多的资金来购买整套的高性能存储方案，但是这成本太高了，很多公司后来都会放弃。于是大部分公司都会极力采用后者，就是避免不必要的IO，缓存就是用来做这样的事的。 将低速介质上的数据放到高速介质上，访问者先访问高速介质，在找不到需要数据时才访问低速介质，以此来提升访问数据的速度，这样的技术就是缓存了。设在一段时间内有m次没有命中缓存，n次命中，而访问一次缓存的时间是t1， 访问慢速介质的时间是t2，那么为了是缓存有效就得满足不等式： m * (t1 + t2) + n * t1 < (m + n) * t2， 于是有 m / n < t2 / t1 -1 。由此可见，在介质的速度比一定的情况下，命中比率要高于一定的值，缓存才有效果。提高命中比率，就是要把那些最常用的数据放到缓存里。另一方面，缓存里数据如果被修改了，就要同步到低速存储介质中，同样的，如果低速存储介质的数据被修改了，也要同步到缓存里。如果加上同步的开销，就需要更高的命中率。提高命中率和保证数据的同步，是使用缓存的两个艰巨的任务。 豆瓣网使用memcache，还使用专门的nigix服务器来提供图片的服务，其实也是cache。linkedin则使用了数十台大内存的服务器作为缓存服务器，运行着用c++写的专门的缓存程序。可见这些网站在使用缓存方面都是不遗余力呀。如果能把缓存用好，那么就把一大半的IO问题解决掉了。 IO往往会成为程序的瓶颈，因此，程序员应当时刻的注意，你写的代码是否在进行IO操作，是否可以减少IO操作，等等。]]></description>
			<content:encoded><![CDATA[<p>最近几天看了几家互联网公司的和架构有关的PPT，有支付宝，linkedin，douban等。这些公司所使用的具体的技术有差别，但是为了能做到支持大规模访问，他们都在与缓慢的IO做斗争！ 比如说豆瓣网的历次架构变迁，不是因为磁盘IO成为瓶颈，就是因为网络IO成为瓶颈。如果能把IO的问题解决掉，那么对于互联网企业来说，性能问题就解决掉一半了，我想。</p>
<p>与飞速的CPU和内存相比，磁盘和网络的IO慢如蜗牛，这是问题的根源。如果没有大规模廉价而又足够快的存储方案出现的话，这个问题还将继续下去。我们只能期待这一革命性的技术出现来从根本上解决这一问题吧！</p>
<p>那对于现在的我们该怎么办呢？大家的想法可能都是一样的，一是加快IO速度，二是避免不必要的IO。豆瓣曾经通过购买更高性能的硬盘来解决这个问题，如果想要更好的效果，需要投入更多的资金来购买整套的高性能存储方案，但是这成本太高了，很多公司后来都会放弃。于是大部分公司都会极力采用后者，就是避免不必要的IO，缓存就是用来做这样的事的。</p>
<p>将低速介质上的数据放到高速介质上，访问者先访问高速介质，在找不到需要数据时才访问低速介质，以此来提升访问数据的速度，这样的技术就是缓存了。设在一段时间内有m次没有命中缓存，n次命中，而访问一次缓存的时间是t1， 访问慢速介质的时间是t2，那么为了是缓存有效就得满足不等式： m * (t1 + t2) + n * t1 < (m + n) * t2， 于是有 m / n < t2 / t1 -1 。由此可见，在介质的速度比一定的情况下，命中比率要高于一定的值，缓存才有效果。提高命中比率，就是要把那些最常用的数据放到缓存里。另一方面，缓存里数据如果被修改了，就要同步到低速存储介质中，同样的，如果低速存储介质的数据被修改了，也要同步到缓存里。如果加上同步的开销，就需要更高的命中率。提高命中率和保证数据的同步，是使用缓存的两个艰巨的任务。</p>
<p>豆瓣网使用memcache，还使用专门的nigix服务器来提供图片的服务，其实也是cache。linkedin则使用了数十台大内存的服务器作为缓存服务器，运行着用c++写的专门的缓存程序。可见这些网站在使用缓存方面都是不遗余力呀。如果能把缓存用好，那么就把一大半的IO问题解决掉了。</p>
<p>IO往往会成为程序的瓶颈，因此，程序员应当时刻的注意，你写的代码是否在进行IO操作，是否可以减少IO操作，等等。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/232/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>企业应用与游戏开发的差别</title>
		<link>http://www.sulong.info/archives/234</link>
		<comments>http://www.sulong.info/archives/234#comments</comments>
		<pubDate>Wed, 01 Jul 2009 06:24:47 +0000</pubDate>
		<dc:creator>wuwei</dc:creator>
				<category><![CDATA[程序]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[思考]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=234</guid>
		<description><![CDATA[两个领域完全不一样,包括关注点,技术,运营等..我总结了一下: 1. 企业应用有很多功能属于增删改查的类型.有的是单表操作,有的是多表的JOIN,有的可能需要些逻辑判断,但大致的基本思路是这样,一个企业应用大约逃离不出这些结构.游戏不同.没有增删改查,没有任何的模式套路!做企业应用的思路和做游戏的思路完全不同.我们部门曾经单独为游戏的后台做了机器人脚本,能自动创建对游戏的表的管理功能,而游戏的后台管理功能大体与企业应用类似,这样想来可能企业应用还是有套路可循的. 2.二者的关注点不同.企业应用关注的是功能能否实现,模块,代码写的是否秀雅,当然游戏的开发也肯定关注这个,但游戏更要关注:性能,画面和可玩性&#8230;性能包括游戏的响应速度,能否支撑玩家的巨大的并发量 等.画面也非常重要,一个好的游戏能让人有赏心悦目的感觉.同样可玩性也要挖掘出来.要让玩家玩的爽,有能从中盈利,难度比较高呢&#8230; 3.代码编写的方式不同.企业应用的思路大多可以想到.比如页面列表显示,无法是取数据,然后转换成一个VIEW在页面上显示出来.而游戏呢,逻辑性之复杂令人瞠目.这里不多说了.可能一个简单的功能,需要上千行代码&#8230;还有一系列的算法等等,同时还要考虑到编写代码后游戏的运行速度和性能&#8230; 4.做企业应用很多人习惯用模型的方式设计数据库,比如一个表代码一个对象等.这样会产生可能一个查询有涉及到5张表之多.游戏呢?一个月就会有50万条记录,如何JOIN?JOIN一次要让你必须在1秒内响应,并且线上还有1000个玩家在玩,你能行吗?不行!尽量少JOIN表,这是提高数据库效率的一个非常好的方法. 5.多用缓存.不多说了,优势是:1减少访问数据库的时间和数据库的压力 2.提高请求响应速度.等等&#8230; 还有很多&#8230;呵呵]]></description>
			<content:encoded><![CDATA[<p>两个领域完全不一样,包括关注点,技术,运营等..我总结了一下:</p>
<p>1. 企业应用有很多功能属于增删改查的类型.有的是单表操作,有的是多表的JOIN,有的可能需要些逻辑判断,但大致的基本思路是这样,一个企业应用大约逃离不出这些结构.游戏不同.没有增删改查,没有任何的模式套路!做企业应用的思路和做游戏的思路完全不同.我们部门曾经单独为游戏的后台做了机器人脚本,能自动创建对游戏的表的管理功能,而游戏的后台管理功能大体与企业应用类似,这样想来可能企业应用还是有套路可循的.</p>
<p>2.二者的关注点不同.企业应用关注的是功能能否实现,模块,代码写的是否秀雅,当然游戏的开发也肯定关注这个,但游戏更要关注:性能,画面和可玩性&#8230;性能包括游戏的响应速度,能否支撑玩家的巨大的并发量 等.画面也非常重要,一个好的游戏能让人有赏心悦目的感觉.同样可玩性也要挖掘出来.要让玩家玩的爽,有能从中盈利,难度比较高呢&#8230;</p>
<p>3.代码编写的方式不同.企业应用的思路大多可以想到.比如页面列表显示,无法是取数据,然后转换成一个VIEW在页面上显示出来.而游戏呢,逻辑性之复杂令人瞠目.这里不多说了.可能一个简单的功能,需要上千行代码&#8230;还有一系列的算法等等,同时还要考虑到编写代码后游戏的运行速度和性能&#8230;</p>
<p>4.做企业应用很多人习惯用模型的方式设计数据库,比如一个表代码一个对象等.这样会产生可能一个查询有涉及到5张表之多.游戏呢?一个月就会有50万条记录,如何JOIN?JOIN一次要让你必须在1秒内响应,并且线上还有1000个玩家在玩,你能行吗?不行!尽量少JOIN表,这是提高数据库效率的一个非常好的方法.</p>
<p>5.多用缓存.不多说了,优势是:1减少访问数据库的时间和数据库的压力 2.提高请求响应速度.等等&#8230;</p>
<p>还有很多&#8230;呵呵</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/234/feed</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>个人对开发WEB游戏的总结</title>
		<link>http://www.sulong.info/archives/211</link>
		<comments>http://www.sulong.info/archives/211#comments</comments>
		<pubDate>Wed, 24 Jun 2009 09:38:59 +0000</pubDate>
		<dc:creator>wuwei</dc:creator>
				<category><![CDATA[程序]]></category>
		<category><![CDATA[经验]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=211</guid>
		<description><![CDATA[很多人以为WEB游戏的样子就类似开心网,很简单,主要是大家互动.但其实不是这样的. 开心网的WEB游戏比如种菜,大家觉得画面很精美,其实主要是前段采用了FLASH作为页面的展示,而FLASH有优势也有劣势.画面精良,与服务端数据通讯少(只需要提供必要的数据就可以了)是他的强项.当然他也有很大的缺陷,那就是第一次加载SWF文件很慢.不过因为开心网的这个SWF游戏本身比较小,所以并不能体现出他的劣势,这可能只有开心网这个平台才可以这么做,而很多网页游戏(FALSH版本)光下载SWF(第一次)就需要几M的容量,加上后续还需要下载地图&#8230;这不得不感叹有客户端游戏的极大优势啊&#8230; 我们的游戏没有采用FALSH方式,当然也有团队对FLASH的SOCKET通讯方式不熟悉,也有FALSH下载量太大导致服务器流量与并发量吃紧有关.我们采用的是javascript.用了很多扩展包,比如propotype,dwr(ajax),以及JS的特效包.页面采用的是WEB2.0(CSS+DIV)方式.其实效果也是很好的.这里不得不说一下DWR了.速度快,只刷新局部页面是他的最大优势.普通的WEB请求需要请求图片,js,html等等,花费的请求时间与数据下载量巨大.一个JS小的到50毫秒,大的到500毫秒不等.而不起眼的小图片,竟然也会吞噬你20毫秒的时间,而这些请求一累计,请求时间花费无数&#8230;这个时候DWR就发挥出他的威力了,他只有一个请求(只有一个!)在这个游戏里最大的数据库消耗功能(排名统计)也仅仅用了800毫秒,而这个功能竟然包括了数据库的一张表(几万数据量)的 1select,2count,3where 等3次查询,性能之高可想而知. 这里大家可以看出来,WEB游戏除了画面之外,重要的是什么?性能.基本上我们游戏5万个会员,在线人数保持在500人左右(并发量).这可不同于普通网站的在线人数哦.因为普通网站一般访问一下要过好久然后再次请求,没有狂刷页面的.而游戏是实时互动的.一个用户可能一秒就要来一个请求,服务器的压力之大可想而知&#8230;有人说,加大服务器配置嘛,这句有点偏颇.其实是,要先从软件的角度优化性能.比如不必要的数据库查询(大约占性能的30%),比需要的网络请求下载(30%),数据的缓存(20%)以及其他的一些优化.需要综合&#8230;这样的结果就是,我们用3台服务器(1个MYSQL,2台应用)撑起了整个游戏环境(应用服务器还是TOMCAT集群的哦!) 开服只1个月,数据库量大到什么程度?一张表竟然有100万条记录了&#8230;这时候怎么办呢?目前比较好的想法是用年月的方式作为表的名称,但这个就与hibernate的动态映射有关了,网上搜了一下有这个技术,但目前还没用.只能用定时删除历史的方式来实现了..呵呵 做游戏,重要的是你要时刻考虑:性能,游戏的效率,游戏的可玩性.如果你觉得这个功能好玩,就要吧他做到最好,既好玩,又速度快,又要让玩家有刺激感&#8230;很复杂啊.. 第一部分先写到这里吧,能写的太多了,这里只是一小部分.呵呵]]></description>
			<content:encoded><![CDATA[<p>很多人以为WEB游戏的样子就类似开心网,很简单,主要是大家互动.但其实不是这样的.</p>
<p>开心网的WEB游戏比如种菜,大家觉得画面很精美,其实主要是前段采用了FLASH作为页面的展示,而FLASH有优势也有劣势.画面精良,与服务端数据通讯少(只需要提供必要的数据就可以了)是他的强项.当然他也有很大的缺陷,那就是第一次加载SWF文件很慢.不过因为开心网的这个SWF游戏本身比较小,所以并不能体现出他的劣势,这可能只有开心网这个平台才可以这么做,而很多网页游戏(FALSH版本)光下载SWF(第一次)就需要几M的容量,加上后续还需要下载地图&#8230;这不得不感叹有客户端游戏的极大优势啊&#8230;</p>
<p>我们的游戏没有采用FALSH方式,当然也有团队对FLASH的SOCKET通讯方式不熟悉,也有FALSH下载量太大导致服务器流量与并发量吃紧有关.我们采用的是javascript.用了很多扩展包,比如propotype,dwr(ajax),以及JS的特效包.页面采用的是WEB2.0(CSS+DIV)方式.其实效果也是很好的.这里不得不说一下DWR了.速度快,只刷新局部页面是他的最大优势.普通的WEB请求需要请求图片,js,html等等,花费的请求时间与数据下载量巨大.一个JS小的到50毫秒,大的到500毫秒不等.而不起眼的小图片,竟然也会吞噬你20毫秒的时间,而这些请求一累计,请求时间花费无数&#8230;这个时候DWR就发挥出他的威力了,他只有一个请求(只有一个!)在这个游戏里最大的数据库消耗功能(排名统计)也仅仅用了800毫秒,而这个功能竟然包括了数据库的一张表(几万数据量)的 1select,2count,3where 等3次查询,性能之高可想而知.</p>
<p>这里大家可以看出来,WEB游戏除了画面之外,重要的是什么?性能.基本上我们游戏5万个会员,在线人数保持在500人左右(并发量).这可不同于普通网站的在线人数哦.因为普通网站一般访问一下要过好久然后再次请求,没有狂刷页面的.而游戏是实时互动的.一个用户可能一秒就要来一个请求,服务器的压力之大可想而知&#8230;有人说,加大服务器配置嘛,这句有点偏颇.其实是,要先从软件的角度优化性能.比如不必要的数据库查询(大约占性能的30%),比需要的网络请求下载(30%),数据的缓存(20%)以及其他的一些优化.需要综合&#8230;这样的结果就是,我们用3台服务器(1个MYSQL,2台应用)撑起了整个游戏环境(应用服务器还是TOMCAT集群的哦!)</p>
<p>开服只1个月,数据库量大到什么程度?一张表竟然有100万条记录了&#8230;这时候怎么办呢?目前比较好的想法是用年月的方式作为表的名称,但这个就与hibernate的动态映射有关了,网上搜了一下有这个技术,但目前还没用.只能用定时删除历史的方式来实现了..呵呵</p>
<p>做游戏,重要的是你要时刻考虑:性能,游戏的效率,游戏的可玩性.如果你觉得这个功能好玩,就要吧他做到最好,既好玩,又速度快,又要让玩家有刺激感&#8230;很复杂啊..</p>
<p>第一部分先写到这里吧,能写的太多了,这里只是一小部分.呵呵</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/211/feed</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>ActiveMQ使用经验</title>
		<link>http://www.sulong.info/archives/207</link>
		<comments>http://www.sulong.info/archives/207#comments</comments>
		<pubDate>Thu, 18 Jun 2009 09:56:41 +0000</pubDate>
		<dc:creator>sulong</dc:creator>
				<category><![CDATA[java]]></category>
		<category><![CDATA[经验]]></category>
		<category><![CDATA[jms]]></category>

		<guid isPermaLink="false">http://www.sulong.info/?p=207</guid>
		<description><![CDATA[ActiveMQ是apache的一个开源JMS服务器，不仅具备标准JMS的功能，还有很多额外的功能。公司里引入ActiveMQ后，ActiveMQ成里我们公司业务系统中最重要的一个环节。所有应用都通过jms集成，如果ActiveMQ出了故障，整个系统就瘫痪了。因此，头对ActiveMQ的性能，可靠性，以及如何正确使用，是非常的关心的，而我就被指派来做关于ActiveMQ的调研，本文对此做了些总结。 1 使用jms需要注意的问题 一下所述的问题，不仅是对ActiveMQ，对于其他的JMS也一样有效。 1.1 不要频繁的建立和关闭连接 JMS使用长连接方式，一个程序，只要和JMS服务器保持一个连接就可以了，不要频繁的建立和关闭连接。频繁的建立和关闭连接，对程序的性能影响还是很大的。这一点和jdbc还是不太一样的。 1.2 Connection的start()和stop()方法代价很高 JMS的Connection的start()和stop()方法代价很高，不能经常调用。我们试用的时候，写了个jms的connection pool，每次将connection取出pool时调用start()方法，归还时调用stop()方法，然而后来用jprofiler发现，一般的cpu时间都耗在了这两个方法上。 1.3 start()后才能收消息 Connection的start()方法调用后，才能收到jms消息。如果不调用这个方法，能发出消息，但是一直收不到消息。不知道其它的jms服务器也是这样。 1.4 显示关闭Session 如果忘记了最后关闭Connection或Session对象，都会导致内存泄漏。这个在我测试的时候也发现了。本来以为关闭了Connection，由这个Connection生成的Session也会被自动关闭，结果并非如此，Session并没有关闭，导致内存泄漏。所以一定要显示的关闭Connection和Session。 1.5 对Session做对象池 对Session做对象池，而不是Connection。Session也是昂贵的对象，每次使用都新建和关闭，代价也非常高。而且后来我们发现，原来Connection是线程安全的，而Session不是，所以后来改成了对Session做对象池，而只保留一个Connection。 2 集群 ActiveMQ有强大而灵活的集群功能，但是使用起来还是会有很多陷阱。 2.1 broker cluster和 master-slave ActiveMQ可以做broker的集群，也可以做master-slave方式的集群。前者能在多个broker之前fail-over和load-balance，但是在某个节点出故障时，可能导致消息丢失；而后者能实时备份消息，和fail-over，但是不能load-balance。broker cluser的方式，在一个broker上发送的消息可以在其它的broker上收到。当一个broker失效时，客户端可以自动的转到别的broker上运行，多个broker可以同时提供服务，但是消息只存储在一个broker上，如果那个broker失效了，那么客户端直到它重新启动后才能收到该broker上的消息，假如很不幸，那个broker的存储介质坏了，那么消息就丢失掉了。 Master-slave方式中，只有master提供服务，slave只是实时的备份master的数据，所以消息不会丢失。当master失效时，slave会自动升为master，客户端会自动转到slave上工作，所以能fail-over。由于只有master提供服务，所以不能将负载分到多个broker上。 其实单个broker的性能已经是相当的惊人了，在我们公司的机器上能达到每秒收发4000个消息，没个消息4K字节这样的速度，足够公司目前的需要了，而公司并不希望丢失任何数据，所以我们选择使用master-slave模式。 2.2 多种master-slave模式 master-slave也有多种实现方式。它们的不同只是在共享数据和锁机制上。 2.2.1 Pure master-slave Pure master-slave，显示的在配置文件中指定一个broker做为另一个broker的slave。运行时，slave同过网络自动从master出复制数据，同时在和master失去连接时自动升级为master。当master失效，slave成为master后，如果要让原先的master重新投入运行，需要停掉运行中的slave(现在升级为master了)，手动复制slave中的数据到master中。再重新启动master和slave。这种方式最简单，效率也不错，但是只能有两台做集群，只能fail-over一次，而且需要停机回复master-slave结构。 2.2.2 JDBC master-slave 这种方式不需要特殊的配置，只要让所有的节点都把数据存储到同一个数据库中。先拿到数据库表的锁的节点成为master，一旦它失效了，其它的节点获得锁，就可以成为master。因为数据通过数据库共享，放在一个地方，不需要停机恢复master-slave。这种方式，需要额外的数据库服务器，如果数据库失效了，那么就全失效了，而且速度不是很快。我们在用mysql测试时，并没有成功，master失效后，其他的节点始终没有升级成slave，可能是数据库配置的问题。 2.2.3 Share file master-slave 这种方式类似于前者，也不需要特别的配置，只是通过共享文件系统来共享数据，靠文件锁实现只有一台成为master。共享文件系统的方式有很多，我们测试了nfs v4 (v3有bug，不行)， 最终在稳定性，效率等方面不是很满意，可能是通过网络太慢了。 测试过众多master-slave模式后发现，pure方式管理起来麻烦，jdbc方式成本高，效率低，share file方式需要高性能的共享文件，都有缺点。鉴于单台activeMQ很可靠，而我们的基础平台组愿意用硬件备份，最终还是决定不用master-slave了，也不用broker cluster，就用单台，通过硬件冗余保证数据不会丢失，并找另外一台刀片机做冷备，在主服务器失效时顶替。]]></description>
			<content:encoded><![CDATA[<p>ActiveMQ是apache的一个开源JMS服务器，不仅具备标准JMS的功能，还有很多额外的功能。公司里引入ActiveMQ后，ActiveMQ成里我们公司业务系统中最重要的一个环节。所有应用都通过jms集成，如果ActiveMQ出了故障，整个系统就瘫痪了。因此，头对ActiveMQ的性能，可靠性，以及如何正确使用，是非常的关心的，而我就被指派来做关于ActiveMQ的调研，本文对此做了些总结。</p>
<h2>1 使用jms需要注意的问题</h2>
<p>一下所述的问题，不仅是对ActiveMQ，对于其他的JMS也一样有效。</p>
<h3>1.1 不要频繁的建立和关闭连接</h3>
<p>JMS使用长连接方式，一个程序，只要和JMS服务器保持一个连接就可以了，不要频繁的建立和关闭连接。频繁的建立和关闭连接，对程序的性能影响还是很大的。这一点和jdbc还是不太一样的。</p>
<h3>1.2 Connection的start()和stop()方法代价很高</h3>
<p>JMS的Connection的start()和stop()方法代价很高，不能经常调用。我们试用的时候，写了个jms的connection pool，每次将connection取出pool时调用start()方法，归还时调用stop()方法，然而后来用jprofiler发现，一般的cpu时间都耗在了这两个方法上。</p>
<h3>1.3 start()后才能收消息</h3>
<p>Connection的start()方法调用后，才能收到jms消息。如果不调用这个方法，能发出消息，但是一直收不到消息。不知道其它的jms服务器也是这样。</p>
<h3>1.4 显示关闭Session</h3>
<p>如果忘记了最后关闭Connection或Session对象，都会导致内存泄漏。这个在我测试的时候也发现了。本来以为关闭了Connection，由这个Connection生成的Session也会被自动关闭，结果并非如此，Session并没有关闭，导致内存泄漏。所以一定要显示的关闭Connection和Session。</p>
<h3>1.5 对Session做对象池</h3>
<p>对Session做对象池，而不是Connection。Session也是昂贵的对象，每次使用都新建和关闭，代价也非常高。而且后来我们发现，原来Connection是线程安全的，而Session不是，所以后来改成了对Session做对象池，而只保留一个Connection。</p>
<h2>2 集群</h2>
<p>ActiveMQ有强大而灵活的集群功能，但是使用起来还是会有很多陷阱。</p>
<h3>2.1 broker cluster和 master-slave</h3>
<p>ActiveMQ可以做broker的集群，也可以做master-slave方式的集群。前者能在多个broker之前fail-over和load-balance，但是在某个节点出故障时，可能导致消息丢失；而后者能实时备份消息，和fail-over，但是不能load-balance。broker cluser的方式，在一个broker上发送的消息可以在其它的broker上收到。当一个broker失效时，客户端可以自动的转到别的broker上运行，多个broker可以同时提供服务，但是消息只存储在一个broker上，如果那个broker失效了，那么客户端直到它重新启动后才能收到该broker上的消息，假如很不幸，那个broker的存储介质坏了，那么消息就丢失掉了。<br />
Master-slave方式中，只有master提供服务，slave只是实时的备份master的数据，所以消息不会丢失。当master失效时，slave会自动升为master，客户端会自动转到slave上工作，所以能fail-over。由于只有master提供服务，所以不能将负载分到多个broker上。<br />
其实单个broker的性能已经是相当的惊人了，在我们公司的机器上能达到每秒收发4000个消息，没个消息4K字节这样的速度，足够公司目前的需要了，而公司并不希望丢失任何数据，所以我们选择使用master-slave模式。</p>
<h3>2.2 多种master-slave模式</h3>
<p>master-slave也有多种实现方式。它们的不同只是在共享数据和锁机制上。</p>
<h4>2.2.1 Pure master-slave</h4>
<p>Pure master-slave，显示的在配置文件中指定一个broker做为另一个broker的slave。运行时，slave同过网络自动从master出复制数据，同时在和master失去连接时自动升级为master。当master失效，slave成为master后，如果要让原先的master重新投入运行，需要停掉运行中的slave(现在升级为master了)，手动复制slave中的数据到master中。再重新启动master和slave。这种方式最简单，效率也不错，但是只能有两台做集群，只能fail-over一次，而且需要停机回复master-slave结构。</p>
<h4>2.2.2 JDBC master-slave</h4>
<p>这种方式不需要特殊的配置，只要让所有的节点都把数据存储到同一个数据库中。先拿到数据库表的锁的节点成为master，一旦它失效了，其它的节点获得锁，就可以成为master。因为数据通过数据库共享，放在一个地方，不需要停机恢复master-slave。这种方式，需要额外的数据库服务器，如果数据库失效了，那么就全失效了，而且速度不是很快。我们在用mysql测试时，并没有成功，master失效后，其他的节点始终没有升级成slave，可能是数据库配置的问题。</p>
<h4>2.2.3 Share file master-slave</h4>
<p>这种方式类似于前者，也不需要特别的配置，只是通过共享文件系统来共享数据，靠文件锁实现只有一台成为master。共享文件系统的方式有很多，我们测试了nfs v4 (v3有bug，不行)， 最终在稳定性，效率等方面不是很满意，可能是通过网络太慢了。</p>
<p>测试过众多master-slave模式后发现，pure方式管理起来麻烦，jdbc方式成本高，效率低，share file方式需要高性能的共享文件，都有缺点。鉴于单台activeMQ很可靠，而我们的基础平台组愿意用硬件备份，最终还是决定不用master-slave了，也不用broker cluster，就用单台，通过硬件冗余保证数据不会丢失，并找另外一台刀片机做冷备，在主服务器失效时顶替。</p>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/207/feed</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</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[技巧]]></category>
		<category><![CDATA[经验]]></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依赖，只要在它的部署文件里填上一行，例如: &#160; &#160; &#60;server&#62; &#160; &#160; &#160; &#160; &#60;mbean name=&#34;xx&#34; code=&#34;xx.xx.xxx&#34;&#62; &#160; &#160; &#160; &#160; &#160; &#160; &#60;depends&#62;jboss.ha:service=HASingletonDeployer,type=Barrier&#60;/depends&#62; &#160; &#160; &#160; &#160; &#60;/mbean&#62; &#160; &#160; &#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="codecolorer-container xml default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="xml codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;server<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <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><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <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><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/mbean<span style="color: #000000; font-weight: bold;">&gt;</span></span></span><br />
&nbsp; &nbsp; <span style="color: #009900;"><span style="color: #000000; font-weight: bold;">&lt;/server<span style="color: #000000; font-weight: bold;">&gt;</span></span></span></div></div>
<p>对于war,jar,ear，可以在jboss.xml里添加，具体见jboss文档。对于ejb3，加上下面的annotation就好了：<br/></p>
<div class="codecolorer-container java default" style="overflow:auto;white-space:nowrap;border:1px solid #9F9F9F;width:500px;"><div class="java codecolorer" style="padding:5px;font:normal 12px/1.4em Monaco, Lucida Console, monospace;white-space:nowrap">@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></div></div>
<p><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/125/feed</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</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><a class="a2a_dd addtoany_share_save" href="http://www.addtoany.com/share_save"><img src="http://www.sulong.info/wp-content/plugins/add-to-any/share_save_171_16.gif" width="171" height="16" alt="Share/Bookmark"/></a> </p>]]></content:encoded>
			<wfw:commentRss>http://www.sulong.info/archives/97/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
