﻿<?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-xskow's road.-文章分类-Java</title><link>http://www.blogjava.net/xskowscut/category/39190.html</link><description>&lt;font size=5&gt;做好自己，做好一切。&lt;/font&gt;</description><language>zh-cn</language><lastBuildDate>Tue, 21 Jul 2009 02:43:03 GMT</lastBuildDate><pubDate>Tue, 21 Jul 2009 02:43:03 GMT</pubDate><ttl>60</ttl><item><title>【转】菜鸟课堂：教你提升JSP应用程序七大绝招 </title><link>http://www.blogjava.net/xskowscut/articles/283153.html</link><dc:creator>xskow!</dc:creator><author>xskow!</author><pubDate>Fri, 19 Jun 2009 00:56:00 GMT</pubDate><guid>http://www.blogjava.net/xskowscut/articles/283153.html</guid><wfw:comment>http://www.blogjava.net/xskowscut/comments/283153.html</wfw:comment><comments>http://www.blogjava.net/xskowscut/articles/283153.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xskowscut/comments/commentRss/283153.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xskowscut/services/trackbacks/283153.html</trackback:ping><description><![CDATA[<span style="color: red">前言：</span>虽然有一定JSP开发经验的人都认为自己不是菜鸟，但到底你是不是菜鸟？看看这篇文章吧，可能有些东东你以前是没有想到过的。<br />
<span style="color: red">文章出处：</span>http://news.newhua.com/news1/program_net/2009/616/09616946223A29I5BAB71IJIF9E74844E030D238D1JHA88JEH9II48.html<br />
<span style="color: red">文章内容：</span><br />
<p style="text-indent: 2em">你时常被客户抱怨JSP页面响应速度很慢吗？你想过当客户访问次数剧增时，你的WEB应用能承受日益增加的访问量吗？ </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">本文讲述了调整JSP和servlet的一些非常实用的方法，它可使你的servlet和JSP页面响应更快，扩展性更强。而且在用户数增加的情况下，系统负载会呈现出平滑上长的趋势。在本文中，我将通过一些实际例子和配置方法使得你的应用程序的性能有出人意料的提升。其中，某些调优技术是在你的编程工作中实现的。而另一些技术是与应用服务器的配置相关的。在本文中，我们将详细地描述怎样通过调整servlet和JSP页面，来提高你的应用程序的总体性能。在阅读本文之前，假设你有基本的servlet和JSP的知识。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em"><strong>方法一：在servlet的init()方法中缓存数据</strong> </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">当应用服务器初始化servlet实例之后，为客户端请求提供服务之前，它会调用这个servlet的init()方法。在一个servlet的生命周期中，init()方法只会被调用一次。通过在init()方法中缓存一些静态的数据或完成一些只需要执行一次的、耗时的操作，就可大大地提高系统性能。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">例如，通过在init()方法中建立一个JDBC连接池是一个最佳例子，假设我们是用jdbc2.0的DataSource接口来取得数据库连接，在通常的情况下，我们需要通过JNDI来取得具体的数据源。我们可以想象在一个具体的应用中，如果每次SQL请求都要执行一次JNDI查询的话，那系统性能将会急剧下降。解决方法是如下代码，它通过缓存DataSource，使得下一次SQL调用时仍然可以继续利用它： </p>
<p style="text-indent: 2em"><ccid_nobr></ccid_nobr></p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" style="font-size: 9pt" bgcolor="#e6e6e6">
            <pre>						<ccid_code></ccid_code>public class ControllerServlet extends HttpServlet {
            　private javax.sql.DataSource testDS = null;
            　public void init(ServletConfig config)
            throws ServletException 　{
            　　super.init(config);
            　　Context ctx = null;
            　　try 　　{
            　　　ctx = new InitialContext();
            　　　testDS = (javax.sql.DataSource)ctx.lookup("jdbc/testDS");
            　　}
            　　catch(NamingException ne) 　　{
            　　　ne.printStackTrace();
            　　}
            　　catch(Exception e) 　　{
            　　　e.printStackTrace();
            　　}
            　}
            　public javax.sql.DataSource getTestDS() 　{
            　　return testDS;
            　}
            　...
            　...
            }</pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em"><strong>方法 2:禁止servlet和JSP 自动重载(auto-reloading)</strong> </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">Servlet/JSP提供了一个实用的技术，即自动重载技术，它为开发人员提供了一个好的开发环境，当你改变servlet和JSP页面后而不必重启应用服务器。然而，这种技术在产品运行阶段对系统的资源是一个极大的损耗，因为它会给JSP引擎的类装载器(classloader)带来极大的负担。因此关闭自动重载功能对系统性能的提升是一个极大的帮助。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em"><strong>方法 3: 不要滥用HttpSession</strong> </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">在很多应用中，我们的程序需要保持客户端的状态，以便页面之间可以相互联系。但不幸的是由于HTTP具有天生无状态性，从而无法保存客户端的状态。因此一般的应用服务器都提供了session来保存客户的状态。在JSP应用服务器中，是通过HttpSession对像来实现session的功能的，但在方便的同时，它也给系统带来了不小的负担。因为每当你获得或更新session时，系统者要对它进行费时的序列化操作。你可以通过对HttpSession的以下几种处理方式来提升系统的性能： </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">如果没有必要，就应该关闭JSP页面中对HttpSession的缺省设置： 如果你没有明确指定的话，每个JSP页面都会缺省地创建一个HttpSession。如果你的JSP中不需要使用session的话，那可以通过如下的JSP页面指示符来禁止它： ＜%@ page session="false"%＞ </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">不要在HttpSession中存放大的数据对像：如果你在HttpSession中存放大的数据对像的话，每当对它进行读写时，应用服务器都将对其进行序列化，从而增加了系统的额外负担。你在HttpSession中存放的数据对像越大，那系统的性能就下降得越快。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">当你不需要HttpSession时，尽快地释放它：当你不再需要session时，你可以通过调用HttpSession.invalidate()方法来释放它。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<div style="text-indent: 2em">尽量将session的超时时间设得短一点：在JSP应用服务器中，有一个缺省的session的超时时间。当客户在这个时间之后没有进行任何操作的话，系统会将相关的session自动从内存中释放。超时时间设得越大，系统的性能就会越低，因此最好的方法就是尽量使得它的值保持在一个较低的水平。 </div>
