﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-心有多大舞台便有多大-随笔分类-Java</title><link>http://www.blogjava.net/jjwwhmm/category/30244.html</link><description>Embrace changes, pursue excellence, share niceness. 
</description><language>zh-cn</language><lastBuildDate>Wed, 31 Mar 2010 10:23:38 GMT</lastBuildDate><pubDate>Wed, 31 Mar 2010 10:23:38 GMT</pubDate><ttl>60</ttl><item><title>学习：Thread的setDaemon方法</title><link>http://www.blogjava.net/jjwwhmm/archive/2010/03/31/317061.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Wed, 31 Mar 2010 07:26:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2010/03/31/317061.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/317061.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2010/03/31/317061.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/317061.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/317061.html</trackback:ping><description><![CDATA[setDaemon方法把java的线程设置为守护线程，此方法的调用必须在线程启动之前执行。只有在当前jvm中所有的线程都为守护线程时，jvm才会退出。<br />
如果创建的线程没有显示调用此方法，这默认为用户线程。<br />
下面是一个示例代码：<br />
<p>public class TestThreadDaemonMethod {</p>
<p>&nbsp;/**<br />
&nbsp; * @param args<br />
&nbsp; */<br />
&nbsp;public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestThread t = new TestThread("test thread");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果设置为false,那么在执行完后面的start方法后,jvm不会退出<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.setDaemon(false);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//如果设置为true,则执行完后面的start方法后,jvm会退出<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.setDaemon(true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;t.start();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//在start之后设置daemon会抛出异常<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//t.setDaemon(true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (t.isDaemon()) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("test thread&nbsp;is a daemon.");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}<br />
}</p>
<p>class TestThread extends Thread {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;private String name;<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public TestThread(String name) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;this.name = name;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/* (non-Javadoc)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * @see java.lang.Thread#run()<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;public void run() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;while(true) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println("running " + name);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Thread.sleep(1);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;} catch (InterruptedException e) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br />
}</p>
 <img src ="http://www.blogjava.net/jjwwhmm/aggbug/317061.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2010-03-31 15:26 <a href="http://www.blogjava.net/jjwwhmm/archive/2010/03/31/317061.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>插播一条招聘广告：盛大在线招聘Java程序员</title><link>http://www.blogjava.net/jjwwhmm/archive/2010/03/31/317035.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Wed, 31 Mar 2010 05:03:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2010/03/31/317035.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/317035.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2010/03/31/317035.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/317035.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/317035.html</trackback:ping><description><![CDATA[RT，包括高级、资深Java程序员，架构师，有意的请与我联系，有金融相关行业从业经验的优先，要求除了Java知识之外，对分析设计方面有丰富的经验。
 <img src ="http://www.blogjava.net/jjwwhmm/aggbug/317035.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2010-03-31 13:03 <a href="http://www.blogjava.net/jjwwhmm/archive/2010/03/31/317035.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[ZZ]Jetty 源码分析</title><link>http://www.blogjava.net/jjwwhmm/archive/2010/03/26/316653.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Fri, 26 Mar 2010 08:49:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2010/03/26/316653.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/316653.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2010/03/26/316653.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/316653.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/316653.html</trackback:ping><description><![CDATA[<table cellspacing="0" cellpadding="3" width="760" align="center" border="0">
    <tbody>
        <tr width="100%">
            <td width="1%">
            <h3>一、 总括</h3>
            <div align="left">&nbsp; &nbsp;&nbsp;&nbsp;你了解Jetty 吗，就像我们所熟知的Tomcat一样, Jetty是一个免费的开放源码的100%纯Java的Http服务器和Servlet容器。 </div>
            </td>
            <!--开始正文-->
            <td width="98%">
            <center>
            <h4><br />
            </h4>
            </center><br />
            </td>
        </tr>
        <tr>
            <td>
            <p align="justify">&nbsp; &nbsp;&nbsp;&nbsp;Jetty具备以下特点：</p>
            </td>
        </tr>
        <tr>
            <td>
            <div align="left">&nbsp; &nbsp;&nbsp;&nbsp;快速高效 </div>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;。Jetty是最快的Servlet服务器之一</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;。Jetty可以处理上千个并发连接 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;小巧嵌入 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;。Jetty的jar只有600多K </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;。可动态嵌入到应用程序，适合开发web2.0等应用 </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;应用广泛</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;。开源项目有<a href="http://geronimo.apache.org/">Geronimo</a>, <a href="http://sourceforge.net/projects/jboss/">JBoss</a>, <a href="http://www.objectweb.org/jonas/index.html">JOnAS</a>等</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;。商业项目有IBM Tivoli, Sonic MQ and Cisco SESM等</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;可到Jetty网站<a href="http://jetty.mortbay.org/jetty/"> http://jetty.mortbay.org/jetty/</a> 查看最新信息</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;本文将通过对Jetty最新稳定版 Jetty5.1.5RC2 源码的研究，向读者展示Jetty在设计方面使用的不同设计理念, 希望对广大开发者在设计自己的系统时有所帮助。 </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;Jetty按照功能可以分为四个主个主要的部分,HttpServer, HttpContext,HttpHandler,HttpListener,详见如下类图:</p>
            </td>
        </tr>
        <tr>
            <td><img height="610" alt="" src="http://docs.huihoo.com/jetty/i/Architecture.jpg" width="726" /></td>
        </tr>
        <tr>
            <td>
            <p align="center">&lt;图 1-1&gt;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp;</p>
            </td>
        </tr>
        <tr>
            <td>
            <h3>二、HttpServer及配置</h3>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;对于初次接触Jetty的人一定会对上图感到迷惑，其实在Jetty中 HttpServer是一个服务器的核心控制类, 我们可以看到，其它的组件类都是由该类扩展开来，HttpServer的作用就是在一系列的监听器类和处理器类之间搭起了一个桥梁,有效的控制着消息在系统内的传递,如下图: </td>
        </tr>
        <tr>
            <td>
            <div align="center"><img height="55" alt="" src="http://docs.huihoo.com/jetty/i/HttpServer_Sequence.jpg" width="431" /></div>
            </td>
        </tr>
        <tr>
            <td>
            <div align="center">&lt;图 1-2 &gt; </div>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpServer职责是接受从HttpListener传递过来的request(请求),HttpServer通过对request的Host(主机)或Path(路径)进行匹配,然后分发给相应的HttpContext(可以理解为一个web application)。</td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;这里举个例子，假设我们现在要建立一个提供静态页面web服务,页面内容在c:\root \下,可以通过如此配置HttpServer: </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpServer server = new HttpServer(); // 创建一个新的HttpServer </td>
        </tr>
        <tr>
            <td height="25">&nbsp; &nbsp;&nbsp;&nbsp;SocketListener listener = new SocketListener(); // 创建一个新监听器 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;listener.setPort(8080);// 设置监听端口为8080 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.addListener(listener);// 将监听类注册到server中 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpContext context = new HttpContext(); // 创建一个新HttpContext </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context.setContextPath("/app/*"); // 设置访问路径 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context.setResourceBase("c:/root/"); // 设置静态资源路径 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context.addHandler(new ResourceHandler()); // 为这个HttpContext添加一个静态资源处理器 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.addContext(context); // 将这个HttpContext注册到server中 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.start();// 最后启动这个server </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;当我们要建立一个提供动态页面web服务时, 假设我们自己的 web 应用放在Jetty目录下的webapps下并打好包文件名为myapp.war, 可以通过如此配置HttpServer: </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;Server server = new Server(); // 创建一个新的HttpServer </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;SocketListener listener = new SocketListener();// 创建一个新监听器 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;listener.setPort(8080); // 设置监听端口为8080 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.addListener(listener ); // 将监听类注册到server中 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.addWebApplication("myapp","./webapps/myapp/"); // 将这个web应用注册到这个Server中 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.start(); // 最后启动这个server </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;短短数行代码就可创建一个web服务器并启动它,这有点类似于我们windows中的即插即用的概念,需要什么就添加什么,把这些类以HttpServer为核心组合在一起，就可以完成强大的功能。</td>
        </tr>
        <tr>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>
            <h3>三、Jetty Server</h3>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;1.上面我们探讨了HttpServer的启动,读者一定还存在这样疑问,整个Jetty 服务器是怎样启动的？ </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;首先我们可以在图 1-1 看到左下角有一个Server类,这个类实际上继承了HttpServer,当启动Jetty服务器时，具体来说，在Jetty根目录下命令行下如输入 java&nbsp;-jar&nbsp;start.jar&nbsp;etc/demo.xml，注意这里有一个配置文件 demo.xml做为运行参数,这个参数也可以是其它的配置文件,也可是多个xml配置文件，其实这个配置文件好比我们使用struts时的struts -config.xml文件，将运行Server需要用到的组件写在里面，比如上一节中HttpServer的配置需要的组件类都可以写在这个配置文件中。 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;2.我们自己部署到Jetty的webapps目录下的web application,Jetty如何运行我们自己的web application? </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;首先当我们按上述方法启动Jetty Server时,就会调用Server类里面的main方法,这个入口方法首先会构造一个Server类实例(其实也就构造了一个 HttpServer),创建实例过程中就会构造XmlConfiguration类的对象来读取参数配置文件，之后再由这个配置文件产生的 XmlConfiguration对象来配置这个Server,配置过程其实是运用Java的反射机制调用Server的方法并传入配置文件中所写的参数来向这个Server添加HttpListener,HttpContext,HttpHandler,web application(对应我们自己部署的web应用)。 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;添加我们自己的web application过程中相应的就会读取我们所熟知的/WEB-INF/web.xml来创建一个WebApplicationContext(这个类继承了HttpContext)的实例,同时也会创建WebApplicationContext自身的ServletHandler(实现了 HttpHandler接口),注意到ServletHandler中包含一组ServletHolder指向实际的Servlet,譬如说我们在 web.xml文件中配置了两个Filter和一个Servlet,这里就会有三个ServletHolder,实际处理请求时 ServeletHandler就会依次调用这三个ServletHolder传入request,response处理(实际最后交给这两个 Filter和Servlet处理),这样我们自己做好的一个 web应用就挂载到这个Server上了,可以接受客户端相应的request(请求)。 </td>
        </tr>
        <tr>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>
            <h3>四、运行原理(请参考如下时序图)</h3>
            </td>
        </tr>
        <tr>
            <td><img height="587" alt="" src="http://docs.huihoo.com/jetty/i/work_sequence.jpg" width="720" /></td>
        </tr>
        <tr>
            <td>
            <p align="center">&lt;图 1-7 &gt;</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;上图展示了一个request的处理过程,首先HttpListener监听到客户端发来的请求创建一个HttpConnection实例(封装了连接细节,比如从Socket连接中获取的输入流和输出流), HttpConnection对象构建过程中会创建Jetty内部自定义的HttpRequest和HttpResponse对象,接着 HttpListener会调用这个HttpConnection实例的handle方法, HttpConnection实例就调用HttpRequest对象的read()方法读取信息,调用HttpServer的service方法以 HttpRequest,HttpResponse为参数传给HttpServer,HttpServer又将HttpRequest和 HttpResponse分发给相应的HttpCotext,HttpContext最后将HttpRequest和HttpResponse交给自身的 HttpHandler 处理,在这里HttpRequest,HttpResponse被再次封装为ServletHttpRequest和 ServletHttpResponse,其实这两个类实现了我们所熟知的HttpServletRequest和 HttpServletResponse接口。</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>
            <h3>五、高级性能</h3>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;1.HttpHandler:</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;该接口的实现类用于处理HttpContext分发过来的reqeust,不同的实现类的有不同的处理功能,这里介绍几常用的HttpHandler实现类: </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;ReourceHandler:用于处理静态内容,如以扩展名为.html的文件 </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;SecurityHandler:提供基本的安全验证</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;ForwardHandler:转发一个request到另一个url</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;ServletHandler:用于将request交由具体的Servlet类进行处理 </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;2.当你在看图 1-2 时候会注意到HttpServer和HttpListener,HttpServer与HttpContext，HttpContext与 HttpHandler存在一对多的关系,下面就介绍一下它们之间的这种关系如何通过程序来配置. </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;HttpListener &amp; HttpServer:</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;HttpListener是所有监听器类的接口,如图中的SocketListener (基于传统的Socket技术)就实现了该接口,Jetty还有其它的实现该接口类,如SocketChannelListener(基于NIO技术)类等,HttpListener职责主要是在服务器启动后监听相应端口的来自客户端请求并建立连接(图 1-1 中所示用HttpConnection封装连接细节),监听器可在同个IP上开启多个端口为同一个HttpServer 进行监听,所以HttpListener和HttpServer是多对一的关系,如下图:</p>
            </td>
        </tr>
        <tr>
            <td>
            <div align="center"><img height="174" alt="" src="http://docs.huihoo.com/jetty/i/multi_listener.jpg" width="524" /></div>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">&lt;图 1-3 &gt;</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;配置代码：</td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpServer server = new HttpServer(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpListenrer listener1 = new SocketChanneListener(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;Listener1.setPort(8080); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp; HttpListenrer listener1 = new SocketListener(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;Listener1.setPort(8443); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.addListener(listener1); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.addListener(listener2); </td>
        </tr>
        <tr>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;HttpContext &amp; HttpHandler:</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;HttpContext相当于对应客户端请求的URL或某个虚拟机, 其子类中包含若干个HttpHandler, 当接受到request(请求)时,HttpContext会依次(按某个预定的次序)把request交给这些HttpHandler处理,直到这个 request被标示处理过为止, 需要注意的是这个request可能被多个HttpHandler处理，但只能有一个HttpHandler能标示这个request已被处理过.</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;一个典型的HttpContext有用于安全处理、静态资源处理及Servlet类的 HttpHandler,如下图: </td>
        </tr>
        <tr>
            <td>
            <div align="center"><img height="195" alt="" src="http://docs.huihoo.com/jetty/i/Typical_HttpContext.jpg" width="447" /></div>
            </td>
        </tr>
        <tr>
            <td>
            <div align="center">&lt;图 1-4&gt; </div>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;配置代码：</td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpContext context = new HttpContext(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context.setContextPath(&#8220;/myapp/*&#8221;); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpHandler securitHandler = new SecurityHandler(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpHandler resourceHandler = new ResourceHandler(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpHandler servletHandler = new ServletHandler(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context.addHandler(securitHandler); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context.addHandler(resourceHandler); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context.addHandler(servletHandler); </td>
        </tr>
        <tr>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpServer &amp; HttpContext: </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;一般的HTTP服务器软件可以同时处理多个web application,同样一个HttpServer可以包含多个HttpContext,如下图可以通过同一个端口的监听类来映射多个 HttpContext: </td>
        </tr>
        <tr>
            <td>
            <div align="center"><img height="170" alt="" src="http://docs.huihoo.com/jetty/i/one_port_multi_HttpContext.jpg" width="450" /></div>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">&lt;图 1-5 &gt;</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;配置代码：</td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpServer server = new HttpServer(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpContext context1 = new HttpContext(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context1.setContextPath(&#8220;/app1/*&#8221;); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpContext context2 = new HttpContext(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;context2.setContextPath(&#8220;/app2/*&#8221;); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server.addContext(context1); </td>
        </tr>
        <tr>
            <td>&nbsp; </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpServer &amp; HttpLister &amp; HttpContext: </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;另外Jetty对多网卡（多个IP地址,不同的主机名）的服务器也提供了很好的支持,每个 HttpContext都有自身的HttpServer:</p>
            </td>
        </tr>
        <tr>
            <td>
            <div align="center"><img alt="" src="http://docs.huihoo.com/jetty/i/multi_hosts_multi_context.jpg" /></div>
            </td>
        </tr>
        <tr>
            <td>
            <p align="center">&lt;图 1-6 &gt;</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;配置代码：</td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;HttpServer server1 = new HttpServer(); </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;SocketListener listener1 = new SocketListener(); </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;listener1.setHost(&#8220;www.app1.com&#8221;);//orListener1.setHost(&#8220;www.app2.com&#8221;)</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;listener2.setPort(80);</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;HttpContext context1 = new HttpContext();</p>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;context1.setContextPath(&#8220;/&#8221;);</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;server1.addListener(listener1); </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;server1.addContext(context1);</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp; </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;3.Jetty对高并发的支持 </td>
        </tr>
        <tr>
            <td>
            <div align="center"><img height="168" alt="" src="http://docs.huihoo.com/jetty/i/jetty_ThreadPool.jpg" width="378" /></div>
            </td>
        </tr>
        <tr>
            <td>
            <div align="center">&lt;图 1-8&gt; </div>
            </td>
        </tr>
        <tr>
            <td>&nbsp; &nbsp;&nbsp;&nbsp;如果多用户请求服务就会涉及到多线程的管理，如图 1-8,Jetty中主要由ThreadPool负责管理多线程，注意其中Pool.PondLife是Pool的一个内部接口, ThreadPool.PoolThread是ThreadPool的一个内部线程类,我们看到Pool.PondLife和Pool存在一个聚集的关系，实际上Pool对象中存放在是一个个ThreadPool.PoolThread线程对象，当有新用户连接上Server时，ThreadPool就从Pool中取一个空闲的线程为当前用户连接服务。 </td>
        </tr>
        <tr>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>
            <h3>六、小结</h3>
            </td>
        </tr>
        <tr>
            <td>
            <p>&nbsp; &nbsp;&nbsp;&nbsp;本文通过图示简要介绍了Jetty整个体系架构和主要的组件类及服务器的启动执行过程,其实Jetty 通常被用来做为内嵌的Web Server来使用，一些常见的服务器软件，如Apache Cocoon、JBoss ,JOnAs等都会采用Jetty作为Web解決方案；另外由于Jetty在性能及稳定性要优于同类HTTP Server的原因，Jetty已在国外已很流行,鉴于这一点,本文作者可以预测在不久的将来Jetty同样也会在国内流行开来。</p>
            </td>
        </tr>
        <tr>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td>附：</td>
        </tr>
        <tr>
            <td>来源：http://blog.leiling.com/CALM/archive/2005/12/23/106662.aspx <br />
            作者联系方式：陈应刚 <a href="&#109;&#97;&#105;&#108;&#116;&#111;&#58;&#100;&#121;&#99;&#121;&#103;&#64;&#121;&#97;&#104;&#111;&#111;&#46;&#99;&#111;&#109;">dycyg@yahoo.com</a> 熊红阳 <a =""><br />
            </a></td>
        </tr>
    </tbody>
</table>
 <img src ="http://www.blogjava.net/jjwwhmm/aggbug/316653.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2010-03-26 16:49 <a href="http://www.blogjava.net/jjwwhmm/archive/2010/03/26/316653.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>主业务流程+前中后的控制</title><link>http://www.blogjava.net/jjwwhmm/archive/2009/12/22/306889.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Tue, 22 Dec 2009 03:36:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2009/12/22/306889.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/306889.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2009/12/22/306889.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/306889.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/306889.html</trackback:ping><description><![CDATA[<p>产品设计的时候，往往是一个比较简单的东西，到后面弄的越来越复杂，甚至到最后没有人能够完整的描述这个产品，因为大家都被产品里繁多的细枝末叶搅得头晕眼花，最终迷失在&#8220;钻牛角尖&#8221;里.......<br />
我的体会是，一定要把主业务流程和业务的控制措施分开。主业务流程应该是简洁明了，可以依据输入、会话处理、输出、反馈的系统思想把一个业务比较清楚的描述出来。而控制措施则可以体现在输入端、会话处理中、输出端及反馈阶段上，对每一个阶段，都存在于这个阶段之前的控制，阶段之中的控制、阶段之后的控制。</p>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/306889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2009-12-22 11:36 <a href="http://www.blogjava.net/jjwwhmm/archive/2009/12/22/306889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>servlet中重定向的错误:IllegalStateException</title><link>http://www.blogjava.net/jjwwhmm/archive/2009/01/22/252364.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Thu, 22 Jan 2009 08:28:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2009/01/22/252364.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/252364.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2009/01/22/252364.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/252364.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/252364.html</trackback:ping><description><![CDATA[今天写了个servlet，在service方法中要重定向到另一个url地址，结果报错：<br />
java.lang.IllegalStateException<br />
&nbsp;org.apache.catalina.connector.ResponseFacade.sendRedirect(ResponseFacade.java:435)<br />
........<br />
&nbsp;javax.servlet.http.HttpServlet.service(HttpServlet.java:803)<br />
&nbsp;org.jboss.web.tomcat.filters.ReplyHeaderFilter.doFilter(ReplyHeaderFilter.java:96)<br />
最后检查发现是因为在service方法中第一行调用了super.service(req,rep)方法导致的错误.<br />
这个细节以前没有注意到,特此随笔记录.
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/252364.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2009-01-22 16:28 <a href="http://www.blogjava.net/jjwwhmm/archive/2009/01/22/252364.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基于请求应答及会话控制的系统集成设计模式</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/12/29/248836.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Mon, 29 Dec 2008 02:13:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/12/29/248836.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/248836.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/12/29/248836.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/248836.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/248836.html</trackback:ping><description><![CDATA[基于请求应答及会话控制的系统集成设计模式<br />
这个模式是我在多个系统的设计实践中总结出来的系统设计模式,属于EIP(Enterprise Integration Pattern的范畴吧!)<br />
首先举个例子:在支付系统的设计中怎么使用这个设计模式<br />
请求:用户或持卡人发起一个订单支付,系统接收到一个支付请求对象,然后系统就可以有一个支付请求处理的模块,有一个支付请求接收的多个渠道模块,请求的日志记录模块等<br />
会话控制:系统在处理万支付请求后,创建一个会话控制对象,用于控制用户在支付过程中的业务逻辑处理及状态跟踪,这个会话控制对象将根据各参与者的配置参数进行初始化,根据用户的行为设置并控制会话对象<br />
响应:用户在会话控制对象的协助下,完成了支付,系统返回一个支付响应对象,通过响应对象来通知各参与者支付结果<br />
<br />
在这个设计模式中,包含三个重要的对象:XXXRequest,XXXSession,XXXResponse.此处的XXX可根据系统业务的定义更改为对应的缩写.例如对于设置一个会员注册系统,则是MemberRegisterRequest、MemberRegisterSession、MemberRegisterResponse三个类。然后系统基于这三个对象设计各模块,通常至少包含三个模块:请求处理模块、会话业务处理模块以及响应处理模块.在这个基础上,再根据系统业务的复杂度来进一步细分模块.例如注册请求处理模块,可能根据注册请求的提交方式而进一步分为个人会员注册请求提交模块、企业会员注册请求提交模块、批量会员注册请求提交模块、WAP会员注册请求提交模块等等.<br />
<br />
这样的系统设计模式有什么好处呢?首先,模块的职责变的更清楚;第二,系统的设计更加规范化;第三,更加有利于系统的扩展<br />
。。。
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/248836.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-12-29 10:13 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/12/29/248836.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>java InetAddress 的dns cache问题</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/07/09/213685.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Wed, 09 Jul 2008 07:57:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/07/09/213685.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/213685.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/07/09/213685.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/213685.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/213685.html</trackback:ping><description><![CDATA[jdk的InetAddress有一个特性,就是当系统访问过一个域名的时候,InetAddress就会通过其私有变量addressCache把域名对应的ip地址缓存起来.<br />
虽然缓存起来能极大的提高系统性能,但有时候会给系统带来很大的麻烦.例如,当对方改动了ip地址后,系统就不能再访问到新的ip地址了,这个时候最直接的方案就是:重启jvm!!!这对于需要7*24小时服务的系统来说,是不可忍受的.<br />
下面一段代码可以重现这个现象(但需要你在运行的时候是在调试模式):<br />
public void testDnsCachePolicy() throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InetAddress addr1 = InetAddress.getByName("<a href="http://www.baidu.com/">www.baidu.com</a>");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(addr1.getHostAddress());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //在下一行设置断点.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InetAddress addr2 = InetAddress.getByName("<a href="http://www.baidu.com/">www.baidu.com</a>");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(addr2.getHostAddress());<br />
}<br />
具体测试方式是:<br />
1.修改c:/windows/system32/drivers/etc/hosts文件,在文件末尾加入:64.233.189.104&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.baidu.com/">www.baidu.com</a><br />
这个ip地址是google的ip<br />
2.运行代码到断点处<br />
这时候打印出的ip地址是64.233.189.104<br />
3.修改hosts文件,把"64.233.189.104&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.baidu.com/">www.baidu.com</a>"这行注释掉,"#64.233.189.104&nbsp;&nbsp;&nbsp;&nbsp; <a href="http://www.baidu.com/">www.baidu.com</a>"<br />
4.继续运行代码到结束<br />
这时候打印出的ip地址还是64.233.189.104,并没有更改为baidu的ip地址.<br />
<br />
那么应该怎么来解决这个问题呢?<br />
查了下网上的解决方案,一般是在启动jvm的时候,指定jvm参数:networkaddress.cache.ttl和networkaddress.cache.negative.ttl,具体的含义你可以查看InetAddress的源代码.<br />
这种方法的缺点是在JVM启动的时候就固定了dns的缓存策略.如果不缓存的话,对系统性能的影响是很大的,那么能不能动态的修改这个缓存的值呢?<br />
正好前段时间写了篇文章:怎么通过反射修改类的私有字段值.正好有了用武之地!<br />
下面是测试代码:<br />
//方法中的字符串常量policy,cache,addressCache请参考InetAddress源代码.<br />
public void testDnsCachePolicy() throws Exception {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InetAddress addr1 = InetAddress.getByName("<a href="http://www.baidu.com/">www.baidu.com</a>");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(addr1.getHostAddress());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //在下一行设置断点.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i = 0;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //修改缓存数据开始<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class inetAddressClass = java.net.InetAddress.class;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final Field cacheField = inetAddressClass.getDeclaredField("addressCache");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cacheField.setAccessible(true);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final Object obj = cacheField.get(inetAddressClass);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Class cacheClazz = obj.getClass();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final Field cachePolicyField = cacheClazz.getDeclaredField("policy");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final Field cacheMapField = cacheClazz.getDeclaredField("cache");&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cachePolicyField.setAccessible(true);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cacheMapField.setAccessible(true);&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; final Map cacheMap = (Map)cacheMapField.get(obj);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; cacheMap.remove("<a href="http://www.baidu.com/">www.baidu.com</a>");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //修改缓存数据结束<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; InetAddress addr2 = InetAddress.getByName("<a href="http://www.baidu.com/">www.baidu.com</a>");<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(addr2.getHostAddress());<br />
}<br />
重新按照上面的测试方法测试一次,第2次已经能够拿到正确的ip地址了.<br />
<br />
如果在用apache的httpclient,那么,在把缓存中的数据清除后,需要重新创建GetMethod/PostMethod对象.<br />
例如:<br />
HttpClient client = new HttpClient();<br />
GetMethod m1 = new GetMethod("http://www.baidu.com");<br />
client.executeMethod(m1);<br />
String content = m1.getResponseBodyAsString();<br />
........//通过上面的反射方法清楚缓存<br />
//重新执行m1,仍然不会得到正确的结果<br />
client.executeMethod(m1);<br />
String content = m1.getResponseBodyAsString();<br />
//重新创建GetMethod,才能得到正确的结果<br />
GetMethod m2 = new GetMethod("http://www.baidu.com");<br />
client.executeMethod(m2);<br />
content = m2.getResponseBodyAsString();<br />
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/213685.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-07-09 15:57 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/07/09/213685.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>我的JMS实践</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/06/26/210840.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Thu, 26 Jun 2008 07:43:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/06/26/210840.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/210840.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/06/26/210840.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/210840.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/210840.html</trackback:ping><description><![CDATA[本文中只是把我的一些使用JMS的心得写出来,并非什么"最佳实践",有错误的请大家尽管拍砖!<br />
<br />
1.消息类型的选择<br />
Java的JMS消息类型有文本类型,对象类型,字节类型,流类型,XML类型,在实际项目中,用的最多的是文本类型,对象类型和xml类型的消息.建议最好不用对象类型,因为如果用对象类型的话,调试的时候是很麻烦的,首先你必须要写专门的测试代码用来发送消息,第二,必须要管理对象所属的类的不同版本,第三,不方便查看queue或者topic中的消息内容.而如果使用文本类型或者xml类型的消息,那么可以很容易的通过JMS中间件提供的一些管理工具来发送测试消息,查看消息内容,并且更加容易管理不同版本之间的兼容性.如果一定要用对象类型消息的话,建议使用xstream把对象转化为xml<br />
<br />
2.是使用queue还是topic?<br />
这两者的定义是很清楚的,也很容易区分.但是在实际项目中,如何来取舍呢?我的建议是尽量用queue.如果你的项目用到了JMS,那么你的系统也应该是到了需要部署在集群环境的规模了.用topic在集群环境下会带来很多麻烦.举个简单的例子,如果你是用MDB来处理topic的消息,你有一个MDB名为SampleMDB,它以集群的方式分别部署在A服务器和B服务器上.那么有可能同一条topic消息被同一个MDB处理两次.虽然一些JMS中间件提供商为解决这种问题提供了一些解决方案,例如把subsriber分组,但是它为开发和调试都带来了很大的麻烦.topic消息的处理也要比queue的复杂,很难跟踪topic消息的处理过程.<br />
那么,如果不用topic的话,怎么来实现topic这种性质的消息处理呢?可以写一个消息转发器,把一个queue上的消息转发给所有关注这个queue的其它queue中.例如,有一个queue,名为SampleQ1,一个消息发送者sender,一个消息转发器router,有三个handler A,B,C需要处理这个queue中的消息.那么,sender发送消息到SampleQ1,router接收SampleQ1的消息后分别发送到SampleQ1_A,SampleQ1_B,SampleQ1_C,handler A,B,C分别从队列SampleQ1_A,SampleQ1_B,SampleQ1_C中接收消息.<br />
<br />
3.用JMS来解决什么问题?<br />
一提起JMS可以做什么,第一想到的就是异步处理.面试的时候问JMS可以做什么?大多数的回答是:用JMS来异步发送邮件!(到底应该怎么样构建一个邮件发送系统不是本文的主题,以后有时间我会专门来谈谈在我的项目中,我是怎么来设计邮件发送系统的).其实,还可以用JMS来解决很多复杂的问题,例如分布,并发,系统解耦,负载均衡,热部署,触发器等等,这些复杂的问题因为引入了JMS而变的更加简单.下面简单介绍下解决分布,并发问题的场景.<br />
3.1 用JMS来解决并发问题<br />
queue的概念大家都很清楚了,那就是queue里的一条消息只会被一个消息接收者处理.基于这个概念,我们可以在系统中对并发要求很严格的模块中引入JMS的使用.例如,系统的送积分,一般这个模块是用一个定时器,例如quartz,每天定期查询数据库,如果发现有满足条件的记录,那么就把积分送给会员.如果同时有多个quartz在运行,那么必须严格控制防止并发的对同一条记录送多次积分.解决这个问题有很多方法,可以通过业务的设计,系统的部署,数据库的设计,事务的控制等方法来实现,在这里提一个用JMS来解决问题的方法:在插入记录的同时发送一个queue的消息.这样即使有多个送积分的MDB实例在运行,也只会被一个实例处理.<br />
<br />
3.2用JMS来解决分布的问题<br />
解决分布有两种类型,第一种是指消息是集中的,但消息的处理是分布的.例如,系统可能会被分为前台与后台,这两个系统是部署在不同的网段里的.那么怎么把前台发生的业务通知后台系统呢?当然,可以通过一个类似定时器的玩意定期去数据库查询.但这种方式要么就是浪费系统资源,可能在定期查询中80%的时间都是在做无用功,要么就是业务请求没有被及时处理.,因为定期的时间总是有一个时间间隔的.用JMS来处理这个问题会怎么样呢?前台系统在处理完业务请求后的同时发送一个消息到queue中,后台系统的消息接收者接收到消息后立即处理.这里消息的处理也可能有一定的延期,但这主要取决于消息服务器的硬件能力,网络带宽,消息接收者的处理速度等.<br />
<br />
第二中是指消息也是分布的.很多消息中间件都提供了消息路由的功能,即消息发送到一个消息服务器后,这个消息服务器根据定义的规则再把这条消息路由转发到其它的消息服务器.例如,可能在北京的一个数据中心部署了数据采集系统,采集到数据后以消息的方式发送到消息服务器,然后消息服务器再把这条消息路由到上海的数据中心,再由上海数据中心部署的数据处理系统来处理这条消息.<br />
<br />
4.JMS与事务,一定要用JTA事务吗<br />
很多人接触到JTA事务都是从用JMS开始的,毕竟同时要连多个数据库的的系统并不是那么的多!而要用JTA事务的话,就得要在笨重的应用服务器中部署.(当然,你也可以用类似atomikos的轻量级JTA事务管理器),更重要的是,并不是事务本身的技术有多复杂,而是事务的界定,这种事务的界定有时都不是程序员能决定的事情,需要在设计的时候就要考虑清楚,甚至可能还需要业务人员的参与.(题外话:经常问面试的,用spring的aop做什么?大多数答:用来管理事务!事务要真这么简单该多好啊!)<br />
我也不是要反对用JTA事务,而是要说明一下,用JMS,并非一定要用JTA事务.这可以分为三种场景:<br />
一,必须用JTA事务,这种情况下,一般消息的接收者只从消息本身获得数据并进行处理.所以必须要保证消息的发送与所依赖的业务保持一致.<br />
二.不需要用事务,这种情况下, 要么是业务无关紧要,例如用JMS来记录日志.要么是发送的消息仅仅是一个作为后续业务处理的一个触发器!消息接收者仅仅是从消息中获得一个id,然后根据这个id去查询所依赖的其它数据进行业务处理.即使消息丢失也没关系,可以通过其它的机制来补偿.<br />
三.消息丢失可以通过补偿事务来完成.这个依赖与具体实现,就不详细说了.<br />
<br />
5.处理消息永远比发送消息慢!<br />
要保证你的JMS应用稳定的运行,那么你必须在开发,部署的时候时刻重视这个问题.<br />
首先,需要把发送消息的连接池与接收消息的连接池分开.以避免接收消息的连接过过而导致发送消息的应用拿不到连接.<br />
在一个连接上并发的处理消息,而不是连接打开,处理一个消息,马上关闭连接.<br />
合理的设置消息的过期时间,否则消息日积月累,最终超出queue的size<br />
对于非关键业务的消息处理,可以采用异步处理的方法:接收到消息后并不是立刻处理,而是放到一个任务池或者线程池中处理.如果消息处理失败,则把消息重新发送回队列中.<br />
<br />
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/210840.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-06-26 15:43 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/06/26/210840.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>通过反射修改类的私有字段值,调用私有方法</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/06/19/209083.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Thu, 19 Jun 2008 02:14:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/06/19/209083.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/209083.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/06/19/209083.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/209083.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/209083.html</trackback:ping><description><![CDATA[<p>下面这个例子在实际项目中一般都不会这么用,只是用来说明怎么通过反射修改类的私有字段的值.<br />
<br />
有一个类TestData:<br />
<br />
public class TestData {<br />
&nbsp;private String name = "1";<br />
&nbsp;<br />
&nbsp;public String getName() {<br />
&nbsp;&nbsp;return name;<br />
&nbsp;}<br />
}<br />
在运行的时候怎么来修改name的值呢?<br />
<br />
public class TestReflection extends TestCase {<br />
&nbsp;public void testSetPrivateField() throws Exception {<br />
&nbsp;&nbsp;TestData data = new TestData();<br />
&nbsp;&nbsp;System.out.println(data.getName());<br />
&nbsp; Assert.assertEquals("1", data.getName());<br />
&nbsp;&nbsp;Field f = data.getClass().getDeclaredField("name");<br />
&nbsp;&nbsp;f.setAccessible(true);<br />
&nbsp;&nbsp;f.set(data, "2");<br />
&nbsp;&nbsp;System.out.println(data.getName());<br />
&nbsp; Assert.assertEquals("2", data.getName());<br />
&nbsp;}<br />
}<br />
运行结果:<br />
1<br />
2<br />
其中,最关键的代码是:<br />
f.setAccessible(true);<br />
这行代码把对象data上的name字段设置为public访问属性.<br />
<br />
既然私有字段可以这样访问,那么,类似的,私有方法也可以这样调用!<br />
改一下TestData:<br />
<br />
public class TestData {<br />
&nbsp;private String name = "1";<br />
&nbsp;<br />
&nbsp;public String getName() {<br />
&nbsp;&nbsp;return name;<br />
&nbsp;}<br />
&nbsp;<br />
&nbsp;private void setName(String name) {<br />
&nbsp;&nbsp;this.name = name;<br />
&nbsp;}<br />
}<br />
在TestData中增加了私有的setName方法,下面是测试代码:<br />
public class TestReflection extends TestCase {&nbsp;<br />
&nbsp;public void testInvokePrivateMethod() throws Exception {<br />
&nbsp;&nbsp;TestData data = new TestData();<br />
&nbsp;&nbsp;System.out.println(data.getName());<br />
&nbsp; Assert.assertEquals("1", data.getName());<br />
&nbsp;&nbsp;Method m = data.getClass().getDeclaredMethod("setName", String.class);<br />
&nbsp;&nbsp;m.setAccessible(true);<br />
&nbsp;&nbsp;m.invoke(data, "3");<br />
&nbsp;&nbsp;System.out.println(data.getName());<br />
&nbsp; Assert.assertEquals("3", data.getName());<br />
&nbsp;}<br />
}<br />
运行结果:<br />
1<br />
3<br />
其中最关键的代码行是:<br />
m.setAccessible(true);<br />
它把对象data的setName方法的访问属性设置为public.</p>
<p>那么这样调用私有方法,访问私有属性有什么用处呢?<br />
在实际项目中,我们会使用很多其它第三方的包,有的时候是通过修改源代码完成你想要的功能,有的时候,是因为第三方包中仅仅因为某几个方法的访问属性被设置为private,或者只要修改private的字段值即可.这个时候,用这种反射的方法就可以很容易实现了.<br />
<br />
另外一个场景就是从系统架构层来考虑数据封装.例如系统有一些元数据类,99%的情况下,我们只是提供get方法供其它应用层获得字段的值,如果把修改的set方法也提供出去,那么可能会影响到系统的可维护性.而在系统运行期间,又很难避免的要修改这些元数据的值.这种情况下,也可以通过这种反射的方式来实现.</p>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/209083.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-06-19 10:14 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/06/19/209083.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>hessian序列化协议+memcached的缓存存取</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/06/18/208784.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Wed, 18 Jun 2008 02:04:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/06/18/208784.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/208784.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/06/18/208784.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/208784.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/208784.html</trackback:ping><description><![CDATA[<p>大名鼎鼎的memcached恐怕没人不知道吧!hessian是一种远程调用的机制,类似与web service,不过它是使用自己的序列化协议.<br />
那么,为什么要把hessian的序列化协议和memcached结合起来实现缓存的读取呢?<br />
有过使用memcached的经验的人会了解到,php+memcached的性能是最好的,java+memcached的性能比较差,其主要原因就是在于java本身的序列化机制很慢.<br />
我做了个简单的测试,一个UserData类,有一个字符串属性,一个日期属性,一个double属性,分别用java,hessian来序列化一百万次,结果让人吃惊,不止是hessian序列化的速度要比java的快上一倍,而且hessian序列化后的字节数也要比java的少一倍.因为我在测试的时候只是做了序列化这部分的工作,并没有把序列化后的结果放到网络上传输,所以,实际中的性能hessian应该会更好!<br />
既然hessian的序列化协议要比java本身的好,而memcached客户端的性能又在很大程度上依赖与对象的序列化.所以,我就决定把我的cache实现中序列化这部分的工作改成用hessian来实现了.<br />
我用的memcached客户端是用的danga.MemCached包,主要是改动了MemCachedClient的get方法及set方法,在set方法中改为调用hessian的序列化:<br />
ByteArrayOutputStream bos = new ByteArrayOutputStream();<br />
//修改以前的序列化代码:<br />
&nbsp;//(new ObjectOutputStream( bos )).writeObject( value );<br />
//修改后的序列化代码:<br />
serializeByHessian(bos, value);<br />
&nbsp;val = bos.toByteArray();<br />
serializeByHessian方法如下:</p>
&nbsp;protected void serializeByHessian(OutputStream os, Object object) throws IOException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AbstractHessianOutput out = new Hessian2Output(os);;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;SerializerFactory serializerFactory = getSerializerFactory();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.setSerializerFactory(serializerFactory);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.startReply();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.writeObject(object);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.completeReply();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;out.flush();<br />
&nbsp;}<br />
在get方法中主要是修改了这个方法调用的类ContextObjectInputStream的readObject方法:<br />
在ContextObjectInputStream中覆盖了readObjectOverride方法:<br />
&nbsp;protected Object readObjectOverride() throws IOException,&nbsp;&nbsp;ClassNotFoundException {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ByteArrayInputStream is = new ByteArrayInputStream(bytes);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ClHessian2Input in = new ClHessian2Input(is, this.mLoader);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;in.setSerializerFactory(getSerializerFactory());<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int code = in.read();//"r"<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int major = in.read();//&gt;=2<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int minor = in.read();//0<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Object value = in.readObject();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;is.close();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return value;<br />
&nbsp;}<br />
因为我的框架是基于osgi的,所以我重载了Hessian2Input,把classloader作为参数传进去,否则hessian在反序列化的时候会找不到类.如果你没有用osgi框架的话,&nbsp;ClHessian2Input in = new ClHessian2Input(is, this.mLoader);这行代码就可以直接用:&nbsp;Hessian2Input in = new Hessian2Input(is);<br />
这样修改就基本完成了.<br />
我把memcached client的序列化协议改为hessian也有另外一个系统架构的原因,那就是因为我的服务层逻辑都是用java+spring+osgi的方式实现,而web层则是用php实现,两者之间通讯已经是采用hessian的远程调用.所以,部分缓存数据在服务层通过java设置到memcached服务器中,在php中一样可以用memcached php client读取出来.(php的memcached client我用的是memcached-client.php,而不是php扩展,所以一样可以修改memcached-client.php的序列化机制)<br />
<br />
<br />
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/208784.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-06-18 10:04 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/06/18/208784.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OSGI启动参数-Dosgi.compatibility.bootdelegation=true的作用</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/06/02/205315.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Mon, 02 Jun 2008 05:59:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/06/02/205315.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/205315.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/06/02/205315.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/205315.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/205315.html</trackback:ping><description><![CDATA[今天写le一个bundle,名字叫JmsSendBundle,用spring的jms template来实现发送jms消息.,写完之后,在eclipse环境中运行都正常,但导出到我的osgi环境中,始终报一个错误:java.lang.NoClassDefFoundError: javax/naming/Referenceable
<div>搞了一上午,最后比较eclipse和我自己的osgi的启动环境变量,发现eclipse中<span  style="font-family: 'lucida grande'; font-size: 11px; white-space: pre; ">osgi.compatibility.bootdelegation的值是true,而我的是false,结果把这个参数改成true之后就可以了.</span></div>
<div><font  face="'lucida grande'" size="3"><span  style="font-size: 11px; white-space: pre;">然后去google了下osgi.compatibility.bootdelegation这个参数的作用,<span  style="font-family: Tahoma; font-size: 12px; line-height: 18px; white-space: normal; ">如果该参数值为"true"，当一个类或资源查找不到时，类加载器会启动父类加载器进行最后的查找。该参数的默认值为"true",不知道我的为什么缺省成false了.</span></span></font></div>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/205315.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-06-02 13:59 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/06/02/205315.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>equinox开发osgi时的一个小技巧:定义公用的jar文件.</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/05/29/203922.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Thu, 29 May 2008 11:33:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/05/29/203922.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/203922.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/05/29/203922.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/203922.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/203922.html</trackback:ping><description><![CDATA[一般在开发java项目的时候,我们会有一些公用的jar文件,在开发bundle的时候,如果把这些jar文件重复的在各bundle中复制的话,即烦琐,又容易出错.<br />
今天我琢磨出一个方法,虽然不敢说这么做是否是正确方法,但至少解决了正确的问题(用错误的方法解决正确的事总比用正确的方法解决错误的事好!哈哈).下面是解决的方法:<br />
&nbsp;1.修改org.eclipse.osgi.xxxxxx.jar文件<br />
&nbsp;&nbsp; a.把文件中META-INF目录中的ECLIPSE.SF,ECLIPSE.RSA文件删除掉(因为jar文件是通过SF文件来保证jar中的内容不被篡改!如果不了解这个的,可以去查下jar的详细说明)<br />
&nbsp;&nbsp; b.修改jar根目录下的J2SE-1.5.profile文件(如果你开发osgi使用的是其它J2SE环境,请编辑相应的文件)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 这个文件中定义了osgi启动时的org.osgi.framework.system.packages属性,因为osgi中每个bundle都有自己独立的classpath,那么在各个bundle之间共享的class就是通过这个属性中定义的包来指定的.(如果不了解osgi的class载入机制,请参阅osgi的入门教材!),你可以在文件中的这个属性值上加入自己的包,例如:<br />
&nbsp;........<br />
&nbsp;org.ietf.jgss,\<br />
&nbsp;org.omg.*,\<br />
&nbsp;org.w3c.*,\<br />
&nbsp;org.xml.*,\<br />
&nbsp;sun.*,\<br />
&nbsp;demo.*&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这一行是新增加的包<br />
2.把demo.*所在的jar文件加入到启动osgi的classpath中,一般你可以系统环境变量的classpath中加入这个jar文件路径.<br />
3.把第1步中修改后的osgi jar文件拷贝到eclipse的plugins目录下,重新启动eclipse<br />
4.打开一个bundle的MANIFEST.MF文件,在dependencies项中,你就可以在imported packages中导入刚才定义的demo包了.<br />
<br />
虽然这样做可以做到在各个bundle间共享一些jar文件,但这些公用的jar一定要确认清楚,否则会给以后的开发带来麻烦!因为之所以用osgi来开发,就是为了使用它的class loader的管理机制. 
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/203922.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-05-29 19:33 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/05/29/203922.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>OOD比OOP更重要</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/05/29/203892.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Thu, 29 May 2008 09:35:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/05/29/203892.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/203892.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/05/29/203892.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/203892.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/203892.html</trackback:ping><description><![CDATA[OOP相对比较容易学习,毕竟与编程语言的语法有很大关系.但是OOD就很复杂了,一个大的系统,到了后期越来越混乱,大多数原因是随着新员工的不断加入,他们不能和以前的老员工或者已离职的员工的设计概念保持一致.或者由于系统上线后,新来的业务需求大部分是以一个个小的特性加入到系统中,所以开发人员,管理人员都以一种很容易实现的方式去做这些事情,结果到后面就乱成一团.所以,系统在后期有个重要的工作,就是不断进行架构的重构,以便使新的模块,代码能与以前的在构架概念上保持一致.一个大的系统如果不以OOD的方式设计,那么构架师基本上很难把这个系统向新的涉众解释清楚,无论你是用用例图,类图,序列图,还是交互图,部署图,都难.必须要以一个个的子系统去描述它.<br />
总之,概念完整性是系统成功的关键.设计上的技术可能对某一个模块的影响会比较大.<br />
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/203892.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-05-29 17:35 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/05/29/203892.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Oracle AS的远程调试</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/05/28/203446.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Wed, 28 May 2008 03:57:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/05/28/203446.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/203446.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/05/28/203446.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/203446.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/203446.html</trackback:ping><description><![CDATA[如果要使OracleAS支持远程调试功能,需要在目录: \OracleAS_1\opmn\conf,修改配置文件opmn.xml:
<div><span  style="font-family: white-space: pre; ">&lt;module-data></span>
<pre>&lt;category id="start-parameters">
&lt;data id="java-options" value="-server &lt;del>Xdebug &lt;/del>Xnoagent -Djava.compiler=NONE
-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=4000
-Djava.security.policy=$ORACLE_HOME/j2ee/home/config/java2.policy
-Djava.awt.headless=true"/>
&lt;/category>
&lt;/module-data>
</pre>
</div>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/203446.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-05-28 11:57 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/05/28/203446.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Felix设计中的一个疑问</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/05/19/201412.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Mon, 19 May 2008 08:11:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/05/19/201412.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/201412.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/05/19/201412.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/201412.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/201412.html</trackback:ping><description><![CDATA[这两天在看apache的osgi框架felix的源代码,对里面很多类的构造函数都有个logger感到很疑惑,一个logger对象会成为一个类的构造函数所必须要的参数吗?
<div>例如:</div>
<div>public Felix(Logger logger, Map configMutableMap, List activatorList) {...}</div>
<div>private EventDispatcher(Logger logger) {...}</div>
<div>protected BundleContextImpl(Logger logger, Felix felix, FelixBundle bundle) {...}</div>
<div>这样的例子太多了.我还看不出这样使用logger有什么好处,应该是跟osgi框架的每个bundle使用单独的classpath有关,不知道哪位可以解释下.谢谢!</div>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/201412.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-05-19 16:11 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/05/19/201412.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>equinox的osgi命令</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/05/14/200343.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Wed, 14 May 2008 01:49:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/05/14/200343.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/200343.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/05/14/200343.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/200343.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/200343.html</trackback:ping><description><![CDATA[<span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">控制osgi framework的命令:<br />
&nbsp;launch&nbsp;-&nbsp;start&nbsp;the&nbsp;OSGi&nbsp;Framework</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">shutdown&nbsp;-&nbsp;shutdown&nbsp;the&nbsp;OSGi&nbsp;Framework</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">close&nbsp;-&nbsp;shutdown&nbsp;and&nbsp;exit</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">exit&nbsp;-&nbsp;exit&nbsp;immediately&nbsp;(System.exit)</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">init&nbsp;-&nbsp;uninstall&nbsp;all&nbsp;bundles</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">setprop&nbsp;&lt;key&gt;=&lt;value&gt;&nbsp;-&nbsp;set&nbsp;the&nbsp;OSGi&nbsp;property<br />
</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P><br />
控制bundle的命令:</O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">install&nbsp;-&nbsp;install&nbsp;and&nbsp;optionally&nbsp;start&nbsp;bundle&nbsp;from&nbsp;the&nbsp;given&nbsp;URL</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">uninstall&nbsp;-&nbsp;uninstall&nbsp;the&nbsp;specified&nbsp;bundle(s)</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">start&nbsp;-&nbsp;start&nbsp;the&nbsp;specified&nbsp;bundle(s)</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">stop&nbsp;-&nbsp;stop&nbsp;the&nbsp;specified&nbsp;bundle(s)</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">refresh&nbsp;-&nbsp;refresh&nbsp;the&nbsp;packages&nbsp;of&nbsp;the&nbsp;specified&nbsp;bundles</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">update&nbsp;-&nbsp;update&nbsp;the&nbsp;specified&nbsp;bundle(s)</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
显示bundle状态的命令:<br />
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">status&nbsp;[-s&nbsp;[&lt;comma&nbsp;separated&nbsp;list&nbsp;of&nbsp;bundle&nbsp;states&gt;]&nbsp;&nbsp;[&lt;segment&nbsp;of&nbsp;bsn&gt;]]&nbsp;-&nbsp;display&nbsp;installed&nbsp;bundles&nbsp;and&nbsp;registered&nbsp;services</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">ss&nbsp;[-s&nbsp;[&lt;comma&nbsp;separated&nbsp;list&nbsp;of&nbsp;bundle&nbsp;states&gt;]&nbsp;&nbsp;[&lt;segment&nbsp;of&nbsp;bsn&gt;]]&nbsp;-&nbsp;display&nbsp;installed&nbsp;bundles&nbsp;(short&nbsp;status)</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">services&nbsp;{filter}&nbsp;-&nbsp;display&nbsp;registered&nbsp;service&nbsp;details</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">packages&nbsp;{&lt;pkgname&gt;|&lt;id&gt;|&lt;location&gt;}&nbsp;-&nbsp;display&nbsp;imported/exported&nbsp;package&nbsp;details</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">bundles&nbsp;[-s&nbsp;[&lt;comma&nbsp;separated&nbsp;list&nbsp;of&nbsp;bundle&nbsp;states&gt;]&nbsp;&nbsp;[&lt;segment&nbsp;of&nbsp;bsn&gt;]]&nbsp;-&nbsp;display&nbsp;details&nbsp;for&nbsp;all&nbsp;installed&nbsp;bundles</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">bundle&nbsp;(&lt;id&gt;|&lt;location&gt;)&nbsp;-&nbsp;display&nbsp;details&nbsp;for&nbsp;the&nbsp;specified&nbsp;bundle(s)</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">headers&nbsp;(&lt;id&gt;|&lt;location&gt;)&nbsp;-&nbsp;print&nbsp;bundle&nbsp;headers</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
<p class="0" style="layout-grid-mode: char; text-align: justify"><font size="3"><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">&nbsp;</span><span style="font-size: 10.5pt; color: rgb(0,0,0); font-family: ''Courier New''; mso-spacerun: ''yes''">log&nbsp;(&lt;id&gt;|&lt;location&gt;)&nbsp;-&nbsp;display&nbsp;log&nbsp;entries</span><span style="font-size: 10.5pt; font-family: ''Courier New''; mso-spacerun: ''yes''"><O:P></O:P></span></font></p>
其它的命令一般不怎么用到,就不贴出来了.<br />
一般启动好osgi后,我们会用ss命令来看看当前bundles的启动状态<br />
用install命令把开发好的bundle部署到osgi中<br />
用update命令更新已经部署的bundle<br />
用uninstall命令停止一个bundle的服务
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/200343.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-05-14 09:49 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/05/14/200343.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Eclipse中自动通过ant脚本把web应用部署到tomcat中</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/05/04/198060.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Sun, 04 May 2008 05:51:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/05/04/198060.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/198060.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/05/04/198060.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/198060.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/198060.html</trackback:ping><description><![CDATA[<div>1.要使用tomcat的DeployTask,首先要在eclipse的ant环境变量中把DeployTask所在的jar把加到ant的classpath中</div>
<br />
<div>把tomcat目录的lib目录中的catalina-ant.jar拷贝的eclipse的ant插件所在目录的lib目录中,一般这个目录是在eclipse目录的plugins目录中的org.apache.ant开头的一个目录中.</div>
<div>eclipse->window->preference->ant->runtime->classpath,把上一步拷贝的jar文件加到classpath中</div>
<div>2.在ant脚本中定义deploy,undeploy的任务</div>
<div>&lt;taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask" /></div>
<div>&lt;taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" /></div>
<div>3.在ant脚本中部署应用</div>
<div><span  style="white-space: pre; "><span class="Apple-tab-span" style="white-space:pre">	</span>&lt;target name="undeploy">
&lt;undeploy url="http://localhost:8080/manager"
username="username"
password="password"
path="/webapp-name" />
&lt;/target>
&lt;target name="deploy" depends="cas-war">
&lt;deploy url="http://localhost:8080/manager"
username="username"
password="password"
path="/webapp-name"
update="true"
localWar="${distDir}/webapp-name.war" />
&lt;/target>	</span></div>
<div><span  style="white-space: pre;">把username, password替换为登录tomcat的管理界面时使用的用户名/密码,把webapp-name替换为应用的名称.</span></div>
<div><span  style="white-space: pre;">执行ant的deploy任务,即可把在ant中打包好的war包部署到tomcat中.这样就不用每次ant打包好后,再登录tomcat管理界面部署应用了.同样的方法可以用于jboss的部署.</span></div>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/198060.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-05-04 13:51 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/05/04/198060.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Spring的InitializingBean和init-method</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/04/14/192800.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Mon, 14 Apr 2008 07:36:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/04/14/192800.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/192800.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/04/14/192800.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/192800.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/192800.html</trackback:ping><description><![CDATA[<div><span  style="font-family: Arial; font-size: 14px; line-height: 18px; ">Spring在设置完一个bean所有的属性后，会检查bean是否实现了InitializingBean接口，如果实现就调用bean的afterPropertiesSet方法。另外,如果bean是单例的,则afterPropertiesSet方法只会被调用一次;否则每次创建bean时afterPropertiesSet方法都会被重新调用.</span></div>
<div><span  style="font-family: Arial; font-size: 14px; line-height: 18px; ">Spring虽然可以通过InitializingBean完成一个bean初始化后对这个bean的回调，但是这种方式要求bean实现 InitializingBean接口。一但bean实现了InitializingBean接口，那么这个bean的代码就和Spring耦合到一起了。通常情况下不建议直接实现InitializingBean，而是用Spring提供的init-method的功能来执行一个bean 子定义的初始化方法,这可以在一个bean的配置文件中通过init-method声明:</span></div>
<div><font  face="Arial" size="4"><span  style="font-size: 14px; line-height: 18px;"><span class="Apple-tab-span" style="white-space:pre">	</span>&lt;bean id="testBean" class="TestClass" init-method="initialize"/><br />
</span></font></div>
<div><font  face="Arial" size="4"><span  style="font-size: 14px; line-height: 18px;">spring要求这个init-method方法是一个无参数的方法</span></font></div>
<div><font  face="Arial" size="4"><span  style="font-size: 14px; line-height: 18px;">如果一个bean同时实现了这两种方式的初始化配置,则spring会先调用afterPropertiesSet方法,然后通过反射调用init-method,任何一个方法出错都会导致spring创建bean失败.如果afterPropertiesSet方法调用失败,也不会再继续执行init-mehtod方法.</span></font></div>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/192800.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-04-14 15:36 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/04/14/192800.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>String,简单又复杂</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/04/14/192706.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Mon, 14 Apr 2008 03:26:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/04/14/192706.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/192706.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/04/14/192706.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/192706.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/192706.html</trackback:ping><description><![CDATA[<br />
<div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; ">String a = "abc";</div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; ">String b = "abc";</div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; ">Assert.assertTrue(a == b);</div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; ">String c = "abcdefg";</div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; ">String d = c.substring(0, 3);</div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; ">Assert.assertFalse(a == d);</div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; ">a == b这个比较好理解,因为<span  style="font-family: Arial; font-size: 14px; line-height: 21px; ">在编译的时候会产生一个静态对象&#8220;abc&#8221;, 执行a = "abc"和b = "abc"的时候,只是把这个静态对象赋给了a和b,所以两个对象的引用相同,a==b</span></div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; "><font  face="Arial" size="4"><span  style="font-size: 14px; line-height: 21px;">但是,d的值为"abc"字符串,为什么jvm不把静态的"abc"的引用赋给d对象呢?</span></font></div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; "><font  face="Arial" size="4"><span  style="font-size: 14px; line-height: 21px;">我的理解是:String a = "abc"; String b = "abc";这两行代码是在解释执行之前编译成字节码的时候,"abc"就放在常量池中了,所以在执行的时候a和b指向同一个引用,而String d = c.substring(0, 3);是在执行的时候才给d对象赋值"abc",所以这个"abc"应该是放在堆中.</span></font></div>
<div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; cursor: pointer; "><font  face="Arial" size="4"><span  style="font-size: 14px; line-height: 21px;">还是想的不明白.</span></font></div>
</div>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/192706.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-04-14 11:26 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/04/14/192706.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>今天看jdk包里的Class的源代码,不知道isSynthetic()是做什么用的</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/03/26/188663.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Wed, 26 Mar 2008 02:35:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/03/26/188663.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/188663.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/03/26/188663.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/188663.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/188663.html</trackback:ping><description><![CDATA[这个方法在class是什么类型的时候返回true呢?有什么用呢?不知道哪位大虾可以告知小弟,万分感谢!
<div>参考连接:http://www.sagewire.org/java-programmer/isSynthetic-185494.aspx</div>
<img src ="http://www.blogjava.net/jjwwhmm/aggbug/188663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-03-26 10:35 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/03/26/188663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于http gzip压缩的一点想法</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/03/21/187675.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Fri, 21 Mar 2008 04:52:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/03/21/187675.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/187675.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/03/21/187675.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/187675.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/187675.html</trackback:ping><description><![CDATA[今天在路上偶尔想到,既然js,html,图片等静态内容可以通过http gzip压缩的方式传输到浏览器(相对于普通的浏览过程HTML ,CSS,Javascript , Text&nbsp;，它可以节省40%左右的流量),那用jsp,servlet等动态创建的内容是否也可以压缩传输呢?还有AJAX的请求内容是否也可以用gziap压缩传输?<br />
带着这些问题在网上查了下资料<br />
AJAX的请求可以通过在http request中增加一个头标识:accept-encoding,值为"gzip"的方式实现<br />
servlet则可以通过配置一个filter来实现<br />
针对Apache2.0之前的版本，可以通过添加第三方的module_gzip模块来启用<br />
针对Apache2.0及之后的版本，可以通过mod_deflate启动<br />
<br />
<br />
下面的一个链接详细介绍了apache,tomcat中的配置方法:<br />
http://www.128kj.com/article/article5/DA6B1D7BCDE9DE999C34E7379E18B35A.htm?id=2746<br />
http://blogger.org.cn/blog/more.asp?name=lhwork&amp;id=21867<br />
<br />
用tomcat 6的可以到下面的url参考:<br />
http://tomcat.apache.org/tomcat-6.0-doc/config/http.html<br />
<br />
在tomcat的server.xml的connector部分,把compression="force"选项加上,然后,就可以用下面的代码测试,我是在demo应用下放了个md5.js:<br />
<p>/**<br />
&nbsp;* Created at 2008-03-21.<br />
&nbsp;*/<br />
package com.demo.test.http.gzip;</p>
<p>import junit.framework.TestCase;</p>
<p>import org.apache.commons.httpclient.HttpClient;<br />
import org.apache.commons.httpclient.methods.GetMethod;</p>
<p>/**<br />
&nbsp;* @author pony</p>
<p>&nbsp;* 如果有任何对代码的修改,请按下面的格式注明修改的内容.<br />
&nbsp;* 序号&nbsp;&nbsp; 时间&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 作者&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 修改内容<br />
&nbsp;* 1.&nbsp; 2008-3-21&nbsp;pony created this class.<br />
&nbsp;*<br />
&nbsp;*/<br />
public class TestTomcatGzipConfigure extends TestCase {<br />
&nbsp;public void testGetGzipContentFromTomcat() throws Exception {<br />
&nbsp;&nbsp;HttpClient http = new HttpClient();<br />
&nbsp;&nbsp;GetMethod get = new GetMethod("http://192.168.66.128:8080/demo/md5.js");<br />
&nbsp;&nbsp;try {<br />
&nbsp;&nbsp;&nbsp;get.addRequestHeader("accept-encoding", "gzip,deflate");<br />
&nbsp;&nbsp;&nbsp;get.addRequestHeader(<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"user-agent",<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0; Alexa Toolbar; Maxthon 2.0)");<br />
&nbsp;&nbsp;&nbsp;int er = http.executeMethod(get);<br />
&nbsp;&nbsp;&nbsp;if (er == 200) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(get.getResponseContentLength());<br />
&nbsp;&nbsp;&nbsp;&nbsp;String html = get.getResponseBodyAsString();<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(html);<br />
&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(html.getBytes().length);<br />
&nbsp;&nbsp;&nbsp;}<br />
&nbsp;&nbsp;} finally {<br />
&nbsp;&nbsp;&nbsp;get.releaseConnection();<br />
&nbsp;&nbsp;}<br />
&nbsp;}<br />
}</p>
<br />
<br />
 <img src ="http://www.blogjava.net/jjwwhmm/aggbug/187675.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-03-21 12:52 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/03/21/187675.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>jasperReport创建报表的基本流程</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/03/11/185378.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Tue, 11 Mar 2008 06:46:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/03/11/185378.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/185378.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/03/11/185378.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/185378.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/185378.html</trackback:ping><description><![CDATA[1.报表的xml设计,当然也可以是在内存中创建<br />
