日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

tomcat防cc_浅析Tomcat防止资料被锁的方式

發(fā)布時(shí)間:2024/7/19 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 tomcat防cc_浅析Tomcat防止资料被锁的方式 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

在Windows平臺(tái)的Tomcat上部署應(yīng)用后,應(yīng)用下的個(gè)別文件可能會(huì)被Tomcat鎖住,解部署的時(shí)候刪除不掉那些內(nèi)容,就會(huì)導(dǎo)致無(wú)法重部署。如果解部署刪除不掉被鎖的文件,Tomcat會(huì)在日志中警告說(shuō):

2013-1-9 15:44:09 org.apache.catalina.startup.ExpandWar delete

嚴(yán)重: [D:\tomcat\apache-tomcat-7.0.32\webapps\struts2-blank] could not be completely deleted. The presence of the remaining files may cause problems

被鎖的文件通常是/WEB-INF/lib下的Jar包,又以Struts2和XWork的Jar包為甚。

遇到這個(gè)問(wèn)題,最簡(jiǎn)單但最折騰的做法就是停止Tomcat、手動(dòng)刪除webapps目錄下殘留的文件,再重啟、重新部署應(yīng)用。

說(shuō)明:

測(cè)試應(yīng)用是Struts 2.3.8自帶的struts2-blank.war

源碼分析對(duì)象是Tomcat 7.0.23

1. 文件是如何被鎖的?

Tomcat會(huì)為每個(gè)應(yīng)用創(chuàng)建一個(gè)單獨(dú)的ClassLoader(WebappClassLoader),負(fù)責(zé)加載應(yīng)用使用的Java類和資源。

WebappClassLoader是java.net.URLClassLoader的子類,URLClassLoader在加載資源的時(shí)候會(huì)使用getResource方法去訪問(wèn)資源,如果資源文件在Jar包里,那就會(huì)打開(kāi)到Jar包的URL連接,而URLConnection缺省會(huì)打開(kāi)一個(gè)緩存、將創(chuàng)建過(guò)連接的內(nèi)容緩存起來(lái),一旦內(nèi)容被緩存,那相應(yīng)的Jar包就會(huì)被鎖定。

2. 解決方案

針對(duì)Windows上文件被鎖、不能重部署應(yīng)用的問(wèn)題,Tomcat給出了兩個(gè)解決方案:

2.1 從Tomcat 5.0開(kāi)始,可以在context.xml的Context元素上設(shè)置antiJARLocking屬性為true;從Tomcat 5.5開(kāi)始,可以在context.xml的Context元素上設(shè)置antiResourceLocking屬性為true(說(shuō)明)

但在Tomcat 7.0.23(注釋掉server.xml里Server元素下的JreMemoryLeakPreventionListener,這個(gè)監(jiān)聽(tīng)器在后面分析)和Tomcat 6.0.20里用struts2-blank.war測(cè)試,只有將antiResourceLocking設(shè)置為true,Struts和XWork的Jar包才會(huì)在解部署時(shí)刪除。接下來(lái)分析一下這兩個(gè)屬性的工作原理。

(1)antiJARLocking

先來(lái)看看應(yīng)用的antiJARLocking屬性設(shè)置為true時(shí),Tomcat是怎么處理的。

針對(duì)antiJARLocking屬性的處理集中在WebappClassLoader的getResource和findResourceInternal方法里,主要原理是將包含在Jar包里的資源抽取放到應(yīng)用的工作目錄(work里應(yīng)用對(duì)應(yīng)的目錄)下去。findResourceInternal的主要代碼為:

if (antiJARLocking && !(path.endsWith(".class"))) {

byte[] buf = new byte[1024];

File resourceFile = new File

(loaderDir, jarEntry.getName());

if (!resourceFile.exists()) {

Enumeration entries =

jarFiles[i].entries();

while (entries.hasMoreElements()) {

JarEntry jarEntry2 = entries.nextElement();

if (!(jarEntry2.isDirectory())

&& (!jarEntry2.getName().endsWith

(".class"))) {

resourceFile = new File

(loaderDir, jarEntry2.getName());

......

File parentFile = resourceFile.getParentFile();

if (!parentFile.mkdirs() && !parentFile.exists()) {

// Ignore the error (like the IOExceptions below)

}

FileOutputStream os = null;

InputStream is = null;

try {

is = jarFiles[i].getInputStream

(jarEntry2);

os = new FileOutputStream

(resourceFile);

while (true) {

int n = is.read(buf);

if (n <= 0) {

break;

}

os.write(buf, 0, n);

}

resourceFile.setLastModified(

jarEntry2.getTime());

} catch (IOException e) {

// Ignore

} finally {

// 關(guān)閉流、釋放資源

}

}

}

}

}