<div style="text-indent: 2em">　　 <span class="a14c" id="zoom">
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em"><strong>方法 4: 将页面输出进行压缩</strong> </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">压缩是解决数据冗余的一个好的方法，特别是在网络带宽不够发达的今天。有的浏览器支持gzip(GNU zip)进行来对HTML文件进行压缩，这种方法可以戏剧性地减少HTML文件的下载时间。因此，如果你将servlet或JSP页面生成的HTML页面进行压缩的话，那用户就会觉得页面浏览速度会非常快。但不幸的是，不是所有的浏览器都支持gzip压缩，但你可以通过在你的程序中检查客户的浏览器是否支持它。下面就是关于这种方法实现的一个代码片段： </p>
<p style="text-indent: 2em"><ccid_nobr></ccid_nobr></p>
<table cellspacing="0" bordercolordark="#ffffff" cellpadding="2" width="400" align="center" bordercolorlight="black" border="1">
    <tbody>
        <tr>
            <td class="code" style="font-size: 9pt" bgcolor="#e6e6e6">
            <pre>								<ccid_code></ccid_code>public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {
            　OutputStream out = null
            　String encoding = request.getHeader("Accept-Encoding");
            　if (encoding != null &amp;&amp; encoding.indexOf("gzip") != -1) 　{
            　　request.setHeader("Content-Encoding" , "gzip");
            　　out = new GZIPOutputStream(request.getOutputStream());
            　}
            　else if (encoding != null &amp;&amp; encoding.indexOf("compress") != -1) 　{
            　　request.setHeader("Content-Encoding" , "compress");
            　　out = new ZIPOutputStream(request.getOutputStream());
            　}
            　else 　{
            　　out = request.getOutputStream();
            　}
            　...
            　...
            }</pre>
            </td>
        </tr>
    </tbody>
