我们知道tomcat可以通过maven启动,执行类似如下的命令,就可以启动一个tomcat服务了。
mvn tomcat7:run
参见 《maven 配置tomcat插件启动》
如果我们也想像tomcat一样,用maven直接启动自己的应用服务,应该怎么做呢?这就是我这两天在折腾的问题。实现这个想法,需要具体几个条件。
-
自定义maven插件
tomcat实现在maven启动,其实是通过执行
org.apache.tomcat.maven:tomcat7-maven-plugin
插件来实现的,上面mvn tomcat7:run
命令其实是插件的简写。
所以如果要实现自定义的应用服务用maven启动,就是要实现一个类似的插件,将自己的服务启动操作放在插件中执行,关于开发自定义插件的基本知识不是本文的重点。
**注意:**自定义插件的pom.xml
中package
类型应该定义为<packaging>maven-plugin</packaging>
-
发布到仓库
有了自定义插件,当然要把它发布到仓库(maven中央仓库,或自己的私服)才能被maven找到。这个部分不是本文重点,可以在网上找到很多的文章介绍如何发布插件。
自定义maven插件听上去是个好高大上的东西,其实并不复杂,只要继承org.apache.maven.plugin.AbstractMojo
实现execute
抽象方法,就完成了一个最简单的插件。
以下是我的项目中用到的启动自定义服务的一个简单插件实现,其中的Main
类是服务入口:
RunMojo.java
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import net.gdface.facelog.service.Main;
/**
* maven 插件<br>
* 执行facelog服务启动,等同于命令行执行{@link Main#main(String[])}
*
* @author guyadong
*
*/
@Mojo(name = "run", requiresProject = false)
public class RunMojo extends AbstractMojo {
/**
* Set this to true to allow Maven to continue to execute after invoking the
* run goal.
*
*/
@Parameter(property = "maven.facelog.fork", defaultValue = "false")
private boolean fork;
public RunMojo() {
}
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
// 调用应用服务入口方法启动服务
Main.main(null);
if (!fork) {
waitIndefinitely();
}
}
/**
* Causes the current thread to wait indefinitely. This method does not
* return.
*/
private void waitIndefinitely() {
Object lock = new Object();
synchronized (lock) {
try {
lock.wait();
} catch (InterruptedException e) {
getLog().warn("RunMojo.interrupted", e);
}
}
}
}
上面这个插件非常简单,只定义一个有默认值的fork
参数,只是简单的调用了Main.main()
方法去启动服务。但作为一个启动服务的插件,在写法上还是与普通插件有些不同:
- 请注意在类的注释中有
requiresProject = false
,是指该插件可以不依赖特定项目运行,简单的说就是不需要在maven 项目的文件夹下执行,可以在任何位置执行。因为我们会在非开发环境使用该插件来启动服务所以这里必须指定为false
, - 上面的代码中在调用了
main
方法启动服务后,还调用了waitIndefinitely
方法故意让当前线程进行无限等待。因为一般来说,应用服务都是异步启动的,服务启动后主线程调用就直接返回了,会导致主线程execute
方法会立即返回,maven调用结束,服务也就自动结束啦!所以这里要用waitIndefinitely
方法阻止主线程结束。
tomcat插件也是这么干的,
waitIndefinitely
方法的代码就是从tomcat7-maven-plugin
插件的源码中直接抄过来的。
为什么主线程结束后,maven会不等服务线程结束就结束插件运行我也没搞明白,这应该涉及到mave调用插件的机制没有详细研究