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

写在前面的话

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

  之前有什么不满意的呢?

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

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

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

本文关于什么

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

  1. maven多模块工程

  2. 基于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且发布的脚本:

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

结合ant插件发布额外war包

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

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

避免版本号到处飞以及屏蔽无用依赖

3. 业务工程

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

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

业务工程的基本配置

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

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

基于ant插件重新打war包

这样,既保留了可以直接运行的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原始插件参见其官方网站

修改后的插件及源码

基于tomcat插件的maven多模块工程热部署(附插件源码)的更多相关文章

  1. (一 、上)搭建简单的SpringBoot + java + maven + mysql + Mybatis+通用Mapper 《附项目源码》

    最近公司一直使用 springBoot 作为后端项目框架, 也负责搭建了几个新项目的后端框架.在使用了一段时间springBoot 后,感觉写代码 比spring 更加简洁了(是非常简洁),整合工具也 ...

  2. Eclipse创建Maven多模块工程Module开发(图文教程)

    自己研究了下Eclipse用Maven多模块工程Module开发,跟大家分享一下! 功能模块来分Module,跟java的package类似,一般是按照的功能模块分module,比如:sso/cas/ ...

  3. Spring使用ComponentScan扫描Maven多模块工程的其它模块

    说明:在新建好了Maven多模块工程后,如果想要在其它模块也能使用Spring的对象管理,比如@Autowrited这些注入方式,那么就必须开启包扫描的功能才能使其进行注入到Spring的对象管理中. ...

  4. Maven多模块工程打包指定模块工程方法

    Maven多模块工程打包指定模块工程执行如下命令: mvn clean package -pl  指定模块工程名 -am 参数说明: -am --also-make 同时构建所列模块的依赖模块:-am ...

  5. Maven:Eclipse导入从SVN上检出的Maven多模块工程

    大致步骤: 1.从SVN中检出多模块项目,名称随意(Eclipse中可以在[Window ==>>Show View==>>Other==>>SVN==>&g ...

  6. SpringBoot工程+热部署进行远程调试

    本文转载自:https://blog.csdn.net/qq_31868349/article/details/78553901 SpringBoot工程+热部署进行远程调试 本地端添加配置 在pom ...

  7. 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件)

    webrtc的音频处理模块分为降噪ns和nsx,回音消除aec,回声控制acem,音频增益agc,静音检测部分.另外webrtc已经封装好了一套音频处理模块APM,如果不是有特殊必要,使用者如果要用到 ...

  8. erlang下lists模块sort(排序)方法源码解析(二)

    上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...

  9. erlang下lists模块sort(排序)方法源码解析(一)

    排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...

随机推荐

  1. C#读取Cookie

    public class HttpCookie { [DllImport("wininet.dll", CharSet = CharSet.Auto, SetLastError = ...

  2. 大数据技术之_08_Hive学习_04_压缩和存储(Hive高级)+ 企业级调优(Hive优化)

    第8章 压缩和存储(Hive高级)8.1 Hadoop源码编译支持Snappy压缩8.1.1 资源准备8.1.2 jar包安装8.1.3 编译源码8.2 Hadoop压缩配置8.2.1 MR支持的压缩 ...

  3. The Mac App Store isn't working. How to fix?

    Q. The Mac App Store isn't working. How to fix? First you must have built-in Ethernet at 'en0'. So, ...

  4. C#新功能--命名参数

    命名参数会潜在的改变编写代码的方式.这个新功能能使代码更容易阅读和理解. 例如,看一下System.IO名称空间中的File.Copy()方法,它一般构建为 File.Copy(@"C:\m ...

  5. 解决SQL Server 2008安装时提示:重新启动计算机 失败

    a.重启机器,再进行安装,如果发现还有该错误,请按下面步骤: b.在开始->运行中输入regedit c.到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet ...

  6. c# 获取客户端文件

    /// <summary> /// 获取有效客户端文件控件集合,文件控件必须上传了内容,为空将被忽略, /// 注意:Form标记必须加入属性 enctype="multipar ...

  7. 第一篇 Spring boot 配置文件笔记

    spring boot 不需要配置太多文件程序便可正常运行,特殊情况需要我们自己配置文件. 项目以IDEA写实例,系统会默认在src/main/java/resources目录下创建applicati ...

  8. MATLAB indexing question

    Question: I have a matrix, for example A = [ 1 2 3; 4 5 6; 7 8 9] ; and a vector of size 1x3 which s ...

  9. What are the differences between struct and class in C++?

    Question: This question was already asked in the context of C#/.Net. Now I'd like to learn the diffe ...

  10. Nginx学习笔记(二)--- 配置虚拟主机

    Linux下安装Nginx  https://www.cnblogs.com/dddyyy/p/9780705.html 1.虚拟主机介绍 一台服务器分成多个"独立"的主机,每台虚 ...