基于tomcat插件的maven多模块工程热部署(附插件源码)
内容属原创,转载请注明出处
写在前面的话
最近一直比较纠结,归根结底在于工程的模块化拆分。以前也干过这事,但是一直对以前的结果不满意,这会重操旧业,希望搞出个自己满意的结果。
之前有什么不满意的呢?
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多模块工程热部署(附插件源码)的更多相关文章
- (一 、上)搭建简单的SpringBoot + java + maven + mysql + Mybatis+通用Mapper 《附项目源码》
最近公司一直使用 springBoot 作为后端项目框架, 也负责搭建了几个新项目的后端框架.在使用了一段时间springBoot 后,感觉写代码 比spring 更加简洁了(是非常简洁),整合工具也 ...
- Eclipse创建Maven多模块工程Module开发(图文教程)
自己研究了下Eclipse用Maven多模块工程Module开发,跟大家分享一下! 功能模块来分Module,跟java的package类似,一般是按照的功能模块分module,比如:sso/cas/ ...
- Spring使用ComponentScan扫描Maven多模块工程的其它模块
说明:在新建好了Maven多模块工程后,如果想要在其它模块也能使用Spring的对象管理,比如@Autowrited这些注入方式,那么就必须开启包扫描的功能才能使其进行注入到Spring的对象管理中. ...
- Maven多模块工程打包指定模块工程方法
Maven多模块工程打包指定模块工程执行如下命令: mvn clean package -pl 指定模块工程名 -am 参数说明: -am --also-make 同时构建所列模块的依赖模块:-am ...
- Maven:Eclipse导入从SVN上检出的Maven多模块工程
大致步骤: 1.从SVN中检出多模块项目,名称随意(Eclipse中可以在[Window ==>>Show View==>>Other==>>SVN==>&g ...
- SpringBoot工程+热部署进行远程调试
本文转载自:https://blog.csdn.net/qq_31868349/article/details/78553901 SpringBoot工程+热部署进行远程调试 本地端添加配置 在pom ...
- 单独编译和使用webrtc音频增益模块(附完整源码+测试音频文件)
webrtc的音频处理模块分为降噪ns和nsx,回音消除aec,回声控制acem,音频增益agc,静音检测部分.另外webrtc已经封装好了一套音频处理模块APM,如果不是有特殊必要,使用者如果要用到 ...
- erlang下lists模块sort(排序)方法源码解析(二)
上接erlang下lists模块sort(排序)方法源码解析(一),到目前为止,list列表已经被分割成N个列表,而且每个列表的元素是有序的(从大到小) 下面我们重点来看看mergel和rmergel ...
- erlang下lists模块sort(排序)方法源码解析(一)
排序算法一直是各种语言最简单也是最复杂的算法,例如十大经典排序算法(动图演示)里面讲的那样 第一次看lists的sort方法的时候,蒙了,几百行的代码,我心想要这么复杂么(因为C语言的冒泡排序我记得不 ...
随机推荐
- 基于 JDK 的动态代理机制
『动态代理』其实源于设计模式中的代理模式,而代理模式就是使用代理对象完成用户请求,屏蔽用户对真实对象的访问. 举个最简单的例子,比如我们想要「FQ」访问国外网站,因为我们并没有墙掉所有国外的 IP,所 ...
- Python和Java编程题(一)
今天偶尔看到一个博客有贴了五十个编程题,决定以后两天左右做一道题 题目来源:http://blog.sina.com.cn/s/blog_60fafdda0100wb21.html 1.题目 一个数如 ...
- CentOS安装Subversion 1.9.*版本客户端
安装yum仓库 以下以CentOS6为例,其他类似 # vim /etc/yum.repos.d/wandisco-svn.rep [WandiscoSVN] name=Wandisco SVN Re ...
- asp.net mvc之自定义WebViewPage
采用Razor引擎的View文件最终都会编译成一个WebViewPage类型, 通过自定义WebViewPage,添加相应的属性和方法,你可以很方便的在View里调用, 自定义WebViewPage只 ...
- [PHP] 数据结构-线性表的顺序存储结构PHP实现
1.PHP中的数组实际上是有序映射,可以当成数组,列表,散列表,字典,集合,栈,队列,不是固定的长度2.数组定义中多个单元都使用了同一个键名,则只使用了最后一个,之前的都被覆盖了3.想要函数的一个参数 ...
- Git 实战手册(一): 批量修改log中的提交信息
本文须知 教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步原文地址 有空就来看看个人技术小站, 我一直都在 背景介绍 事情的起源是这样的:迷恋的谷歌的我最近申请了一个新的 googl ...
- CSS 3D transforms
https://www.creativebloq.com/css3/20-stunning-examples-css-3d-transforms-11112759 https://github.com ...
- loj#2509. 「AHOI / HNOI2018」排列(思维题 set)
题意 题目链接 Sol 神仙题Orz 首先不难看出如果我们从\(a_i\)向\(i\)连一条边,我们会得到以\(0\)为根的树(因为每个点一定都有一个入度,出现环说明无解),同时在进行排列的时候需要保 ...
- 项目启动时发生NOT found
一直想记录一下这个小问题 情景: 我昨晚美滋滋的做完功能,测了测没bug提交到git上之后就屁颠屁颠的回家了,结果今天早上来就失了智,git pull拉了一下代码后,一运行,我去,我的页面呢,页面上直 ...
- 中软高科WEB前端面试题
一个朋友面试的题目,百度了一下这个中软高科貌似是一个培训机构...以下答案是我本人的理解,仅供参考 HTML+CSS 1.你能解释一下css的盒子模型吗? 有两种盒子模型:IE盒子模型,W3C盒子模型 ...