Skip to main content

用jetty6和maven2启动,调试web应用

maven1的日子里对付web应用我一般的做法是用maven-appserver-plugin在项目的target目录里搭建只给当前项目开发用的 tomcat实例,通过配置maven-war-plugin, 可以把程序部署到这个tomcat实例里。调试时因为tomcat实例已经存在了,只要确定tomcat的bootstrap包在classpath里, 就可以在IDE里很容易的启动tomcat的实例。这个流程一旦配置好了很容易用,所以在过去的三年里我启动,调试web应用时都是这样做的。

maven2 里我一直在找类似的做法,可appserver插件没有了,war插件工作起来也不太一样,assembly最终必须产成一个文件,tomcat插件则是 通过tomcat的admin webapp把war热部署到运行的tomcat上,不容易调试。最终我决定试一试maven2的jetty插件。

jetty-maven-plugin是org.codehaus.mojo的子项目,还没有发布过什么稳定的版本,几个maven2 repository里也都没有,所以只能从svn上拿到源码手工安装。mojo项目源码在这里有 介绍。奇怪的是codehaus上各项目svn的位置这几天扑朔迷离, 公布的url经常无效。按照文档配置了maven-war-plugin和maven-jetty-plugin后(主要是设web.xml的位置),在 项目里执行 mvn clean compile war:war jetty:run-war, 报错说log4j找不到。log4j在pom.xml里有年头了,很多别的插件都在用它,这个错误没什么道理。

在maven2 repository里看到了jetty6的插件。这是一个和jetty插件,mojo项目无关的插件,是jetty6项 目里的一个子项目。与其把jetty插件里log4j的问题搞定,还不如试一试这个最新的东西。从codehaus svn上拿下jetty项目的源码,进入modules/maven-plugin, maven package install这个plugin。 在项目的pom.xml中做如下配置(这个修改最终可以放到这些web应用的父pom里去)


<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>${basedir}/src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty6-plugin</artifactId>
<version>6.0-SNAPSHOT</version>
<configuration>
<goalPrefix>jetty6</goalPrefix>
<contextPath>/app</contextPath>
</configuration>
</plugin>
</plugins>
</build>


在项目下执行mvn jetty6:run, 居然程序很顺利的跑起来了。

下一个要解决的问题是调试。调试和上面的配置以及maven2没关系。jetty6的启动是用org.mortbay.jetty:start包。在maven2的dependency里加入如下两个包:


<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty</artifactId>
<version>6.0.0beta7</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>start</artifactId>
<version>6.0.0beta7</version>
<scope>test</scope>
</dependency>


scope是test因为他们的存在只是为了测试,这两个包最终是不会跑到war里的。main类是org.mortbay.start.Main, 带一个参数,参数是jetty的配置xml文件。此物在这里有详细介绍。我只是从jetty6项目考了一个到自己项目的src/test里,这样就可以在IDE里启动了。程序参数是jetty.xml, 主类是org.mortbay.start.Main。 jetty文件的内容如下

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC
"-//Mort Bay Consulting//DTD Configure//EN"
"http://jetty.mortbay.org/configure_1_2.dtd">
<Configure class="org.mortbay.jetty.Server">
<Set name="ThreadPool">
<New class="org.mortbay.thread.BoundedThreadPool">
<Set name="minThreads">20</Set>
<Set name="maxThreads">100</Set>
</New>
</Set>
<Set name="connectors">
<Array type="org.mortbay.jetty.Connector">
<Item>
<New class="org.mortbay.jetty.bio.SocketConnector">
<Set name="port">8080</Set>
<Set name="maxIdleTime">50000</Set>
</New>
</Item>
</Array>
</Set>
<Set name="handlers">
<Array type="org.mortbay.jetty.Handler">
<Item>
<New class="org.mortbay.jetty.webapp.WebAppContext">
<Set name="contextPath">/app</Set>
<Set name="war">./src/main/webapp</Set>
<Get name="SessionHandler">
<Set name="SessionManager">
<New class="org.mortbay.jetty.servlet.HashSessionManager" />
</Set>
</Get>
</New>
</Item>
</Array>
</Set>
<Set name="stopAtShutdown">true</Set>
<Call name="start" />
</Configure>


参考


Comments

Popular posts from this blog

Spring, Angular and other reasons I like and hate Bazel at the same time

For several weeks I've been trying to put together an Angular application served Java Spring MVC web server in Bazel. I've seen the Java, Angular combination works well in Google, and given the popularity of Java, I want get it to work with open source. How hard can it be to run arguably the best JS framework on a server in probably the most popular server-side language with  the mono-repo of planet-scale ? The rest of this post walks through the headaches and nightmares I had to get things to work but if you are just here to look for a working example, github/jiaqi/angular-on-java is all you need. https://github.com/jiaqi/angular-on-java Java web application with Appengine rule Surprisingly there isn't an official way of building Java web application in Bazel, the closest thing is the Appengine rule  and Spring MVC seems to work well with it. 3 Java classes, a JSP and an appengine.xml was all I need. At this point, the server starts well but I got "No ...

Customize IdGenerator in JPA, gap between Hibernate and JPA annotations

JPA annotation is like a subset of Hibernate annotation, this means people will find something available in Hibernate missing in JPA. One of the important missing features in JPA is customized ID generator. JPA doesn't provide an approach for developer to plug in their own IdGenerator. For example, if you want the primary key of a table to be BigInteger coming from sequence, JPA will be out of solution. Assume you don't mind the mixture of Hibernate and JPA Annotation and your JPA provider is Hibernate, which is mostly the case, a solution before JPA starts introducing new Annotation is, to replace JPA @SequenceGenerator with Hibernate @GenericGenerator. Now, let the code talk. /** * Ordinary JPA sequence. * If the Long is changed into BigInteger, * there will be runtime error complaining about the type of primary key */ @Id @Column(name = "id", precision = 12) @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XyzIdGenerator") @SequenceGe...

Project Euler problem 220 - Heighway Dragon

This document goes through a Java solution for Project Euler problem 220 . If you want to achieve the pleasure of solving the unfamiliarity and you don't have a solution yet, PLEASE STOP READING UNTIL YOU FIND A SOLUTION. Problem 220 is to tell the coordinate after a given large number of steps in a Dragon Curve . The first thing came to my mind, is to DFS traverse a 50 level tree by 10^12 steps, during which it keeps track of a direction and a coordinate. Roughly estimate, this solution takes a 50 level recursion, which isn't horrible, and 10^12 switch/case calls. Written by a lazy and irresponsible Java engineer, this solution vaguely looks like: Traveler traveler = new Traveler(new Coordinate(0, 0), Direction.UP); void main() { try { traverse("Fa", 0); } catch (TerminationSignal signal) { print signal; } } void traverse(String plan, int level) { foreach(char c:plan) { switch(c) { case 'F': traveler.stepForward(); break; ca...