考察對類加載的理解(問題篇)

類加載和程序運行是有些關係的,不妨來測試一下。
難度:中級

獨立進程篇

假設有下面的類文件:

// 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

請問:

  1. 執行java -cp main.jar;lib/test.jar com.github.mccxj.test.Main會出錯麼?
  2. 執行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

再請問

  1. 執行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

請問:

  1. 執行java -cp main.jar;lib/test.jar com.github.mccxj.test.Main會出錯麼?
  2. 執行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
  1. 執行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應用服務器有共享類的機制。那麼,請問:

  1. 現在把test.jar扔到appa和appb的WEB_INF/lib目錄中,啓動tomcat,先訪問/appa/test兩次,再訪問/appb/test, 此時會輸出什麼?
  2. 繼續把test.jar都移除掉,只添加到TOMCAT_HOME/lib目錄中,啓動tomcat,先訪問/appa/test兩次,再訪問/appb/test, 此時會輸出什麼?
  3. 最後把test.jar拷貝一份到appa的WEB_INF/lib目錄中,啓動tomcat,先訪問/appa/test兩次,再訪問/appb/test, 此時會輸出什麼?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章