欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

基于tomcat插件的maven多模块工程热部署(附插件源码) 博客分类: java tomcat插件maven多模块热部署

程序员文章站 2024-02-23 18:44:34
...

从博客园搬家过来,这做为开篇吧。

内容属原创,转载请注明出处

写在前面的话

  最近一直比较纠结,归根结底在于工程的模块化拆分。以前也干过这事,但是一直对以前的结果不满意,这会重操旧业,希望搞出个自己满意的结果。

  之前有什么不满意的呢?

  1. 基于maven拆分模块后,热部署的效果不好,经常出故障。

  2. 对于多个子web工程,不能做到任意一个web工程都可以放到tomcat里运行,要在外面搞个壳子组合多个工程。

  于是,有了这纠结的一周,也有了此文。

本文关于什么

  如标题所言,本文涉及到如下几个内容:

  1. maven多模块工程

  2. 基于tomcat插件的热部署

  且听我一一道来。

 

maven多模块

  这次,采用了如下的结构来构建模块:

  基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署

1. 工具工程

之间的依赖关系相对较多,采用了子模块的方式处理,所有工具工程都是 com.up.tool 下的模块工程。

<modules>
      <module>com.up.tool.a</module>
      <module>com.up.tool.b</module>
</modules>

 

2. 基础工程

  基础工程都放在com.up.base目录里,包含系统的基础框架的内容,但是和具体业务无关。

  所有第三方的依赖以及对工具工程的依赖,都在基础工程里处理。

考虑到war类型的maven工程的依赖传递搞不定,com.up.base工程的packaging采用了jar,同时通过ant脚本另外再打war的内容以及发布。

ant插件打war且发布的脚本:

基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署
基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署
<properties>
      <project.build.finalName>${project.artifactId}-${project.version}</project.build.finalName>
      <respositories.url>http://192.168.1.254:8080/nexus/content/repositories/</respositories.url>
  </properties>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-antrun-plugin</artifactId>
            <version>1.7</version>
            <executions>
                <execution>
                    <id>打包其他文件</id>
                    <phase>package</phase>    
                    <configuration>
                        <target>
                            <mkdir dir="${project.build.directory}/war"/>
                            <copy todir="${project.build.directory}/war" overwrite="true" >
                                <fileset dir="${basedir}/src/main/webapp">
                                     <exclude name="WEB-INF/web.xml"/>
                                </fileset>
                            </copy>
                            <zip destfile="${project.build.directory}/${project.build.finalName}.war">
                                   <fileset dir="${basedir}/target/war">
                                                <exclude name="work/**"></exclude>
                                            </fileset>
                            </zip>
                          <delete dir="${project.build.directory}/war"/> 
                        </target>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <id>install到本地</id>
                    <phase>install</phase>
                    <configuration>
                        <target name="install-ext">
                             <exec executable="cmd.exe" failonerror="true">
                                  <arg value="/c" />
                                  <arg value="mvn" />
                                  <arg value="install:install-file"/>
                                  <arg value="-Dfile=${project.build.directory}/${project.build.finalName}.war" />
                                  <arg value="-DgroupId=${project.artifactId}" />
                                  <arg value="-DartifactId=${project.artifactId}.web" />
                                  <arg value="-Dpackaging=war" />
                                  <arg value="-Dversion=${project.version}" />
                             </exec>
                        </target>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
                <execution>
                    <id>deploy到仓库</id>
                    <phase>deploy</phase>
                    <configuration>
                        <target name="deploy-ext">
                              <condition property="project.deploy.type" value="snapshots" else="releases">
                                  <contains string="${project.version}"  substring="SNAPSHOT" />
                              </condition>
                             <exec executable="cmd.exe" failonerror="true">
                                  <arg value="/c" />
                                  <arg value="mvn" />
                                  <arg value="deploy:deploy-file"/>
                                  <arg value="-Dfile=${basedir}\target\${project.build.finalName}.war" />
                                  <arg value="-DgroupId=${project.artifactId}" />
                                  <arg value="-DartifactId=${project.artifactId}.web" />
                                  <arg value="-Dpackaging=war" />
                                  <arg value="-Dversion=${project.version}" />
                                  <arg value="-Durl=${respositories.url}${project.deploy.type}" />
                                  <arg value="-DrepositoryId=${project.deploy.type}" />
                             </exec>
                        </target>
                    </configuration>
                    <goals>
                        <goal>run</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
 </build>
基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署

 

为了避免版本号到处飞以及引入其他不需要的第三方依赖,对所有依赖的第三方包做了如下处理:

基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署
基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署
<properties>
    <spring.version>3.1.4.RELEASE</spring.version>
</properties>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>3.1.4.RELEASE</version>
            <exclusions>
                <exclusion>
                    <artifactId>*</artifactId>
                    <groupId>*</groupId>
                </exclusion>
            </exclusions>
        </dependency>
    </dependencies>
</dependencyManagement>
基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署

3. 业务工程

都以com.up.web为父工程,同时,依赖基础工程 com.up.base

基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署
基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署
 <parent>
    <groupId>com.up</groupId>
    <artifactId>com.up.web</artifactId>
    <version>1.0.0.1-SNAPSHOT</version>
  </parent>
  <dependencies>
      <dependency>
          <groupId>com.up</groupId>
          <artifactId>com.up.base</artifactId>
          <version>1.0.0.1-SNAPSHOT</version>
      </dependency>
  </dependencies>
  <groupId>com.up.web</groupId>
  <artifactId>com.up.web.a</artifactId>
  <version>1.0.0.1-SNAPSHOT</version>
  <packaging>war</packaging>