</table>
<br />
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em"><strong>方法 5: 使用线程池</strong> </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">应用服务器缺省地为每个不同的客户端请求创建一个线程进行处理，并为它们分派service()方法，当service()方法调用完成后，与之相应的线程也随之撤消。由于创建和撤消线程会耗费一定的系统资源，这种缺省模式降低了系统的性能。但所幸的是我们可以通过创建一个线程池来改变这种状况。另外，我们还要为这个线程池设置一个最小线程数和一个最大线程数。在应用服务器启动时，它会创建数量等于最小线程数的一个线程池，当客户有请求时，相应地从池从取出一个线程来进行处理，当处理完成后，再将线程重新放入到池中。如果池中的线程不够地话，系统会自动地增加池中线程的数量，但总量不能超过最大线程数。通过使用线程池，当客户端请求急剧增加时，系统的负载就会呈现的平滑的上升曲线，从而提高的系统的可伸缩性。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em"><strong>方法 6: 选择正确的页面包含机制</strong> </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">在JSP中有两种方法可以用来包含另一个页面1、使用include指示符(＜%@ includee file=&#8221;test.jsp&#8221; %＞)。2、使用jsp指示符(＜jsp:includee page=&#8221;test.jsp&#8221; flush=&#8221;true&#8221;/＞)。在实际中我发现，如果使用第一种方法的话，可以使得系统性能更高。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em"><strong>方法 7:正确地确定javabean的生命周期</strong> </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">JSP的一个强大的地方就是对javabean的支持。通过在JSP页面中使用＜jsp:useBean＞标签，可以将javabean直接插入到一个JSP页面中。它的使用方法如下： ＜jsp:useBean id="name" scope="page|request|session|application" class= "package.className" type="typeName"＞＜/jsp:useBean＞ </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">其中scope属性指出了这个bean的生命周期。缺省的生命周期为page。如果你没有正确地选择bean的生命周期的话，它将影响系统的性能。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">举例来说，如果你只想在一次请求中使用某个bean，但你却将这个bean的生命周期设置成了session，那当这次请求结束后，这个bean将仍然保留在内存中，除非session超时或用户关闭浏览器。这样会耗费一定的内存，并无谓的增加了JVM垃圾收集器的工作量。因此为bean设置正确的生命周期，并在bean的使命结束后尽快地清理它们，会使用系统性能有一个提高。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">其它一些有用的方法 　　? 在字符串连接操作中尽量不使用&#8220;＋&#8221;操作符：在java编程中，我们常常使用&#8220;＋&#8221;操作符来将几个字符串连接起来，但你或许从来没有想到过它居然会对系统性能造成影响吧？由于字符串是常量，因此JVM会产生一些临时的对像。你使用的&#8220;＋&#8221;越多，生成的临时对像就越多，这样也会给系统性能带来一些影响。解决的方法是用StringBuffer对像来代替&#8220;＋&#8221;操作符。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">避免使用System.out.println()方法：由于System.out.println()是一种同步调用，即在调用它时，磁盘I/O操作必须等待它的完成，因此我们要尽量避免对它的调用。但我们在调试程序时它又是一个必不可少的方便工具，为了解决这个矛盾，我建议你最好使用Log4j工具(http://Jakarta.apache.org ; )，它既可以方便调试，而不会产生System.out.println()这样的方法。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">ServletOutputStream 与 PrintWriter的权衡:使用PrintWriter可能会带来一些小的开销，因为它将所有的原始输出都转换为字符流来输出，因此如果使用它来作为页面输出的话，系统要负担一个转换过程。而使用ServletOutputStream作为页面输出的话就不存在一个问题，但它是以二进制进行输出的。因此在实际应用中要权衡两者的利弊。 </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em"><strong>总结</strong> </p>
<p style="text-indent: 2em">&nbsp;</p>
<p style="text-indent: 2em">本文的目的是通过对servlet和JSP的一些调优技术来极大地提高你的应用程序的性能，并因此提升整个J2EE应用的性能。通过这些调优技术，你可以发现其实并不是某种技术平台（比如J2EE和.NET之争）决定了你的应用程序的性能，重要是你要对这种平台有一个较为深入的了解，这样你才能从根本上对自己的应用程序做一个优化！</p>
</span></div>
<img src ="http://www.blogjava.net/xskowscut/aggbug/283153.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xskowscut/" target="_blank">xskow!</a> 2009-06-19 08:56 <a href="http://www.blogjava.net/xskowscut/articles/283153.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【转】浅析java Exception(转)</title><link>http://www.blogjava.net/xskowscut/articles/282628.html</link><dc:creator>xskow!</dc:creator><author>xskow!</author><pubDate>Tue, 16 Jun 2009 08:06:00 GMT</pubDate><guid>http://www.blogjava.net/xskowscut/articles/282628.html</guid><wfw:comment>http://www.blogjava.net/xskowscut/comments/282628.html</wfw:comment><comments>http://www.blogjava.net/xskowscut/articles/282628.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xskowscut/comments/commentRss/282628.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xskowscut/services/trackbacks/282628.html</trackback:ping><description><![CDATA[<div class="blog_content">
<p><span class="hilite1">Java</span>提供了两类主要的异常:runtime exception和checked exception。所有的checked exception是从<span class="hilite1">java</span>.lang.Exception类衍生出来的，而runtime exception则是从<span class="hilite1">java</span>.lang.RuntimeException或<span class="hilite1">java</span>.lang.Error类衍生出来的。 <br />
<br />
　　它们的不同之处表现在两方面:机制上和逻辑上。<br />
<br />
<br />
一、机制上<br />
<br />
　　它们在机制上的不同表现在两点:1.如何定义方法;2. 如何处理抛出的异常。请看下面CheckedException的定义:<br />
<br />
<br />
public class CheckedException extends Exception<br />
{<br />
<br />
　public CheckedException() {}<br />
　public CheckedException( String message )<br />
　{<br />
　　super( message );<br />
　}<br />
}<br />
<br />
　　以及一个使用exception的例子:<br />
<br />
<br />
public class ExceptionalClass<br />
{<br />
<br />
　public void method1()<br />
　　throws CheckedException<br />
　　{<br />
　　　// ... throw new CheckedException( &#8220;...出错了&#8220; );<br />
　　}<br />
　public void method2( String arg )<br />
　　{<br />
　　　if( arg == null )<br />
　　　{<br />
　　　　throw new NullPointerException( &#8220;method2的参数arg是null!&#8221; );<br />
　　　}<br />
　　}<br />
　public void method3() throws CheckedException<br />
　　{<br />
　　　method1();<br />
　　}<br />
}<br />
<br />
　　你可能已经注意到了，两个方法method1()和method2()都会抛出exception，可是只有method1()做了声明。另外，method3()本身并不会抛出exception，可是它却声明会抛出CheckedException。在向你解释之前，让我们先来看看这个类的main()方法:<br />
<br />
<br />
public static void main( String[] args )<br />
{<br />
<br />
　ExceptionalClass example = new ExceptionalClass();<br />
　try<br />
　{<br />
　　example.method1();<br />
　　example.method3();<br />
　}<br />
　catch( CheckedException ex ) { } example.method2( null );<br />
}<br />
<br />
　　在main()方法中，如果要调用method1()，你必须把这个调用放在try/catch程序块当中，因为它会抛出Checked exception。<br />
<br />
　　相比之下，当你调用method2()时，则不需要把它放在try/catch程序块当中，因为它会抛出的exception不是checked exception，而是runtime exception。会抛出runtime exception的方法在定义时不必声明它会抛出exception。<br />
<br />
　　现在，让我们再来看看method3()。它调用了method1()却没有把这个调用放在try/catch程序块当中。它是通过声明它会抛出method1()会抛出的exception来避免这样做的。它没有捕获这个exception，而是把它传递下去。实际上main()方法也可以这样做，通过声明它会抛出Checked exception来避免使用try/catch程序块(当然我们反对这种做法)。<br />
<br />
　　小结一下:<br />
<br />
　　* Runtime exceptions:<br />
<br />
　　在定义方法时不需要声明会抛出runtime exception;<br />
<br />
　　在调用这个方法时不需要捕获这个runtime exception;<br />
<br />
　　runtime exception是从<span class="hilite1">java</span>.lang.RuntimeException或<span class="hilite1">java</span>.lang.Error类衍生出来的。<br />
<br />
　　* Checked exceptions:<br />
<br />
　　定义方法时必须声明所有可能会抛出的checked exception;<br />
<br />
　　在调用这个方法时，必须捕获它的checked exception，不然就得把它的exception传递下去;<br />
<br />
　　checked exception是从<span class="hilite1">java</span>.lang.Exception类衍生出来的。</p>
<p>二、逻辑上<br />
<br />
　　从逻辑的角度来说，checked exceptions和runtime exception是有不同的使用目的的。checked exception用来指示一种调用方能够直接处理的异常情况。而runtime exception则用来指示一种调用方本身无法处理或恢复的程序错误。<br />
<br />
　　checked exception迫使你捕获它并处理这种异常情况。以<span class="hilite1">java</span>.net.URL类的构建器(constructor)为例，它的每一个构建器都会抛出MalformedURLException。MalformedURLException就是一种checked exception。设想一下，你有一个简单的程序，用来提示用户输入一个URL，然后通过这个URL去下载一个网页。如果用户输入的URL有错误，构建器就会抛出一个exception。既然这个exception是checked exception，你的程序就可以捕获它并正确处理:比如说提示用户重新输入。<br />
<br />
　　再看下面这个例子:<br />
<br />
<br />
public void method()<br />
{<br />
<br />
　int [] numbers = { 1, 2, 3 };<br />
　int sum = numbers[0] numbers[3];<br />
}<br />
<br />
　　在运行方法method()时会遇到ArrayIndexOutOfBoundsException(因为数组numbers的成员是从0到2)。对于这个异常，调用方无法处理/纠正。这个方法method()和上面的method2()一样，都是runtime exception的情形。上面我已经提到，runtime exception用来指示一种调用方本身无法处理/恢复的程序错误。而程序错误通常是无法在运行过程中处理的，必须改正程序代码。<br />
<br />
　　总而言之，在程序的运行过程中一个checked exception被抛出的时候，只有能够适当处理这个异常的调用方才应该用try/catch来捕获它。而对于runtime exception，则不应当在程序中捕获它。如果你要捕获它的话，你就会冒这样一个风险:程序代码的错误(bug)被掩盖在运行当中无法被察觉。因为在程序测试过程中，系统打印出来的调用堆栈路径(StackTrace)往往使你更快找到并修改代码中的错误。有些程序员建议捕获runtime exception并纪录在log中，我反对这样做。这样做的坏处是你必须通过浏览log来找出问题，而用来测试程序的测试系统(比如Unit Test)却无法直接捕获问题并报告出来。<br />
<br />
　　在程序中捕获runtime exception还会带来更多的问题:要捕获哪些runtime exception?什么时候捕获?runtime exception是不需要声明的，你怎样知道有没有runtime exception要捕获?你想看到在程序中每一次调用方法时，都使用try/catch程序块吗? </p>
</div>
转载出处：http://westlifesz.javaeye.com/blog/49585
<img src ="http://www.blogjava.net/xskowscut/aggbug/282628.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xskowscut/" target="_blank">xskow!</a> 2009-06-16 16:06 <a href="http://www.blogjava.net/xskowscut/articles/282628.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>[转]jar参数运行应用时classpath的设置方法</title><link>http://www.blogjava.net/xskowscut/articles/267029.html</link><dc:creator>xskow!</dc:creator><author>xskow!</author><pubDate>Wed, 22 Apr 2009 11:08:00 GMT</pubDate><guid>http://www.blogjava.net/xskowscut/articles/267029.html</guid><wfw:comment>http://www.blogjava.net/xskowscut/comments/267029.html</wfw:comment><comments>http://www.blogjava.net/xskowscut/articles/267029.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/xskowscut/comments/commentRss/267029.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/xskowscut/services/trackbacks/267029.html</trackback:ping><description><![CDATA[<h2><a class="entrytitlelist" title="-jar参数运行应用时classpath的设置方法" href="http://www.zeali.net/entry/15" rel="bookmark">-jar参数运行应用时classpath的设置方法</a></h2>
<div class="modcontent">
<div class="date_entry"><span class="small">Posted by zeal on 2005-04-28 10:20 , 3586 characters | &nbsp;<a title="对此贴 '献鲜花'" href="javascript:voteWin('good','15','weblog_zeal','k_')">+</a> 1 <a title="对此贴 '扔鸡蛋'" href="javascript:voteWin('bad','15','weblog_zeal','k_')">-</a> 0 &nbsp;&nbsp;<a title="Translate this aritcle into English Version" href="http://translate.google.com/translate?u=http%3A%2F%2Fwww.zeali.net%2Fblog%2Fentry.php%3Fid%3D15&amp;langpair=zh-CN%7Cen&amp;hl=zh-CN&amp;newwindow=1&amp;ie=UTF-8&amp;oe=UTF-8&amp;prev=%2Flanguage_tools" target="_blank"><span class="small">English</span></a></span></div>
<div id="entryCopyright"><span class="bold highlightfont">转载请保留本行原始链接信息</span> : <a href="http://www.zeali.net/entry/15">http://www.zeali.net/entry/15</a> <span class="small">MADE 1n ZEAL</span></div>
<div id="entryTagsLine">标签 ( <a href="http://www.zeali.net/archive/c/JAVA">JAVA/C++</a> ): <a title="Tag: jar" href="http://www.zeali.net/tag/jar" rel="tag">jar</a>&nbsp;,&nbsp;<a title="Tag: classpath" href="http://www.zeali.net/tag/classpath" rel="tag">classpath</a>&nbsp;,&nbsp;<a title="Tag: 类库" href="http://www.zeali.net/tag/%e7%b1%bb%e5%ba%93" rel="tag">类库</a>&nbsp;,&nbsp;<a title="Tag: classloader" href="http://www.zeali.net/tag/classloader" rel="tag">classloader</a></div>
<div id="entry_introduce"></div>
<div id="entryBody">
<p>当用java -jar yourJarExe.jar来运行一个经过打包的应用程序的时候，你会发现如何设置-classpath参数应用程序都找不到相应的第三方类，报ClassNotFound错误。实际上这是由于当使用-jar参数运行的时候，java VM会屏蔽所有的外部classpath,而只以本身yourJarExe.jar的内部class作为类的寻找范围。</p>
<p>**解决方案**</p>
<p>一 BootStrap class扩展方案</p>
<p>Java 命令行提供了如何扩展bootStrap 级别class的简单方法.<br />
-Xbootclasspath:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;完全取代基本核心的Java class 搜索路径.<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 不常用,否则要重新写所有Java 核心class<br />
-Xbootclasspath/a: 后缀在核心class搜索路径后面.常用!!<br />
-Xbootclasspath/p: 前缀在核心class搜索路径前面.不常用,避免<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 引起不必要的冲突.</p>
<p>语法如下:<br />
&nbsp;(分隔符与classpath参数类似，unix使用:号,windows使用;号，这里以unix为例)<br />
<strong>&nbsp;<font face="courier new,courier,monospace">java -Xbootclasspath/a:/usrhome/thirdlib.jar: -jar yourJarExe.jar</font></strong></p>
<p>二 extend class 扩展方案</p>
<p>Java exten class 存放在{Java_home}\jre\lib\ext目录下.当调用Java时,对扩展class路径的搜索是自动的.总会搜索的.这样,解决的方案就很简单了,将所有要使用的第三方的jar包都复制到ext 目录下.</p>
<p>三 User class扩展方案</p>
<p>当使用-jar执行可执行Jar包时,JVM将Jar包所在目录设置为codebase目录,所有的class搜索都在这个目录下开始.所以如果使用了其他第三方的jar包,一个比较可以接受的可配置方案,就是利用jar包的Manifest扩展机制.<br />
步骤如下:</p>
<p>&nbsp;1.将需要的第三方的jar包,复制在同可执行jar所在的目录或某个子目录下.&nbsp;比如:jar 包在 /usrhome/yourJarExe.jar 那么你可以把所有jar包复制到/usrhome目录下或/usrhome/lib 等类似的子目录下.</p>
<p>&nbsp;2.修改Manifest 文件</p>
<p>&nbsp;在Manifest.mf文件里加入如下行</p>
<p>&nbsp;<font face="courier new,courier,monospace">Class-Path:classes12.jar lib/thirdlib.jar</font></p>
<p>&nbsp;Class-Path 是可执行jar包运行依赖的关键词.详细内容可以参考&nbsp;<a href="http://java.sun.com/docs/books/tutorial/deployment/jar/downman.html" target="_blank">http://java.sun.com/docs/books/tutorial/deployment/jar/downman.html</a>&nbsp;。要注意的是 Class-Path 只是作为你本地机器的CLASSPATH环境变量的一个缩写，也就是说用这个前缀表示在你的jar包执行机器上所有的CLASSPATH目录下寻找相应的第三方类/类库。你并不能通过 Class-Path 来加载位于你本身的jar包里面（或者网络上）的jar文件。因为从理论上来讲，你的jar发布包不应该再去包含其他的第三方类库（而应该通过使用说明来提醒用户去获取相应的支持类库）。如果由于特殊需要必须把其他的第三方类库（jar, zip, class等）直接打包在你自己的jar包里面一起发布，你就必须通过实现自定义的ClassLoader来按照自己的意图加载这些第三方类库。</p>
<p><br />
以上三种方法<strong>推荐第一种</strong>，扩展性好，操作起来也最方便.<br />
另外编写自己的ClassLoader,来动态载入class,是更加复杂和高级技术.限于篇幅,不赘述.有兴趣了解可以去google一下custom classloader，或者参考我的另一篇日志：<a title="让classpath参数走开" href="http://www.zeali.net/blog/entry.php?id=337" alt="让classpath参数走开">让classpath参数走开</a>。</p>
<p>Java的安全机制随不同的JDK版本有不同的变化,会影响很多核心CLASS,比如Thread,所以很多大型商业软件,要求JDK的版本很严格.部分原因也在此.这也要求在发布自己编写的应用时候,不管大小,都要说明开发和测试的JDK版本.</p>
<p><br />
本文所述方法测试基于j2sdk 1.4.2_04-b05 </p>
<p>----------------------------------------------------------------------------------------------</p>
<p>附:背景知识</p>
<p>自JDK 1.2以后,JVM采用了委托(delegate)模式来载入class．采用这种设计的原因可以参考<a href="http://java.sun.com/docs/books/tutorial/ext/basics/load.html" target="_blank">http://java.sun.com/docs/books/tutorial/ext/basics/load.html</a> </p>
<p>归纳来讲:是基于JVM sandbox(沙盒)安装模型上提供应用层的可定制的安全机制.</p>
<p><br />
Java虚拟机(JVM)寻找Class的顺序</p>
<p>1. Bootstrap classes</p>
<p>属于Java 平台核心的class,比如java.lang.String等.及rt.jar等重要的核心级别的class.这是由JVM Bootstrap class loader来载入的.一般是放置在{java_home}\jre\lib目录下</p>
<p>2. Extension classes</p>
<p>基于Java扩展机制,用来扩展Java核心功能模块.比如Java串口通讯模块comm.jar.一般放置在{Java_home}\jre\lib\ext目录下</p>
<p>3. User classes</p>
<p>开发人员或其他第三方开发的Java程序包.通过命令行的-classpath或-cp,或者通过设置CLASSPATH环境变量来引用.JVM通过放置在{java_home}\lib\tools.jar来寻找和调用用户级的class.常用的javac也是通过调用tools.jar来寻找用户指定的路径来编译Java源程序.这样就引出了User class路径搜索的顺序或优先级别的问题.</p>
<p>&nbsp;3.1 缺省值:调用Java或javawa的当前路径(.),是开发的class所存在的当前目录<br />
&nbsp;3.2 CLASSPATH环境变量设置的路径.如果设置了CLASSPATH,则CLASSPATH的值会覆盖缺省值<br />
&nbsp;3.3 执行Java的命令行-classpath或-cp的值,如果制定了这两个命令行参数之一,它的值会覆盖环境变量CLASSPATH的值<br />
&nbsp;3.4 -jar 选项:如果通过java -jar 来运行一个可执行的jar包,这当前jar包会覆盖上面所有的值.换句话说,-jar 后面所跟的jar包的优先级别最高,如果指定了-jar选项,所有环境变量和命令行制定的搜索路径都将被忽略.JVM APPClassloader将只会以jar包为搜索范围.<br />
有关可执行jar有许多相关的安全方面的描述,可以参考<a href="http://java.sun.com/docs/books/tutorial/jar/" target="_blank">http://java.sun.com/docs/books/tutorial/jar/</a> 来全面了解.</p>
</div>
</div>
 <img src ="http://www.blogjava.net/xskowscut/aggbug/267029.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/xskowscut/" target="_blank">xskow!</a> 2009-04-22 19:08 <a href="http://www.blogjava.net/xskowscut/articles/267029.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>