在开发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均已经改变。