将大型*.war文件部署到Tomcat的最佳方法是什么?

11

在开发过程中,我经常需要将一个大的war文件(约45 MB)部署到远程测试服务器上,通常我会使用scp将文件复制到服务器上。

WEB-INF/lib文件夹占据了war文件的最大部分,其中包含了所有必要的库(spring、apache-cxf、hibernate等)。

现在,我正在寻找一种快速且简单的方法来重新部署只更改过的文件。

我如何确定web应用程序真正需要哪些包,因为spring和apache-cxf附带了许多库,我确信我不需要全部。

5个回答

6
当您部署一个.war文件时,Tomcat首先会将该文件解压缩到其webapps目录中,子目录与您的.war同名。
在开发过程中,您显然可以访问您的.class文件、.jar文件、配置文件以及最终进入您的.war的任何其他文件。您可以轻松地确定受到您更改影响的一小部分文件。找出来后,使用脚本或ant任务或其他方法,将这些少量文件直接复制到服务器上的webapps/yourapp目录中。
要查看更改生效,您需要重新启动应用程序。如果Tomcat处于开发模式,则强制重新加载(和重新启动)的一种简单方法是更新WEB-INF/web.xml。因此,让您的部署过程touch该文件或以其他方式更新它,使其具有新的时间戳,scp它也是(最好作为您更新的文件的最后一个),然后您就可以快速轻松地重新加载了。

2
我所做的是从WAR文件中排除WEB-INF/lib/*.jar文件,并在服务器端重新组装。在我的情况下,这将60MB的WAR缩减到250k,从而实现了快速部署。 <exclude name="**/lib/*.jar"/>命令用于排除jar文件(请参见ANT构建的最后一个代码片段)。
在服务器端,很容易从修剪过的WAR文件中组装出完全填充的WAR:
1. 解压缩/展开由下面的ANT脚本创建的修剪过的WAR。 2. 将服务器存储库jar文件复制到展开的WEB-INF/lib目录中。 3. 将所有内容压缩成一个新的(大型)WAR文件。 4. 像往常一样部署。
例如:
unzip ../myapp.trimmed.war
mkdir WEB-INF/lib
cp ../war_lib_repository/* WEB-INF/lib
zip -r ../myapp.war .

也许不是最优雅的解决方案,但可以节省频繁部署大型WAR文件的时间。我希望能够通过Maven来实现这一点,如果有人有建议,请告诉我。
ANT build.xml:
<property file="build.properties"/>
<property name="war.name" value="myapp.trimmedwar"/>
<property name="deploy.path" value="deploy"/>   
<property name="src.dir" value="src"/>
<property name="config.dir" value="config"/>
<property name="web.dir" value="WebContent"/>
<property name="build.dir" value="${web.dir}/WEB-INF/classes"/>
<property name="name" value="${war.name}"/>

<path id="master-classpath">
    <fileset dir="${web.dir}/WEB-INF/lib">
        <include name="*.jar"/>         
    </fileset>
    <!-- other classes to include -->
    <fileset dir="${birt.runtime}/ReportEngine/lib">
        <include name="*.jar"/>
    </fileset>
    <pathelement path="${build.dir}"/>
</path> 

<target name="build" description="Compile main source tree java files">
    <mkdir dir="${build.dir}"/>
    <javac destdir="${build.dir}" debug="true" deprecation="false" optimize="false" failonerror="true">
        <src path="${src.dir}"/>
        <classpath refid="master-classpath"/>
    </javac>
</target>

<target name="createwar" depends="build" description="Create a trimmed WAR file (/lib/*.jar) excluded for size">
    <!-- copy the hibernate config file -->
    <copy todir="${web.dir}/WEB-INF/classes">
        <!-- copy hibernate configs -->
        <fileset dir="${src.dir}/" includes="**/*.cfg.xml" />
    </copy>     
    <copy todir="${web.dir}/WEB-INF/classes">
        <fileset dir="${src.dir}/" includes="**/*.properties" />
    </copy>             
    <!-- copy hibernate classes -->
    <copy todir="${web.dir}/WEB-INF/classes" >
        <fileset dir="${src.dir}/" includes="**/*.hbm.xml" />
    </copy>
    <war destfile="${name}.war" webxml="${web.dir}/WEB-INF/web.xml">
        <fileset dir="${web.dir}">
            <include name="**/*.*"/>
            <!-- exlude the jdbc connector because it's on the server's /lib/common -->
            <exclude name="**/mysql-connector*.jar"/>
            <!-- exclude these jars because they're already on the server (will be wrapped into the trimmed war at the server) -->
            <exclude name="**/lib/*.jar"/>
        </fileset>
    </war>
    <copy todir="${deploy.path}" preservelastmodified="true">
        <fileset dir=".">
            <include name="*.war"/>
        </fileset>
    </copy>