把這個(gè)屬性設(shè)置為true之后,部署應(yīng)用就可以在work\Catalina\localhost\struts2-blank\loader目錄下看到被解壓的Jar包內(nèi)容。

antiJARLocking屬性在有的時(shí)候并不會(huì)生效,從WebappClassLoader的getResource和findResource方法邏輯里可以看出一些端倪,在一些情況下(通過(guò)對(duì)Loader的delegate、searchExternalFirst等相關(guān)屬性進(jìn)行配置),資源的獲取并不是WebappClassLoader去做的,而是其父加載器的getResource方法或父類的findResource方法去做的,WebappClassLoader的父類是URLClassLoader、父加載器是URLClassLoader實(shí)例。

(2)antiResourceLocking

當(dāng)antiResourceLocking設(shè)置為true的時(shí)候,Tomcat不會(huì)鎖定應(yīng)用下的任何文件。那Tomcat是怎么做到這一點(diǎn)的呢?

在Tomcat的架構(gòu)里,應(yīng)用也是一個(gè)級(jí)別的容器,對(duì)應(yīng)的接口是Context;各級(jí)容器本身都具備生命周期,而且配置了多個(gè)生命周期監(jiān)聽(tīng)器來(lái)監(jiān)聽(tīng)容器不同的生命周期過(guò)程。Tomcat在初始化的時(shí)候,給Context增加了一個(gè)生命周期監(jiān)聽(tīng)器org.apache.catalina.startup.ContextConfig;然后在Context真正開(kāi)始啟動(dòng)之前,會(huì)有一個(gè)BEFORE_START_EVENT狀態(tài),ContextConfig監(jiān)聽(tīng)到這個(gè)狀態(tài)的事件后,就會(huì)針對(duì)antiResourceLocking進(jìn)行處理。

antiLocking的主要代碼和主要邏輯為:

protected void antiLocking() {

// 只針對(duì)應(yīng)用做處理,應(yīng)用的antiResourceLocking屬性設(shè)置為true

if ((context instanceof StandardContext)

&& ((StandardContext) context).getAntiResourceLocking()) {

// 獲取應(yīng)用原始的doc base(docBaseFile變量,缺省是webapps下以應(yīng)用名稱為名的目錄)

Host host = (Host) context.getParent();

String appBase = host.getAppBase();

String docBase = context.getDocBase();

if (docBase == null)

return;

if (originalDocBase == null) {

originalDocBase = docBase;

} else {

docBase = originalDocBase;

}

File docBaseFile = new File(docBase);

if (!docBaseFile.isAbsolute()) {

File file = new File(appBase);

if (!file.isAbsolute()) {

file = new File(getBaseDir(), appBase);

}

docBaseFile = new File(file, docBase);

}

// 獲取應(yīng)用的“path + version”,作為新的doc base,version通常是空

String path = context.getPath();

if (path == null) {

return;

}

ContextName cn = new ContextName(path, context.getWebappVersion());

docBase = cn.getBaseName();

// 在java.io.tmpdir下新建目錄

File file = null;

if (originalDocBase.toLowerCase(Locale.ENGLISH).endsWith(".war")) {

file = new File(System.getProperty("java.io.tmpdir"),

deploymentCount++ + "-" + docBase + ".war");

} else {

file = new File(System.getProperty("java.io.tmpdir"),

deploymentCount++ + "-" + docBase);

}

// 將應(yīng)用的內(nèi)容從原始doc base拷貝到j(luò)ava.io.tmpdir下新建的目錄中,

// 并將臨時(shí)目錄下的內(nèi)容作為應(yīng)用的doc base

ExpandWar.delete(file);

if (ExpandWar.copy(docBaseFile, file)) {

context.setDocBase(file.getAbsolutePath());

}

}

}