基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署

同时,为了避免业务工程打出来的war包里包含依赖的其他的jar/war的内容,在com.up.web工程里做了如下处理:

基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署
基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署
<properties>
      <project.build.finalName>${project.artifactId}-${project.version}</project.build.finalName>
</properties>
<build>
<plugins>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-antrun-plugin</artifactId>
    <version>1.7</version>
    <executions>
        <execution>
            <id>after-package</id>
            <phase>package</phase>
            <goals>
                <goal>run</goal>
            </goals>
            <configuration>
                <tasks>
                    <taskdef resource="net/sf/antcontrib/antcontrib.properties" />
                    <if>
                        <equals arg1="${project.packaging}" arg2="war" />
                        <then>
                            <!-- 备份原来的war -->
                            <move file="${project.build.directory}/${project.build.finalName}.war"
                                tofile="${project.build.directory}/${project.build.finalName}-old.war" />
                            <mkdir dir="${project.build.directory}/war/WEB-INF/classes" />
                            <copy todir="${project.build.directory}/war/WEB-INF/classes"
                                overwrite="true">
                                <fileset dir="${project.build.directory}/classes"></fileset>
                            </copy>
                            <copy todir="${project.build.directory}/war" overwrite="true">
                                <fileset dir="${basedir}/src/main/webapp"></fileset>
                            </copy>
                            <zip destfile="${basedir}/target/${project.build.finalName}.war">
                                <fileset dir="${basedir}/target/war">
                                </fileset>
                            </zip>
                            <delete dir="${basedir}/target/war" />
                        </then>
                    </if>
                </tasks>
            </configuration>
        </execution>
    </executions>
    <dependencies>
        <dependency>
            <groupId>ant-contrib</groupId>
            <artifactId>ant-contrib</artifactId>
            <version>1.0b3</version>
            <exclusions>
                <exclusion>
                    <artifactId>ant</artifactId>
                    <groupId>ant</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>1.4.1</version>
        </dependency>
        <dependency>
            <groupId>org.apache.ant</groupId>
            <artifactId>ant-commons-net</artifactId>
            <version>1.8.1</version>
        </dependency>
    </dependencies>
</plugin>
</plugins>
</build>
基于tomcat插件的maven多模块工程热部署(附插件源码)
            
    
    博客分类: java tomcat插件maven多模块热部署

这样,既保留了可以直接运行的war包,也保证发布到仓库的war包只包含工程自身的内容。

基于tomcat插件的热部署

  上面基本上把项目的多模块结构描述了,接下来该是热部署的事情了,怎么才能达到效果呢?

  寻求方案的痛苦过程不再多说,在看到这篇博文后,把方案定下来了

  参考博文:配合m2eclipse,改造tomcatPluginV321根据maven的依赖自动热部署.

  既然已经有大侠基于这个插件做了支持maven的改造,咱也可以这样干。

  开发环境:

  1. Eclipse Java EE IDE for Web Developers. Version: Luna Release (4.4.0)

  2. tomcat插件 org.uqbar.eclipse.tomcat.xt.features_2.0.0

  3. maven3.2.1

  实现方案:

  1. 基于上面“参考博文”的方式,改造tomcat插件支持配置use Maven

  2. 调整当设置use Maven的时候,设置webRoot为 target/webapp

  3. 启动tomcat前,根据maven依赖的jar以及war,拷贝相应内容到target/webapp并开启监听

     具体为:

     对于依赖的jar,拷贝jar到target/webapp/WEB-INF/lib

     对于依赖的war,解压缩后拷贝到target/webapp

     对于依赖的jar或者是war,如果对应工程在工作空间而且是open状态,那么对target/classes,src/main/webapp 目录增加文件变化监听,实时把修改的内容拷贝到target/webapp下对应目录(文件变化监听基于JNotify实现)

  4. 启动tomcat,docBase为target/webapp

  5. 终止tomcat时,停止文件监听(需要通过插件的终止功能,否则文件监听未停止,可能导致maven clean 失败)

  6. 增加切换工程的功能,点击时切换tomcat里的context为当前选中的工程(只支持一个工程)

  实现效果

  做了上面调整后,达到了如下效果:

  1. 设置了工程为tomcat工程而且选中use Maven后,插件会在启动前拷贝所有通过maven依赖的内容到target/webap

  2. 在工作空间打开而且被当前tomcat运行的工程依赖的工程,修改的内容会实时同步到target/webapp(注意设置tomcat插件里的reloadable为false,即不选中该选项)。

  由于tomcat运行的docBase为target/webapp,当所有修改的内容可以实时拷贝到target/webapp时,也就实现了热部署的效果。

 

问题是什么

  目前的方案有如下问题:

  1. 启动的时候的拷贝,会导致启动tomcat延迟3到4秒。

  2. 如果没通过插件关闭tomcat而是直接通过控制台关闭,会导致文件监听未停止,可能造成maven clean失败。

  3. 要求所有工程的output dir都是 target/classes,要求web的root都是 src/main/webapp 也就是maven的标准配置,否则会有问题。

  4. 插件只支持eclipse4.4,连eclipse4.3都不支持,未追究原因。

 

插件及插件源码下载

org.uqbar.eclipse.tomcat.xt_2.0.0原始插件参见其官方网站