</target>           


1

在Rori Stumpf的答案基础上进行改进,这是一个针对“瘦身”操作的Gradle任务。

war {
    archiveName "v1.war"
}

task createThinWar(type: Copy) {
    dependsOn 'war'

    def tmpFolder = "${buildDir}/tmp/thin"
    def outputDir = "${buildDir}/libs"

    // Extract the war (zip) contents
    from zipTree("${outputDir}/v1.war")
    into "${tmpFolder}/v1"

    doLast {
        // Extracting the war third party libraries to a separate dir
        ant.move(file: "${tmpFolder}/v1/WEB-INF/lib", tofile: "${tmpFolder}/v1-libs")

        // Zip the third party libraries dir
        ant.zip(destfile: "${outputDir}/v1-libs.zip") {
            fileset(dir: "${tmpFolder}/v1-libs")
        }

        // Finally zip the thinned war back
        ant.zip(destfile: "${outputDir}/v1-thin.war") {
            fileset(dir: "${tmpFolder}/v1")
        }
    }
}

这将生成 v1-thin.war(不到1mb),以及一个库的压缩包。
将薄型war部署到服务器上(并在那里重建库),并在修改版本/添加库时部署库的zip文件。

1
我使用rsync将本地机器上的.war复制到生产环境。通常可以提供大量加速,约为8-10倍。
另一个选择是使用git存储.war文件。当你git push一个新的.war时,只有差异会被传输。这也是一个很大的加速。有些人说git不适合存储大文件,它会变慢并且不能很好地工作。事实上,是的,仓库会增长很多,但在某些情况下,这可能是一个很好的选择。
一些数据:我的.war大约为50MB,当我部署新版本时,它只复制了约4MB而不是上传完全新的war。无论是使用git还是rsync都可以达到这个效果。 更新: 我遇到的问题是,当Git仓库有几个.war版本时,它将永远无法克隆,因为需要创建所有增量并将其传输到客户端。
我改变了策略,通过上传 .war 文件到 Dropbox。Dropbox 也使用了一种类似于 rsync 的方法,只复制增量。从服务器上,我使用 wget 命令下载 .war 文件并重新部署应用程序。希望这可以帮到你。

rsync 速度非常快!只需要几秒钟,而不是我的应用程序需要的 5-7 分钟。调试速度与本地机器一样快。非常感谢! - no id

0

我认为没有更快的方法来重新部署WAR文件中的更改。

如果您以展开的方式部署,您可以查看哪些文件时间戳已更改并相应地采取行动,但您将不得不编写代码来执行此操作。

我不知道OSGi是否能在这里提供帮助。这将允许您将问题分成更独立和可交换的模块。

只是好奇:

  1. 现在需要多长时间?
  2. 您是否使用持续集成来构建和部署?

我最大的问题是上传到远程服务器的时间,部署本身运行快且干净。由于Web应用程序所依赖的庞大而复杂的子系统,我只能在远程服务器上测试整个Web应用程序。 - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接