Вы когда-нибудь задумывались над тем, почему в Java мы упаковываем веб-приложения в файлы WAR (или структуры каталогов WAR)? Это, безусловно, удобный способ перемещения приложения и его зависимостей из одного места в другое. Но разве не было бы неплохо, если бы все могло оставаться на прежнем месте и не было бы перемещения файлов? Разве не было бы неплохо, если бы вы указали требуемую версию Jetty или Tomcat, как и в случае с любой другой зависимостью? Подход без WAR — это тот, который завоевывает популярность в таких веб-фреймворках Java, как Play! угробить файлы WAR. С помощью стандартных веб-приложений на Java мы также можем отказаться от файлов WAR, просто запустив встроенный сервер Jetty или Tomcat. Давайте попробуем и посмотрим, как все пойдет.
Для этого эксперимента я собираюсь использовать Maven и Jetty. Он по-прежнему будет использовать ту же стандартную исходную структуру для файла WAR ( src / main / java , src / main / webapp и т. Д.). Основное отличие состоит в том, что я на самом деле запускаю Jetty, используя старый добрый статический void main . Это похоже на использование цели jetty: запустить цель, но позволит нам иметь одинаковую точную настройку при разработке и производстве. Статический материал будет в src / main / webapp , скомпилированные классы будут в target / classes, и зависимости будут правильными, если Maven загрузит их. Во-первых, вот небольшой класс Java ( src / main / java / foo / Main.java ), который устанавливает сервер Jetty и запускает его:
package foo;
import java.io.File;
import java.net.URL;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.*;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.webapp.WebAppContext;
public class Main
{
public static void main(String[] args) throws Exception
{
String webappDirLocation = "src/main/webapp/";
Server server = new Server(8080);
WebAppContext root = new WebAppContext();
root.setContextPath("/");
root.setDescriptor(webappDirLocation + "/WEB-INF/web.xml");
root.setResourceBase(webappDirLocation);
root.setParentLoaderPriority(true);
server.setHandler(root);
server.start();
server.join();
}
}
Как видите, Main просто ссылается на каталог webapp, поэтому мне не нужно копировать материал оттуда в другое место. Далее у меня есть небольшой тестовый сервлет ( src / main / java / foo / HelloServlet.java ):
package foo;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.*;
public class HelloServlet extends HttpServlet
{
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
PrintWriter out = resp.getWriter();
out.println("hello, world");
out.close();
}
}
А теперь файл web.xml ( src / main / webapp / WEB-INF / web.xml ):
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>foo.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
И, наконец, файл pom.xml, который определяет Jetty как зависимость и предоставляет простой способ запуска класса Main:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jamesward</groupId>
<version>1.0-SNAPSHOT</version>
<name>warless_java_web_app</name>
<artifactId>warless_java_web_app</artifactId>
<packaging>jar</packaging>
<properties>
<jettyVersion>7.3.1.v20110307</jettyVersion>
</properties>
<dependencies>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jettyVersion}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<version>${jettyVersion}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jettyVersion}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2</version>
<configuration>
<mainClass>foo.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
А теперь просто запустите:
mvn compile exec:java
Maven компилирует мои классы Java в target / classes, а затем цель exec: java запускает Main, который находит другие активы WAR в каталоге src / main / webapp . Если вы следили за этим, сделайте запрос на http: // localhost: 8080 /, чтобы убедиться, что он работает (что должно).
Есть две альтернативы запуску Jetty от Maven. Вы можете использовать плагин Maven appassembler для создания сценариев запуска, содержащих правильные ссылки CLASSPATH, а затем запустить основной класс, используя сгенерированные сценарии. Или вы можете использовать сборку Maven или плагин shade для создания JAR-файла, содержащего приложение и все его зависимости.
Вот пример раздела файла pom.xml для использования плагина appassembler:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<assembleDirectory>target</assembleDirectory>
<generateRepository>false</generateRepository>
<programs>
<program>
<mainClass>foo.Main</mainClass>
<name>main</name>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
Для генерации стартовых скриптов просто запустите:
mvn install
Затем для запуска сценария установите переменную среды REPO в свой репозиторий Maven:
export REPO=~/.m2/repository
А затем просто запустите скрипт:
sh target/bin/main
Весь код для этого примера находится на github.com:
https://github.com/jamesward/warless_java_web_apps
Чтобы сделать все это еще проще, у Jetty есть архетип Maven для генерации всего для вас. Чтобы создать новый проект, содержащий эту настройку, выполните:
mvn archetype:generate -DarchetypeGroupId=org.mortbay.jetty.archetype -DarchetypeArtifactId=jetty-archetype-assembler -DarchetypeVersion=7.5.0-SNAPSHOT
И теперь вы готовы создать веб-приложение Java без войны!
Эта настройка действительно необходимый минимум для обработки запросов к веб-ресурсам и сервлетам, вам нужно будет проделать немного больше работы, если вы хотите добавить поддержку JSP. Узнайте больше об этом в документации Jetty .
Итак … Что вы думаете о веб-приложениях Java без файлов WAR и упаковки WAR? Я хотел бы услышать ваши мысли!