测试Maven Web项目
《Maven实战》一书中介绍了jetty-maven-plugin插件的使用。不过,该书写的时候Maven才发布3.0版,而现在已经是3.6版,其“约定优于配置”得到了更进一步发扬。比如对于插件前缀,只要在POM中配置了插件,对于匹配maven-${prefix}-plugin或${prefix}-maven-plugin模式的插件artifact,会自动把匹配到的{perfix}部分作为前缀,所以对于jetty-maven-plugin这个插件来说,就无需在setting.xml中设置,就可以直接使用。
jetty是一个轻量级的servlet的容器,可以独立(Standalone)运行,也可以嵌入(Embedded)运行,而jetty-maven-plugin这个插件就是以嵌入方式运行jetty,并且把当前项目发布到容器里。同样地,tomcat也有maven插件,tomcat的maven插件是区分tomcat主版本的,tomcat6-maven-plugin、tomcat7-maven-plugin、tomcat8-maven-plugin分别运行的是tomcat6、7、8的Embedded版,但是目前没有tomcat9的maven插件。
如果不想用嵌入式容器,或者要用的容器没有对应的maven插件的话(比如tomcat9),就要用《Maven实战》中介绍的cargo-maven2-plugin插件了。cargo的官网地址是https://codehaus-cargo.github.io/,这个插件支持的大多数常用的servlet容器甚至EAR容器。同样,maven现在也能自动匹配cargo-maven2-plugin这个插件的前缀,而无需修改setting.xml文件。可以使用的最小配置如下:
[...]
<build>
<plugins>
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
</plugin>
</plugins>
</build>
[...]
最小配置实际上只是声明了插件,并没有什么配置。配置插件最主要是通过container、configuration配置容器和对容器进行设置。而container里最重要的又是containerId和type,其中:containerId是容器的标记,默认是jetty8x,虽然可以随便命名,但是如果像默认值那么规范的命名,那么剩余的参数大多可以省略,因为插件会根据Id在支持的容器中去查找容器,甚至会自动下载安装。这也是前面的最小配置会自动下载安装jetty8并安装、运行的原因。容器的type有installed、embedded、remote三种,默认是installed,也就是本地安装、嵌入式和远程。remote容器指的是在cargo插件之外启动的容器和后面容器configuration节里的Runtime类型对应,通过配置的deployer进行布署,其运行参数只能用远程容器里的参数,是不可以设置的。
容器的类型installed是指“安装版”,和embedded“嵌入版”对比起来就容易明白了,而并不是已安装的意思。当然,配置为已经安装好的容器也是可以的,这时就要用home指明已安装容器的主目录,如果没有指定,且根据containerId能够解析出是插件支持的哪一个容器软件的话,就会自动去下载。当然,从哪下?下载以后安装(解压)在哪里?可以通过zipUrlInstaller或artifactInstaller指定。不过,如果配置了zipUrlInstaller或artifactInstaller,插件就会忽略home配置。显然zipUrlInstaller用来配置下载zip或tar.gz包,默认的downloadDir是${java.io.tmpdir}/cargo/installs,而artifactInstaller很明显就是下载在maven本地仓库里。它们都有一个extractDir参数指出解压在哪个位置,默认是${project.build.directory}/cargo/installs。另外,zipUrlInstaller或artifactInstaller只对installed类的窗口有效,也就是embedded的容器,没办法控制从哪下,下什么版本的。
需要注意的是插件目标的调用。cargo:start这个命令,从字面上来看,是启动服务的命令,它显然能够启动一个本地已经安装好的容器。并且,如果需要,它还能下载并安装一个。但是,这个命令其实只合适用来启动embedded类型的容器,因为一般的容器会随着父进程的结束而结束,简单的启动是不行的,需要用脚本建立一个守护进程,这显然不是一个插件需要考虑的事情。所以,如果要用cargo来运行一个安装好的容器的话,应该用cargo:run命令,这个命令启动容器后挂起,等待用户按Ctrl+C中止运行,可以进行页面测试,但这里运行mvn插件的命令行窗口就不能再输入别的命令了。所以,如果要反反复复的测试,又不想反反复复的重启容器,就需要用布署(deploy)功能。
对于cargo:deploy、cargo:redeploy、cargo:undeploy这几个命令,它们分别是cargo:deployer-deploy、cargo:deployer-redeploy、cargo:deployer-undeploy的别名,是用来把项目发布到容器中的,发布的目标类型有Standalone、Existing和Runtime三种。其中独立的是指配置是独立的,意思是把运行时配置复制到一个目录,然后发布到这个目录,这样修改配置不会影响已经安装好的容器。默认就是这种方式。缺省配置文件是复制在项目target目录下,由于这个目录会被clean掉,在没有配置的情况下,deploy是不可能成功的。所以,如果项目被clean了,就需要运行cargo:configure从容器的安装目录复制配置,当然,如果用缺省的配置文件目录,得先得有target目录,那么执行maven的顺序应该是package->cargo:configure->cargo:deploy->cargo:run。其中的deploy这个目标倒是会由run自动调用。如果配置方式是Existing的话,就不用configure这个过程了。但是需要配置已经有配置文件的目录通常就是tomcat安装目录。比如:
<configuration>
<!-- Container configuration -->
<container>
<containerId>tomcat9x</containerId>
<home>/Library/apache-tomcat-9.0.24</home>
</container>
<configuration>
<type>existing</type>
<home>/Library/apache-tomcat-9.0.24</home>
</configuration>
并且,由于是发布到容器的安装目录,所以可以用安装的startup.sh启动tomcat,在unix/linux下这个命令启动tomcat之后退出,而tomcat继续运行,这样就可以在同一个命令窗口运行其他命令,而且可以反复发布,缺点就是需要当前用户拥有容器发布目录的写权限。
还可以配置发布目标为Runtime类型,这种发布类型对应前面的Remote类型容器,要求容器已经运行,并且支持远程发布。一般需要用户名密码,对于Tomcat来说,需要修改conf/tomcat-users.xml文件,定义manager-script角色并授予一个用户如:
<role rolename="manager-script"/>
<user username="tomcat" password="s3cret" roles="manager-script"/>
然后像下面这样配置cargo插件
<configuration>
<container>
<containerId>tomcat9x</containerId>
<type>remote</type>
</container>
<configuration>
<type>runtime</type>
<properties>
<cargo.remote.username>tomcat</cargo.remote.username>
<cargo.remote.password>s3cret</cargo.remote.password>
</properties>
</configuration>
</configuration>
这种方法实际最好用,就是第一次要配置Tomcat用户,稍稍复杂了一点。
Remote在这里并不仅仅是“远程”,只要不是通过同一cargo进程启动的容器,包括本机上运行的容器,都算是“远程”。配置Remote布署,有一个