類加載和程序運行是有些關係的,不妨來測試一下。
難度:中級
獨立進程篇
假設有下面的類文件:
// Main.java
package com.github.mccxj.test;
public class Main {
public static void main(String[] args){
new TestServlet().test();
}
}
// TestServlet.Java
package com.github.mccxj.test;
public class TestServlet {
public void test() {
InputStream is = TestServlet.class.getClassLoader().getResourceAsStream("config.properties");
if(is == null){
throw new RuntimeException("couId not found config.properties");
}
}
}
假設目錄結構是這樣的,其中jar下面的表示是在jar包裏邊的內容:
test
-lib
-test.jar
-com/github/mccxj/test/Main.class
-main.jar
-com/github/mccxj/test/TestServlet.class
-config.properties
請問:
- 執行java -cp main.jar;lib/test.jar com.github.mccxj.test.Main會出錯麼?
- 執行java -cp main.jar -Djava.ext.dirs=./lib com.github.mccxj.test.Main結果是怎樣?
繼續調整目錄結果如下:
test
-lib
-test.jar
-com/github/mccxj/test/Main.class
-main.jar
-com/github/mccxj/test/TestServlet.class
-config.properties
再請問
- 執行java -Djava.ext.dirs=./lib com.github.mccxj.test.Main結果是怎樣?
繼續調整一下TestServlet的代碼:
// TestServlet.Java
package com.github.mccxj.test;
public class TestServlet {
public void test() {
- InputStream is = TestServlet.class.getClassLoader().getResourceAsStream("config.properties");
+ InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties");
if(is == null){
throw new RuntimeException("couId not found config.properties");
}
}
}
把目錄結構恢復成:
test
-lib
-test.jar
-com/github/mccxj/test/Main.class
-main.jar
-com/github/mccxj/test/TestServlet.class
-config.properties
請問:
- 執行java -cp main.jar;lib/test.jar com.github.mccxj.test.Main會出錯麼?
- 執行java -cp main.jar -Djava.ext.dirs=./lib com.github.mccxj.test.Main結果又是怎樣?
最後調整目錄結果如下:
test
-lib
-test.jar
-com/github/mccxj/test/Main.class
-main.jar
-com/github/mccxj/test/TestServlet.class
-config.properties
- 執行java -Djava.ext.dirs=./lib com.github.mccxj.test.Main結果是怎樣?
Web應用服務器篇
下面的例子,以tomcat爲例。
假設有下面的Servlet文件,並打包成test.jar:
// TestServlet.java
package com.github.mccxj.test;
public class TestServlet extends HttpServlet {
private static Atomiclnteger al = new AtomicInteger();
private Atomiclnteger a2 = new AtomicInteger();
@Override
public void service(ServletRequest arg0, ServletResponse arg1) throws Servlet Exception, IOException {
System.out.printIn(String.valueOf(al.incrementAndGet()));
System.out.printIn(String.valueOf(a2.incrementAndGet()));
}
}
並部署兩個應用程序appa、appb,在他們的WEB_INF/web.xml添加了下面的內容
<servlet>
<servlet-name>test</servlet-name>
<display-name>test servlet</display-name>
<servlet-class>com.huawei.test.TestServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>test</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
大家應該聽說過Servlet是單例的概念,也可能聽過Web應用服務器有共享類的機制。那麼,請問:
- 現在把test.jar扔到appa和appb的WEB_INF/lib目錄中,啓動tomcat,先訪問/appa/test兩次,再訪問/appb/test, 此時會輸出什麼?
- 繼續把test.jar都移除掉,只添加到TOMCAT_HOME/lib目錄中,啓動tomcat,先訪問/appa/test兩次,再訪問/appb/test, 此時會輸出什麼?
- 最後把test.jar拷貝一份到appa的WEB_INF/lib目錄中,啓動tomcat,先訪問/appa/test兩次,再訪問/appb/test, 此時會輸出什麼?