2.Loader,把xml报表设计加载到内存中<br />
3.Compiler,把加载到内存中的设计编译成为报表设计对象ReportDesign<br />
4.FillManager,读取数据填充到报表设计中,得到ReportPrint<br />
5.ExportManger,把ReportPrint保存到文件或打印到输出中
 <img src ="http://www.blogjava.net/jjwwhmm/aggbug/185378.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-03-11 14:46 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/03/11/185378.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>准备有空的时候写篇文章介绍下各种java remoting机制的benchmarks</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/03/10/184942.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Mon, 10 Mar 2008 01:52:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/03/10/184942.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/184942.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/03/10/184942.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/184942.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/184942.html</trackback:ping><description><![CDATA[主要包括以下几种java remoting机制:<br />
1.binary-rpc:例如hessian,httpinvoker,rmi,ormi<br />
2.xml-rpc:burlap,cxf<br />
3.rmi<br />
4.socket:mina<br />
5.jms:sonic mq, ibm mq, activemq<br />
从网上查到的结果看,一般是:<br />
1.基于二进制的remoting协议要比基于xml的快<br />
2.在各种二进制的remoting协议间性能的差距很小<br />
3.burlap要比其它的基于xml的remoting协议快<br />
4.基于二进制的remoting协议在传输大的对象时性能会有下降<br />
还有一个区别,我觉得基于http的remoting协议能基于http来实现负载均衡,这点很重要.
 <img src ="http://www.blogjava.net/jjwwhmm/aggbug/184942.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-03-10 09:52 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/03/10/184942.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>27/Feb/2008:10:12:44 +0800这样的日期格式在java里的解析.</title><link>http://www.blogjava.net/jjwwhmm/archive/2008/02/28/182679.html</link><dc:creator>pony</dc:creator><author>pony</author><pubDate>Thu, 28 Feb 2008 06:17:00 GMT</pubDate><guid>http://www.blogjava.net/jjwwhmm/archive/2008/02/28/182679.html</guid><wfw:comment>http://www.blogjava.net/jjwwhmm/comments/182679.html</wfw:comment><comments>http://www.blogjava.net/jjwwhmm/archive/2008/02/28/182679.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/jjwwhmm/comments/commentRss/182679.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/jjwwhmm/services/trackbacks/182679.html</trackback:ping><description><![CDATA[今天在解析apache usertrack模块产生的clickstream日志文件时,其中有一个接收请求的时间,其格式为:<br />