總結(jié)一下,就是如果應(yīng)用的antiResourceLocking屬性設(shè)置為true,就將應(yīng)用的doc base移到臨時(shí)目錄下,讓Tomca不會(huì)占用webapps下的文件。Tomcat里java.io.tmpdir默認(rèn)指向Tomcat的temp目錄。

副作用

從上面的分析來(lái)看,antiResourceLocking為true有幾個(gè)副作用:

1) 會(huì)延長(zhǎng)應(yīng)用的啟動(dòng)時(shí)間,因?yàn)槎嗔伺R時(shí)目錄的清理和往臨時(shí)目錄拷貝應(yīng)用內(nèi)容的操作;

2) 如果不知道這個(gè)屬性的原理,修改webapps下應(yīng)用的JSP,那就不會(huì)動(dòng)態(tài)重加載到新的頁(yè)面內(nèi)容了,因?yàn)閼?yīng)用的doc base已經(jīng)不再在webapps下了;

3) 停止Tomcat的時(shí)候,臨時(shí)目錄下實(shí)際的doc base會(huì)被刪掉,代碼如下:

protected synchronized void configureStop() {

......

Host host = (Host) context.getParent();

String appBase = host.getAppBase();

String docBase = context.getDocBase();

// originalDocBase變量初始為null,只有antiResourceLocking為true時(shí)才會(huì)賦值

if ((docBase != null) && (originalDocBase != null)) {

File docBaseFile = new File(docBase);

if (!docBaseFile.isAbsolute()) {

docBaseFile = new File(appBase, docBase);

}

// 刪除

ExpandWar.delete(docBaseFile, false);

}

......

}

結(jié)合第二條和第三條,如果要修改應(yīng)用的JSP,那必須將改動(dòng)同時(shí)拷貝到兩個(gè)目錄下(原始doc base和臨時(shí)目錄下的doc base)。

所以Tomcat里這個(gè)屬性缺省為false。在使用Tomcat 6.0.24之前的版本時(shí),如果要用這個(gè)屬性解決文件被鎖的問(wèn)題,三思而行。

2.2 從Tomcat 6.0.24開(kāi)始,可以在server.xml的Server元素下配置JreMemoryLeakPreventionListener的urlCacheProtection屬性為true(說(shuō)明)

這個(gè)監(jiān)聽(tīng)器有諸多屬性,其中解決文件被鎖的是urlCacheProtection屬性。urlCacheProtection的原理很簡(jiǎn)單,就是針對(duì)文件被鎖的根本原因進(jìn)行處理——在Server(Tomcat的頂級(jí)容器)初始化之前就將URLConnection的緩存關(guān)掉。

// Set the default URL caching policy to not to cache

if (urlCacheProtection) {

try {

// Doesn't matter that this JAR doesn't exist - just as

// long as the URL is well-formed

URL url = new URL("jar:file://dummy.jar!/");

URLConnection uConn = url.openConnection();

uConn.setDefaultUseCaches(false); // 修改URLConnection私有的靜態(tài)變量defaultUserCaches

} catch (MalformedURLException e) {

log.error(sm.getString("jreLeakListener.jarUrlConnCacheFail"), e);

} catch (IOException e) {

log.error(sm.getString("jreLeakListener.jarUrlConnCacheFail"), e);

}

}

這個(gè)監(jiān)聽(tīng)器是缺省配置的,urlCacheProtection屬性也缺省為true,所以從Tomcat 6.0.24開(kāi)始,文件被鎖定的問(wèn)題就不存在了。

另外需要注意的是,JreMemoryLeakPreventionListener這個(gè)監(jiān)聽(tīng)器只能設(shè)置給Server(Tomcat的頂級(jí)容器),所以u(píng)rlCacheProtection設(shè)置為true的話,對(duì)所有應(yīng)用都會(huì)生效。

總結(jié)

以上是生活随笔為你收集整理的tomcat防cc_浅析Tomcat防止资料被锁的方式的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。