天天看點

Tomcat打包時多項目共享jar和精确指定jar版本

在産品打包釋出時一個tomcat中如果存在多個war,部署的一般方式是部署到%TOMCAT_HOME%/webapps目錄下,目錄結構遵循J2EE規範,把引用的jar放到%TOMCAT_HOME%/webapps/xxxxx.war/WEB-INF/lib下面即可。但是多個項目完全可能引用了相同的jar,如何使多項目共享這個jar呢?項目釋出時經常由于jar沖突造成很多問題,如果使打出的包精确指定所需要的jar版本呢?如何不放到%TOMCAT_HOME%/webapps目錄,而把war放到特定的位置如何加載呢呢?本文将解決以上幾個問題。

    1.下載下傳tomcat的zip包并解壓,在%TOMCAT_HOME%/conf/Catalina/localhost檔案夾下建立一個lkexample.xml檔案,内容如下:

[html] view plaincopy

<?xml version="1.0" encoding="UTF-8"?>  

<Context docBase="../../apps/lk-example.war">  

    <Loader className="com.tgb.lk.example.dist.ManifestClasspathWebappLoader"/>  

</Context>  

2.将待部署的lk-example.war放到../../apps/lk-example.war下,并将lk-example.war/WEB-INF/lib下的所有jar剪接到../lib下,檔案結構目錄見下圖

3.編寫com.tgb.lk.example.dist.ManifestClasspathWebappLoader.java類并打包為jar

[java] view plaincopy

package com.tgb.lk.example.dist;  

import org.apache.catalina.Container;  

import org.apache.catalina.LifecycleException;  

import org.apache.catalina.core.StandardContext;  

import org.apache.catalina.loader.WebappLoader;  

import java.io.*;  

import java.util.jar.Attributes;  

import java.util.jar.Manifest;  

/** 

* 從War中的MANIFEST.MF獲得類路徑并進行額外加載 

*/  

public class ManifestClasspathWebappLoader extends WebappLoader {  

    public ManifestClasspathWebappLoader() {  

        super();  

    }  

    public ManifestClasspathWebappLoader(ClassLoader parent) {  

        super(parent);  

    @Override  

    protected void startInternal() throws LifecycleException {  

        final Container container = getContainer();  

        if (container instanceof StandardContext) {  

            File baseFile = new File(((StandardContext) container).getRealPath(""));  

            if (baseFile.exists() && baseFile.canRead()) {  //是否可讀  

                if (baseFile.isDirectory()) {     //目錄  

                    final File manifestFile = new File(baseFile, "META-INF/MANIFEST.MF");  

                    if (manifestFile.exists() && manifestFile.canRead() && manifestFile.isFile()) {     //MANIFEST.MF檔案可讀  

                        System.out.println("[DIST] found MANIFEST.MF" + manifestFile);  

                        try {  

                            FileInputStream fileInputStream = new FileInputStream(manifestFile);  

                            setClasspaths(baseFile, fileInputStream);  

                        } catch (FileNotFoundException e) {  

                            e.printStackTrace();  

                        }  

                    }  

                } else if (baseFile.isFile()) { //檔案(war)  

                }  

            }  

        }  

        super.startInternal();  

    /** 

     * 設定MANIFEST.MF流中的類路徑 

     * 

     * @param baseFile 

     * @param inputStream 

     */  

    private void setClasspaths(File baseFile, InputStream inputStream) {  

        String classpaths[] = null;  

        try {  

            final Manifest manifest = new Manifest(inputStream);  

            final Attributes attributes = manifest.getMainAttributes();  

            String classpathValue = attributes.getValue("Class-Path");  

            if (classpathValue != null) {          //可以不為null說明發現Class-Path  

                classpathValue = classpathValue.replaceAll("[\r\n]+$", ""); //移除換行  

                classpaths = classpathValue.split("\\s+");     //拆分類路徑字元串  

        } catch (IOException e) {  

            e.printStackTrace();  

        if (classpaths != null) {   //如果發現類路徑則設定類路徑  

            for (String classpath : classpaths) {  

                addRepository(new File(baseFile.getParent(), classpath).toURI().toString());    //轉換相對路徑為實際路徑并轉換為URI  

            System.out.println("[DIST] " + baseFile.getName() + " append " + classpaths.length + " classpaths.");  

}  

4.将打出的jar包放到%TOMCAT_HONE%\lib下。

5.修改你的war工程的pom.xml,加入如下配置并運作mvn package指令:

<build>  

        <plugins>  

            <plugin>  

                <artifactId>maven-war-plugin</artifactId>  

                <configuration>  

                    <archive>  

                        <manifest>  

                            <addClasspath>true</addClasspath>  

                            <classpathPrefix>../lib/</classpathPrefix>  

                            <useUniqueVersions>false</useUniqueVersions>  

                        </manifest>  

                    </archive>  

                </configuration>  

            </plugin>  

        </plugins>  

    </build>  

觀察打出的war包lk-example.war/META-INF/MANIFEST.MF檔案,這個檔案中打出了war精确引用的jar版本。如下圖:

6.将打出的war包解壓到apps目錄檔案下。

7.運作tomcat即可通路http://localhost:8080/lkexample。

    總結,修改%TOMCAT_HOME%/conf/Catalina/localhost/lkexample.xml指定了tomcat加載的應用以及加載應用時使用的webapp類加載器,通過自己重寫的類加載器ManifestClasspathWebappLoader加載了xxxx.war/META-INF/MANIFEST.MF中精确的jar路徑所引用的jar.如果釋出的項目有多個war可以同時都指定引用lib下精确版本的jar檔案,這樣相同的jar就可以被多個項目使用。若轉載請注明出處!若有疑問,請回複交流!