日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

技術(shù)問(wèn)答

 Mis林桑 2017-07-10

背景:

某日臨近下班,一個(gè)同事欲任何類(lèi)中獲取項(xiàng)目絕對(duì)路徑,不通過(guò)Request方式獲取,可是始終獲取不到預(yù)想的路徑。于是晚上回家google了一下,誤以為是System.getProperty('java.class.path')-未實(shí)際進(jìn)行測(cè)試,早上來(lái)和同事溝通,提出了使用這個(gè)內(nèi)置方法,結(jié)果人家早已驗(yàn)證過(guò),該方法是打印出CLASSPATH環(huán)境變量的值。

于是乎,繼續(xù)google,找到了ClassgetResourcegetResourceAsStream兩個(gè)方法。這兩個(gè)方法會(huì)委托給ClassLoader對(duì)應(yīng)的同名方法。以為這樣就可以搞定(實(shí)際上確實(shí)可以搞定),但驗(yàn)證過(guò)程中卻發(fā)生了奇怪的事情。


軟件環(huán)境:Windows XP、ResinTomcat6.0、Myeclipse、JDK1.5


發(fā)展:


我的驗(yàn)證思路是這樣的:

1、定義一個(gè)Servlet,然后在該Servlet中調(diào)用Path類(lèi)的getPath方法,getPath方法返回工程classpath的絕對(duì)路徑,顯示在jsp中。

2、另外在Path類(lèi)中,通過(guò)ClassgetResourceAsStream讀取當(dāng)前工程classpath路徑中的a.txt文件,寫(xiě)入到getResource路徑下的b.txt。

由于時(shí)間匆忙,代碼沒(méi)有好好去組織。大致能看出上述兩個(gè)功能,很簡(jiǎn)單不做解釋。

Path.javapublic class Path { public String getPath() throws IOException{ InputStream is = this.getClass().getResourceAsStream('/a.txt'); File file = new File(Path.class.getResource('/').getPath()+'/b.txt'); OutputStream os = new FileOutputStream(file); int bytesRead = 0; byte[] buffer = new byte[8192]; while ((bytesRead = is.read(buffer, 0, 8192)) != -1) { os.write(buffer, 0, bytesRead); } os.close(); is.close(); return this.getClass().getResource('/').getPath(); }}

PathServlet.javapublic class PathServlet extends HttpServlet { private static final long serialVersionUID = 4443655831011903288L; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Path path = new Path(); request.setAttribute('path', path.getPath()); PrintWriter out = response.getWriter(); out.println('Class.getResource('/').getPath():' + path.getPath()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); }}

在此之前使用main函數(shù)測(cè)試Path.class.getResource('/').getPath()打印出預(yù)想的路徑為:/D:/work/project/EhCacheTestAnnotation/WebRoot/WEB-INF/classes/ 

于是將WEB應(yīng)用部署到Resin下,運(yùn)行定義好的Servlet,出乎意料的結(jié)果是:/D:/work/resin-3.0.23/webapps/WEB-INF/classes/ 。特別奇怪,怎么會(huì)丟掉項(xiàng)目名稱(chēng):EhCacheTestAnnotation呢?


還有一點(diǎn)值得注意,getPath方法中使用getResourceAsStream('/a.txt')卻正常的讀到了位于下圖的a.txt。




然后寫(xiě)到了如下圖的b.txt中。代碼中是這樣實(shí)現(xiàn)的:File file = new File(Path.class.getResource('/').getPath()+'/b.txt');本意是想在a.txt文件目錄下再寫(xiě)入b.txt。結(jié)果卻和料想的不一樣。



請(qǐng)注意,區(qū)別還是丟掉了項(xiàng)目名稱(chēng)。


寫(xiě)的比較亂,稍微總結(jié)下:


