Spring application with embedded jetty can't f

2019-03-11 17:26发布

问题:

I have spring application which uses embedded Jetty instance.

project
   | src
      | controller
      | webapps
          | jsp
          | WEB-INF
              | web.xml
              | applicationContext.xml
              | spring-servlet.xml

my jar has the same tree structure but I keep getting

    d:\test>java -jar springtest.jar
2011-11-22 15:37:02.576:INFO::jetty-7.x.y-SNAPSHOT
2011-11-22 15:37:02.686:WARN::Failed startup of context o.e.j.w.WebAppContext{/,[file:/C:/Users/me/AppData/Local/Temp/jetty-0.0.0.0-8080-webapps-_-any-/webinf
/, jar:file:/d:/test/springtest.jar!/org/jcvi/webapps/]}
java.io.FileNotFoundException: d:\test\org\eclipse\jetty\webapp\webdefault.xml (The system cannot find
the path specified)
        at java.io.FileInputStream.open(Native Method)
        at java.io.FileInputStream.<init>(FileInputStream.java:106)
        at java.io.FileInputStream.<init>(FileInputStream.java:66)
        at sun.net.www.protocol.file.FileURLConnection.connect(FileURLConnection.java:70)
        at sun.net.www.protocol.file.FileURLConnection.getInputStream(FileURLConnection.java:161)
        at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:653)
        at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:186)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:772)
        at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:737)
        at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:119)
        at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1205)
        at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:522)
        at javax.xml.parsers.SAXParser.parse(SAXParser.java:395)
        at org.eclipse.jetty.xml.XmlParser.parse(XmlParser.java:188)
        at org.eclipse.jetty.xml.XmlParser.parse(XmlParser.java:204)
        at org.eclipse.jetty.webapp.Descriptor.parse(Descriptor.java:60)
        at org.eclipse.jetty.webapp.WebDescriptor.parse(WebDescriptor.java:140)
        at org.eclipse.jetty.webapp.MetaData.setDefaults(MetaData.java:141)
        at org.eclipse.jetty.webapp.WebXmlConfiguration.preConfigure(WebXmlConfiguration.java:46)
        at org.eclipse.jetty.webapp.WebAppContext.preConfigure(WebAppContext.java:412)
        at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:448)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:58)
        at org.eclipse.jetty.server.handler.HandlerWrapper.doStart(HandlerWrapper.java:89)
        at org.eclipse.jetty.server.Server.doStart(Server.java:258)
        at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:58)
        at org.jcvi.ServerRunner.startServer(ServerRunner.java:83)
        at org.jcvi.MainServer.main(MainServer.java:18)
2011-11-22 15:37:02.748:INFO::Started SelectChannelConnector@0.0.0.0:8080 STARTING

I have following java class which runs jetty server instance

String webDir = this.getClass().getClassLoader().getResource("webapps").toExternalForm();
Server server = new Server(8080);

WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setResourceBase(webDir);
context.setParentLoaderPriority(true);
HandlerList handlers = new HandlerList();
handlers.setHandlers(new Handler[] { context, new DefaultHandler() });
server.setHandler(context);
server.start();

my web.xml looks like

<welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>spring</servlet-name>
            <servlet-class>
                org.springframework.web.servlet.DispatcherServlet
            </servlet-class>
        <load-on-startup>2</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>spring</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

this application runs fine if I run inside IDE, but it fails with JAR. How can I resolve this issue so that I can have single jar file which has the web application in it?

回答1:

I had a similar problem and I solve it with this main class implementation:

private static final int PORT = 8080;
private static final String WAR_LOCATION = "src/webapps"; //in your case I guess
private static final String CONTEXT_PATH = "/movence"; //change it if you want

public static void main(String[] args) throws Exception {
    Server server = new Server();
    WebAppContext context = new WebAppContext();
    SocketConnector connector = new SocketConnector();

    setupConnector(connector);
    setupContext(server, context);
    setupServer(server, context, connector);
    startServer(server);
}

private static void startServer(Server server) throws Exception, InterruptedException {
    server.start();
    server.join();
}

private static void setupServer(Server server, WebAppContext context, SocketConnector connector) {
    server.setConnectors(new Connector[] { connector });
    server.addHandler(context);
}

private static void setupConnector(SocketConnector connector) {
    connector.setPort(PORT);
}

private static void setupContext(Server server, WebAppContext context) {
    context.setServer(server);
    context.setContextPath(CONTEXT_PATH);
    context.setWar(WAR_LOCATION);
}


