maven打造可執行war包(超詳細)
在開發java Web時,有時我們會使用嵌入式jetty來執行,專案完成後,如果能夠直接執行war包從而啟動jetty來執行war包那就非常完美了,本文將講解如何在專案中整合jetty 9,並構造可執行的war包(打包前和打包後都能隨時啟動)。
1.首先新增jetty 9的依賴(本文暫時只用到了jetty的以下依賴,讀者根據自己的專案需要增加)
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version >9.2.7.v20150116</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>9.2.7.v20150116</version>
</dependency>
2.專案中使用jetty 9。
首先我封裝了自己的JettyServer
public class EmbeddedServer {
//public static final Logger logger = LoggerFactory.getLogger(EmbeddedServer.class);
// private static final int DEFAULT_BUFFER_SIZE = 16192;
protected final Server server = new Server();
public EmbeddedServer(int port,String path) throws IOException{
this(port,path,false,null );
}
/**
* use war to start
* @param port
* @param isWar
* @param warPath
* @throws IOException
*/
public EmbeddedServer(int port,boolean isWar,String warPath) throws IOException{
this(port,null,isWar,warPath);
}
private EmbeddedServer(int port, String path,boolean isWar,String warPath) throws IOException {
Connector connector = getConnector(port);
server.addConnector(connector);
WebAppContext application = getWebAppContext(path,isWar,warPath);
server.setHandler(application);
server.setStopAtShutdown(true);
}
protected WebAppContext getWebAppContext(String path,boolean isWar,String warPath) {
WebAppContext application;
if(isWar){
application=new WebAppContext();
application.setWar(warPath);
return application;
}else{
application = new WebAppContext(path, "/");
application.setConfigurationDiscovered(true);
application.setParentLoaderPriority(true);
application.setClassLoader(Thread.currentThread().getContextClassLoader());
return application;
}
}
protected Connector getConnector(int port) throws IOException {
HttpConfiguration http_config = new HttpConfiguration();
// this is to enable large header sizes when Kerberos is enabled with AD
//final int bufferSize = getBufferSize();
//http_config.setResponseHeaderSize(bufferSize);
//http_config.setRequestHeaderSize(bufferSize);
ServerConnector connector = new ServerConnector(server, new HttpConnectionFactory(http_config));
connector.setPort(port);
connector.setHost("0.0.0.0");
server.addConnector(connector);
return connector;
}
/*protected Integer getBufferSize() {
try {
Configuration configuration = ApplicationProperties.get();
return configuration.getInt("sysimple.jetty.request.buffer.size", DEFAULT_BUFFER_SIZE);
} catch (Exception e) {
// do nothing
}
return DEFAULT_BUFFER_SIZE;
}*/
public void start() throws Exception {
server.start();
//logger.info("********************************************************");
//logger.info("The SySimple Has Started !!!");
server.join();
}
public void stop() {
try {
server.stop();
} catch (Exception e) {
//logger.warn("Error during shutdown", e);
}
}
}
接著可以使用封裝好的EmbeddedServer來啟動war
public class StartWeb{
private static EmbeddedServer embeddedServer;
public static void main(String[] args){
//Start web server
int port=3000;
try{
if(args.length==0){
//該方式能夠在開發時快速啟動
embeddedServer=new EmbeddedServer(port, "src/main/webapp");
}else{
//傳入war包的路徑,該方法能夠在打包完成後啟動該war包
embeddedServer=new EmbeddedServer(port, true, args[0]);
}
embeddedServer.start();
}catch(Exception e){
System.exit(0);
}
}
}
注意:打包後如果需要啟動war包,需要使用如下的這種批處理命令來啟動:
以批處理命令(start.bat)和server.war在同級目錄下為例:(以下是start.bat的內容)
@echo off
set bat_dir=%~dp0
java -jar %bat_dir%/web.war %bat_dir%/web.war
讀者可以考慮在程式碼中得到war包的路徑,這樣可以在啟動時省去傳參。
- 下面是最重要的:使用Maven構建可執行war包
總的來說可執行war包是將war包的結構仿照jar包的結構進行改變,第一個是需要在manifest中標記出主方法,第二個是編譯後的程式碼(包,而非.class)必須放在war包的最外層,最後要能夠找到專案的依賴。
①標記主方法
通過maven-war-plugin在manifest中標記主方法入口
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>org.bit.linc.web.commons.StartWeb</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
②拷貝(也可以移動)web的所有的程式碼到war包最外層(使用maven-antrun-plugin)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<id>main-class-placement</id>
<phase>prepare-package</phase>
<configuration>
<target>
<copy todir="${project.build.directory}/${project.artifactId}/">
<fileset dir="${project.build.directory}/classes/">
<include name="**/*.*" />
</fileset>
</copy>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
③ 標記所有依賴的位置(將程式碼拷貝到war最外層後,會出現依賴的類都找不到的情況,因此需要讓war包能夠查詢到這些依賴)
將maven-war-plugin更改為如下內容:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>org.bit.linc.web.commons.StartWeb</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>WEB-INF/lib</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
現在可以構建可執行war包了。
以筆者的專案為例: 構建的war包中META-INF/MANIFEST.MF會變成如下內容:
Manifest-Version: 1.0
Built-By: wubo
Build-Jdk: 1.7.0_17
Class-Path: WEB-INF/lib/commons-0.0.2.jar WEB-INF/lib/commons-configur
ation-1.8.jar WEB-INF/lib/commons-lang-2.6.jar WEB-INF/lib/commons-lo
gging-1.1.1.jar WEB-INF/lib/slf4j-api-1.7.7.jar WEB-INF/lib/slf4j-log
4j12-1.7.7.jar WEB-INF/lib/log4j-1.2.17.jar WEB-INF/lib/plugins-0.0.2
.jar WEB-INF/lib/clusters-0.0.2.jar WEB-INF/lib/monitors-0.0.2.jar WE
B-INF/lib/jetty-server-9.2.7.v20150116.jar WEB-INF/lib/javax.servlet-
api-3.1.0.jar WEB-INF/lib/jetty-http-9.2.7.v20150116.jar WEB-INF/lib/
jetty-util-9.2.7.v20150116.jar WEB-INF/lib/jetty-io-9.2.7.v20150116.j
ar WEB-INF/lib/jetty-webapp-9.2.7.v20150116.jar WEB-INF/lib/jetty-xml
-9.2.7.v20150116.jar WEB-INF/lib/jetty-servlet-9.2.7.v20150116.jar WE
B-INF/lib/jetty-security-9.2.7.v20150116.jar WEB-INF/lib/gson-2.3.1.j
ar
Created-By: Apache Maven 3.3.9
Main-Class: org.bit.linc.web.commons.StartWeb
Archiver-Version: Plexus Archiver
其中的Class-Path和Main-Class均已經改變。