程序中使用ClassLoader的兩個(gè)方法:getResourceAsStreamgetResource。但是事實(shí)證明在WEB應(yīng)用的場(chǎng)景下卻得到了不同的結(jié)果。大家別誤會(huì)啊,看名字他們兩個(gè)方法肯定不一樣,這個(gè)我知道,但是getResourceAsStream總會(huì)獲取指定路徑下的文件吧,示例中的參數(shù)為'/a.txt',正確讀取“/D:/work/resin-3.0.23/webapps/EhCacheTestAnnotation/WEB-INF/classes/ ”下的a.txt,可是將文件寫(xiě)到getResource方法的getPath返回路徑的b.txt文件。兩個(gè)位置的差別在項(xiàng)目名稱(chēng)(EhCacheTestAnnotation)。


這樣我暫且得出一個(gè)結(jié)論:通過(guò)getResourceAsStreamgetResource兩個(gè)方法獲取的路徑是不同的。但是為什么呢?


于是查看了ClassLoader的源碼,貼出getResourcegetResourceAsStream的源碼。


public URL getResource(String name) { URL url; if (parent != null) { url = parent.getResource(name); } else { url = getBootstrapResource(name); } if (url == null) { url = findResource(name); } return url; } public InputStream getResourceAsStream(String name) { URL url = getResource(name); try { return url != null ? url.openStream() : null; } catch (IOException e) { return null; }    }

從代碼中看,getResourceAsStream將獲取URL委托給了getResource方法。天啊,這是怎么回事兒?由此我徹底迷茫了,百思不得其解。


但是沒(méi)有因此就放棄,繼續(xù)回想了一遍整個(gè)過(guò)程:


1、在main函數(shù)中,測(cè)試getResource與getResourceAsStream是完全相同的,正確的。

2、將其部署到Resin下,導(dǎo)致了getResource與getResourceAsStream獲取的路徑不一致。


一個(gè)閃光點(diǎn),是不是與web容器有關(guān)啊,于是換成Tomcat6.0。OMG,“奇跡”出現(xiàn)了,真的是這樣子啊,換成Tomcat就一樣了??!和預(yù)想的一致。


在Tomcat下運(yùn)行結(jié)果如下圖:




對(duì),這就是我想要的。


因此我對(duì)Resin產(chǎn)生了厭惡感,之前也因?yàn)樵?span>Resin下程序報(bào)錯(cuò),在Tomcat下正常運(yùn)行而糾結(jié)了好久。記得看《松本行弘的程序世界》中對(duì)C++中的多繼承是這樣評(píng)價(jià)的(大概意思):多重繼承帶來(lái)的負(fù)面影響多數(shù)是由于使用不當(dāng)造成的。是不是因?yàn)閷?duì)Resin使用不得當(dāng)才使得和Tomcat下得到不同的結(jié)果。


最終,在查閱Resin配置文件resin.conf時(shí)候在標(biāo)簽下發(fā)現(xiàn)了這樣一段:


class-loader> compiling-loader path='webapps/WEB-INF/classes'/> library-loader path='webapps/WEB-INF/lib'/> class-loader>

其中的compiling-loader很可能與之有關(guān),遂將其注釋掉,一切正常。擔(dān)心是錯(cuò)覺(jué),于是將compiling-loaderpath屬性改成:webapps/WEB-INF/classes1,然后運(yùn)行pathServlet,b.txt位置如下圖:




確實(shí)與compiling-loader有關(guān)。


結(jié)局:


終于通過(guò)將標(biāo)簽注釋掉,同樣可以在Resin中獲取“預(yù)想”的路徑。驗(yàn)證了的確是使用Resin的人出了問(wèn)題。


疑問(wèn):


但是沒(méi)有這樣就結(jié)束,我繼續(xù)對(duì)getResource的源碼進(jìn)行了跟進(jìn),由于能力有限,沒(méi)有弄清楚getResource的原理。


最終留下了兩個(gè)疑問(wèn):


1、如果追蹤到getResource方法的最底層(也許是JVM層面),它實(shí)現(xiàn)的原理是什么?

2、為何Resin的配置會(huì)對(duì)getResource產(chǎn)生影響,但是對(duì)getResourceAsStream毫無(wú)影響(getResourceAsStream可是將獲取路徑委托給getResource的啊)。還是這里我理解或者使用錯(cuò)誤了?


在這里也請(qǐng)明白人指明。


    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類(lèi)似文章 更多