回答2:

It seems that jetty's trying to parse the web.xml (descriptor) file, but thinks its in

.../...../...../webdefault.xml

or something like that.

You should explicitly set the web.xml path:

context.setDescriptor("WEB-INF/web.xml"); `

or, assuming that your jar really does include the aformentioned 'project' dir (which isn't standard jar intrernal layout):

context.setDescriptor("project/src/webapps/WEB-INF/web.xml");


回答3:

From @Trein's post, setting the WAR_LOCATION is important. I have seen jetty failing to deploy the web app when this is missing.

Assuming that you are using Jetty to test your app, if you are using Maven POM below is how I test my web app

pom.xml

 <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jetty-servlet-tester</artifactId>
            <version>6.1.22</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>maven-jetty-plugin</artifactId>
            <version>6.1.19</version>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <profiles>
        <profile>
            <id>tomcat</id>
 <build>
        <plugins>
                    <plugin>
                        <groupId>org.mortbay.jetty</groupId>
                        <artifactId>maven-jetty-plugin</artifactId>
                        <version>6.1.22</version>
                        <configuration>
                            <scanIntervalSeconds>10</scanIntervalSeconds>
                            <stopKey>foo</stopKey>
                            <stopPort>9999</stopPort>
                            <contextPath>/</contextPath>
                            <webAppSourceDirectory>src/main/webapp</webAppSourceDirectory>
                            <systemProperties>
                                <systemProperty>
                                    <name>RESOURCE_PATH</name>
                                    <value>${project.build.outputDirectory}</value>
                                </systemProperty>
                            </systemProperties>
                            <connectors>
                                <connector implementation="org.mortbay.jetty.nio.SelectChannelConnector">
                                    <port>9090</port>
                                    <maxIdleTime>60000</maxIdleTime>
                                </connector>
                            </connectors>
                        </configuration>
                        <executions>
                            <execution>
                                <phase>test-compile</phase>
                                <goals>
                                    <goal>run</goal>
                                </goals>
                                <configuration>
                                    <scanIntervalSeconds>0</scanIntervalSeconds>
                                    <daemon>true</daemon>
                                </configuration>
                            </execution>
                            <execution>
                                <id>stop-jetty</id>
                                <phase>package</phase>
                                <goals>
                                    <goal>stop</goal>
                                </goals>
                            </execution>
                        </executions>
                    </plugin>
                </plugins>
            </build>
        </profile>
</profiles>

To run the webapp you can either run mvn jetty:start or run mvn package. This starts the Jetty server on port 9090 and runs the tests (run your http based tests here) and shutdown the server/webapp. If you want to run as standalone webapp, use mvn jetty:start and use your webapp just like any webapp container.

This all assumes you are using Maven. The code above provided by @Trein does the same programatically and the one I provided is the maven configuration equivalent of the above.

Note: You shouldn't worry about webdefault.xml as the default is already packaged in the jetty jar file. You should use your own webdefault.xml only when you need to extend/alter the defaults. There is either something wrong with your Jetty jar (if its reporting this or something to do with your CLASSPATH settings)



回答4:

Found this github project : https://github.com/steveliles/jetty-embedded-spring-mvc

This gives a basic startup template project based on maven. It embedded jetty with spring mvc. Good place to start from scratch or to compare and debug what's wrong with current implementation.

The author has done a nice documentation here : http://steveliles.github.io/setting_up_embedded_jetty_8_and_spring_mvc_with_maven.html



回答5:

Probably a little bit out-dated. However I recently encountered this problem in the context of embedding Jetty in an Eclipse OSGi application using the version of Jetty packaged with Eclipse (Jetty 8.x).

The way I sorted this out is the following :

  1. Get the URL of the webdefault.xml relative to the org.eclipse.jetty.webapp bundle
  2. Pass this URL to the context default descriptor
Bundle bundle = FrameworkUtil.getBundle(WebAppContext.class);
Enumeration<URL> urls = bundle.findEntries("/", "webdefault.xml", true);
String webdefaultURL = urls.nextElement().toExternalForm(); // Should check returned value 
mycontext.setDefaultsDescriptor(webdefaultURL);

Hope it helps

seb



回答6:

Your webdefault.xml (Jetty) is missing:

java.io.FileNotFoundException: d:\test\org\eclipse\jetty\webapp\webdefault.xml

see "What is webdefault.xml?"

If you have a custom location, you need to add it:

context.setDefaultsDescriptor("/my/path/to/webdefault.xml");