27/Feb/2008:10:12:44 +0800<br />
在用SimpleDateFormat解析时始终出错.后来的解决办法:<br />
SimpleDateFormat formatter = new SimpleDateFormat("dd/MMM/yyyy:hh:mm:ss Z", Locale.ENGLISH);<br />
formatter.parse(strDateTime);<br />
这段代码就可以解析上面的时间字符串了.<br />
原因是:<br />
1.+0800表示的是时区的信息,用Z可以解析<br />
2.Feb这个月份只有用Locale.ENGLISH才能解析,如果用缺省的new SimpleDateFormat("dd/MMM/yyyy:hh:mm:ss Z"),<br />
这时解析器使用的是Locale.getDefault(),即Local.Chinese,而Feb在中文里并没有定义是几月,所以解析会出错.<br />
如果时间字符串是"27/一月/2008:10:12:44 +0800",注意英文简称的月份已经变为中文的月份,这时用确认的Locale是可以正确解析的.即:<br />
SimpleDateFormat formatter = new SimpleDateFormat("dd/MMM/yyyy:hh:mm:ss Z");<br />
formatter.parse(strDateTime);<br />
或者:<br />
SimpleDateFormat formatter = new SimpleDateFormat("dd/MMM/yyyy:hh:mm:ss Z", Locale.CHINESE);<br />
formatter.parse(strDateTime);<br />
 <img src ="http://www.blogjava.net/jjwwhmm/aggbug/182679.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/jjwwhmm/" target="_blank">pony</a> 2008-02-28 14:17 <a href="http://www.blogjava.net/jjwwhmm/archive/2008/02/28/182679.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>