Embedded Jetty : how to use a .war that is include

2019-05-01 19:41发布

I'm trying to generate a .jar containing a main() that would start Jetty.

My problem is that I'd like the .war that Jetty loads to be included in the same .jar.

I've been able to create the .jar containing the .war with :

In the POM.xml :

<plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.3</version>
    <configuration>
        <finalName>myApp</finalName>
        <appendAssemblyId>false</appendAssemblyId>
        <archive>
            <manifest>
                <mainClass>com.myApp.Server</mainClass>
            </manifest>
        </archive>
        <descriptors>
            <descriptor>src/main/resources/executable-jar-assembly.xml</descriptor>
        </descriptors>
    </configuration>
    <executions>
        <execution>
            <id>make-my-jar-with-dependencies</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
        </execution>
    </executions>
</plugin>

executable-jar-assembly.xml :

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">

<id>jar-with-dependencies-and-war</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
    <dependencySet>
        <outputDirectory>/</outputDirectory>
        <useProjectArtifact>false</useProjectArtifact>
        <unpack>true</unpack>
        <scope>runtime</scope>
    </dependencySet>
</dependencySets>
<fileSets>
    <fileSet>
        <directory>target/classes/</directory>
        <outputDirectory>/</outputDirectory>
    </fileSet>
    <fileSet>
        <directory>target/</directory>
        <includes>
            <include>
                myApp.war
            </include>
        </includes>
        <outputDirectory>/</outputDirectory>
    </fileSet>
</fileSets>

The code to set the war in Jetty :

handler.setWar("myApp.war");

... I also tried :

URL res = Server.class.getResource("myApp.war");
handler.setWar(res.toExternalForm());

... and :

URL res = Thread.currentThread().getContextClassLoader().getSystemResource("myApp.war");
handler.setWar(res.toExternalForm());

But nothing works!

Using that last example code to start Jetty, the server seems to start correctly but no requests work. The configuration is obviously wrong.

I know there are some workarounds to make a .war itself executable, but I'd like to make the ".war inside the .jar" work.

Any idea how the .war should be configured?

2条回答
走好不送
2楼-- · 2019-05-01 20:00

I have tried like you with a war file inside the jar but jetty seemed to serve me a directory listing with the war file as the only entry, which I found weird... Not sure if I've done something wrong there...

I have found that exploding the war file in a directory inside the jar file seemed to work for me so far. I may unearth some weird things later on but until I do, I'll stick with it.

查看更多
Explosion°爆炸
3楼-- · 2019-05-01 20:08

I played with this a lot in 2009-10 for a specific app.

The problem I found is that when you have a war embedded within a jar, the URIs can end up being ones that do not work with the default jar: uri handler trying to access the war file.

There are a number of solutions that I found:

  1. Tell jetty to extract/explode the war file into a temporary directory

  2. Implement your own URI handler (that was an interesting exercise, but if you need to support the code yourself, I would not recommend doing that)

  3. Make the war file an executable war file, e.g. the same type of trick used by Jenkins. To do this you overlay the jetty server classes and your main class with the war file. Then you just point jetty to the jar file itself as the war file. Jetty does not care that the filename does not end in .war

All three worked for me on Jetty 7. I suspect that the situation will remain the same.

In the end I opted for option 3. It works out as the simplest, does not leave temporary files on the users system, and is quickest to start up.

查看更多
登录 后发表回答