Mule ESB Http項目轉換爲Tomcat項目(10) 關於日誌問題的補充

在(9)中咱們提到了如何讓ESB項目轉換爲Web項目後日志信息能輸出到控制檯和日誌文件,在繼續研究中,我還發現瞭如下一些問題:java

1. 關於jansi-64.dll的問題。web

log4j2-core庫引用了jansi庫,jansi庫用於在控制檯輸出彩色文字,而這個庫正常使用須要jansi的本地dll文件,而這個文件包含在mule_libs/opt/jline-2.7.jar文件中,當Web項目啓動時,會從這個jar文件中解壓出jansi.dll文件,沒必要拷貝一份到Windows/Systems目錄下,可是這個解壓須要tomcat有一個temp目錄。所以要保證log4j2能正常使用,須要在tomcat根目錄下預先創建一個temp目錄,jansi.dll文件解壓後,會在temp目錄下生成一個名爲jansi-64.dll的dll文件,讓每次使用log4j2時能夠直接引用。apache

2.關於Tomcat對共享jar文件的classpath查找問題。bootstrap

    若是須要部署在Tomcat上的ESB項目比較多,並且這些ESB項目引用了相同的庫文件時,通常咱們會將這些公共的庫文件拷貝到tomcat的一個公共目錄下(例如shared_lib目錄),這樣須要部署的ESB項目war文件將會很小,便於部署和複製,但這樣作也帶來了一個問題,就是Tomcat的Classpath尋找問題。tomcat

    Tomcat在加載一個Web項目時,查找Web項目的ClassPath時,只限於這個Web項目本身的classes目錄和WEB-INF/lib目錄,上文提到的公共共享目錄不在Tomcat尋找的ClassPath中,這樣對日誌輸出帶了了反作用,若是用於輸出日誌的類不在Web項目的classes目錄和WEB-INF/lib目錄下,將不會有這個類的日誌輸出,下面咱們用實例來證實這一點。app

   咱們把Web項目中的全部java代碼抽出成一個公共Java模塊文件CommonModule,編譯成jar,讓Web項目引用。spa

         若是咱們在生成Web項目時在WEB-INF/lib目錄下包含CommonModule jar包時,日誌和(9)
同樣能正常輸出。可是若是咱們把CommoModule.jar包移出Web項目到tomcat的共享目錄。日誌不能正常輸出,這是由Tomcat的ClassLoader加載機制決定的。日誌

      根據Tomcat的ClassLoader加載的庫路徑:code

  • Bootstrap classes of your JVM(JDK自帶的rt.jar)
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
  • System class loader classes (Tomcat自帶的bootstrap.jar、tomcat-juli.jar、commons-deamon.jar)
  • Common class loader classes(包含在Tomcat目錄的lib目錄下的jar文件)

     能夠看出Tomcat默認的ClassLoader並無包含咱們共享的庫目錄,咱們能夠把CommonModule.jar拷貝到Tomcat的lib目錄下,以便Tomcat可以加載這個jar包,更完全的解決方案是引入VirtualWebappLoader.xml

    咱們修改conf/context.xml,在Context節點中加入如下代碼:   

<Loader className="org.apache.catalina.loader.VirtualWebappLoader" virtualClasspath="${catalina.home}/shared_lib/*.jar"/>

    再次啓動Tomcat時CommonModule.jar就能夠被Tomcat加載,日誌能夠正常輸出。

    在設置virtual classpath 時發現了log4j-web jar包與tomcat的衝突。若是virutalclasspath路徑中包含log4j-web的jar包時,啓動時會拋出如下異常

java.io.IOException: java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.web.Log4jServletContainerInitializer to javax.servlet.ServletContainerInitializer
	at org.apache.catalina.startup.WebappServiceLoader.loadServices(WebappServiceLoader.java:206)
	at org.apache.catalina.startup.WebappServiceLoader.load(WebappServiceLoader.java:158)
	at org.apache.catalina.startup.ContextConfig.processServletContainerInitializers(ContextConfig.java:1573)
	at org.apache.catalina.startup.ContextConfig.webConfig(ContextConfig.java:1279)
	at org.apache.catalina.startup.ContextConfig.configureStart(ContextConfig.java:887)
	at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:387)
	at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:117)
	at org.apache.catalina.util.LifecycleBase.fireLifecycleEvent(LifecycleBase.java:90)
	at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5472)
	at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:147)
	at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:899)
	at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:875)
	at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:652)
	at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1260)
	at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:2002)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassCastException: Cannot cast org.apache.logging.log4j.web.Log4jServletContainerInitializer to javax.servlet.ServletContainerInitializer

網上查了一下資料,說是由於Tomcat的Class加載順序致使的,修改了context.xml中ClassLoader的類加載順序(delegate設置爲true)

類加載順序從

  • Bootstrap classes of your JVM
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
  • System class loader classes (described above)
  • Common class loader classes (described above)

變成了     

  • Bootstrap classes of your JVM
  • System class loader classes (described above)
  • Common class loader classes (described above)
  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application

     這樣啓動Tomcat雖然沒有異常拋出,可是CommonModule類也沒有被加載,日誌也沒有正常輸出,目前調查肯定的問題是log4j-web這個jar包在加載時致使的問題,只要在virutalclasspath中不包含log4j-web的jar包,啓動Tomcat就沒有問題。

    此外,在啓動多個ESB改造的Web項目時,還發現一個問題,virutalclasspath裏不能加載太多的jar包,例如mule_libs/mule/*.jar這樣的classpath路徑是不建議的,建議指向具體的jar包,

由於太多不須要的jar包被virutalclasspath加載時,會致使啓動多個Tomcat的Web項目(我實際啓動了20多個項目)時,出現

Error waiting for multi-thread deployment of WAR files to complete
java.util.concurrent.ExecutionException: java.lang.OutOfMemoryError: Metaspace

這是virutalclasspath加載的jar太多,致使分配的Meta space溢出。實際應用時MaxMetaspaceSize不可能像-Xmx設置的那麼大,因此若是沒有特殊要求的前提下,建議virutalclasspath只加載日誌記錄類所在的jar文件。

相關文章
相關標籤/搜索