Грешка Не може да се намери или зареди основният клас

Имам вградено приложение jetty java, което се стартира и обслужва заявки по споменатите маршрути. Докато се тества, работи добре. Сега, когато искам да разположа това java приложение чрез военен файл, това ми създава проблеми.

  1. Докато работи java -jar server--1.0-SNAPSHOT.war: Дава ми грешка като Error: Could not find or load main class com.server.core.App

  2. Това ще дойде, след като бъде коригиран първият проблем, как да се включат всички зависимости във военния файл.

Ето моето pom.xml https://gist.github.com/shadow-fox/24ec2c7d40f4b0e6aae5

<?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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.server</groupId>
    <artifactId>server</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>${jetty-version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-servlet</artifactId>
            <version>${jetty-version}</version>
        </dependency>

        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-util</artifactId>
            <version>${jetty-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-servlet-core</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-server</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.containers</groupId>
            <artifactId>jersey-container-jetty-http</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-moxy</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>org.glassfish.jersey.core</groupId>
            <artifactId>jersey-client</artifactId>
            <version>${jersey-version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>${jackson-version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>${jackson-version}</version>
        </dependency>

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>${jackson-version}</version>
        </dependency>

        <dependency>
            <groupId>org.apache.logging.log4j</groupId>
            <artifactId>log4j-core</artifactId>
            <version>${log4j-version}</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit-version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <jdk-version>1.8</jdk-version>
        <jetty-version>9.3.3.v20150827</jetty-version>
        <jersey-version>2.21</jersey-version>
        <junit-version>4.12</junit-version>
        <jackson-version>2.6.1</jackson-version>
        <log4j-version>2.3</log4j-version>
        <mvn-compiler>3.3</mvn-compiler>
        <mvn-war>2.6</mvn-war>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${mvn-compiler}</version>
                <configuration>
                    <source>${jdk-version}</source>
                    <target>${jdk-version}</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>${mvn-war}</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>lib/</classpathPrefix>
                            <mainClass>com.server.core.App</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

Къде може да съм объркал: ClasspathPrefix не съм сигурен какво да задам тук. Моите класове отиват в target dir по подразбиране (използване на IDEA Intellij). Основният клас съществува на същия път.

App.java

package com.server.core;

import com.server.core.filters.RequestFilter;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.glassfish.jersey.servlet.ServletContainer;

import java.util.EnumSet;

import javax.servlet.DispatcherType;

public class App {

    private static final Logger logger = LogManager.getLogger(App.class);

    public static void main(String[] args) throws Exception {

        Server server = new Server();
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8080);
        server.addConnector(connector);

        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        context.addFilter(RequestFilter.class, "/*", EnumSet.of(DispatcherType.INCLUDE,
                DispatcherType.REQUEST, DispatcherType.ASYNC, DispatcherType.ERROR,
                DispatcherType.FORWARD));
        server.setHandler(context);

        ServletHolder servletHolder = new ServletHolder(ServletContainer.class);
        servletHolder.setInitOrder(0);
        servletHolder.setInitParameter("jersey.config.server.provider.packages", "com/server/core/endpoints");
        context.addServlet(servletHolder, "/*");

        try {
            server.start();
            logger.debug("Server started");
            logger.debug(server);
            server.join();
        } catch (Throwable t) {
            logger.error(System.err);
        } finally {
            server.destroy();
        }
    }
}

Има много въпроси, подобни на този, но не можах да намеря за този случай на употреба.


person Pranaya Behera    schedule 21.09.2015    source източник
comment
Обикновено войната е уеб архив и няма основен клас. Трябва да промените на <packaging>jar</packaging>   -  person Jens    schedule 21.09.2015
comment
Ако направя това, това ми дава Error: A JNI error has occurred, please check your installation and try again Exception in thread "main" java.lang.NoClassDefFoundError: org/eclipse/jetty/server/Connector. Бих искал да направя това във военния файл. Не съм разглеждал каква е разликата между тези две, но ако можете да предоставите някои, това би било полезно.   -  person Pranaya Behera    schedule 21.09.2015
comment
прочетете за плъгина maven shade maven.apache.org/plugins/maven-shade-plugin   -  person Jens    schedule 21.09.2015


Отговори (2)


Самоизпълнима WAR с Jetty е възможна, но е малко трудна за настройка, тъй като различните плъгини на maven са склонни да отменят усилията на Self Executing WAR.

Проектът Jetty поддържа такъв примерен проект.

https://github.com/jetty-project/embedded-jetty-live-war

Ключът е как е сглобен.

Проектът има 4 основни части:

  • /thewebapp/ - това е WAR файлът, уебприложението, както съществува в неговия собствен формат, с нормална maven война и произведен артефакт, който е просто WAR файл, който (все още) не се изпълнява сам.
  • /theserver/ - това е вграденият Jetty сървър jetty.livewar.ServerMain.main(String args[]), който персонализирате, за да инициализира вашия Jetty сървър и неговото WebApp. Този проект също е мястото, където можете да персонализирате за неща като JDBC сървърни библиотеки, JNDI, регистриране и т.н. Този проект създава uber-jar с всички зависимости, необходими за стартиране на сървъра. Обръща се специално внимание с плъгина maven-shade за обединяване на META-INF/services/ файлове.
  • /server-bootstrap/ - това съдържа 2 малки класа, които настройват LiveWarClassLoader от съдържанието в live WAR и след това изпълняват jetty.livewar.ServerMain.main(String args[]) от този нов ClassLoader. Този проект също така съдържа live META-INF/MANIFEST.MF, от който живият WAR ще се нуждае/използва
  • /livewar-assembly/ - това е проектът, който свързва горните 3 проекта в жив/изпълним WAR файл. Артефактите от горните 3 проекта се разопаковат от maven-assembly-plugin и се поставят на място, където ще бъдат най-функционални (и безопасни). Например сървърните класове от /theserver/ се поставят в /WEB-INF/jetty-server/, за да бъдат недостъпни от уеб клиенти, които имат достъп до WAR файла.

Забележка: във вашия нов сглобен WAR файл има 3 файла, за които трябва да знаете, тъй като тези файлове могат да бъдат изтеглени от уеб клиент като статично съдържание, ако използвате тази настройка.

/jetty/bootstrap/JettyBootstrap.class
/jetty/bootstrap/LiveWarClassLoader.class
/META-INF/MANIFEST.MF

Примерният проект е настроен по такъв начин, че информацията, присъстваща в тези зареждащи файлове, не трябва да разкрива лична или чувствителна информация за вашия сървър или неговите операции. Просто Webapp може да се стартира като жив/изпълним WAR файл.

Може да изглежда странно 4 модула да водят до 1 изпълним артефакт, но трябва да разберете, че имате работа с 3 неща, за да настроите тази среда.

  1. Самото WebApp (с всичките му класове и jar) - това е /thewebapp/
  2. Класовете, представляващи основния сървър и неговите изисквания. (да не се смесва с класовете WebApp) - това е /theserver/
  3. Изпълнимият файл Main-Class, който свързва горните 2 заедно интелигентно (за да не създавате проблем със сигурността за себе си) - това е /server-bootstrap/

Последният модул, /livewar-assembly/ просто свързва 3-те части в едно цяло.

Знам, че може да е изкушаващо да използвате maven-shade-plugin за всичко това, но няма да можете да изпълните всички от следните изисквания (можете да изпълните някои от тях и след това да се опитате да коригирате останалите, но в крайна сметка да нарушите другите, играейки безкрайна игра на wack-a-mole) ...

  1. Поставяне на сървърните буркани на място, където те не могат да бъдат достъпни чрез Live WebApp.
  2. Обединяване на сървърната страна (и САМО на сървърната страна) META-INF/services интелигентно.
  3. Добавяне на класовете BootStrap към корена на WAR.
  4. Използване на персонализиран META-INF/MANIFEST.MF, предназначен за първоначалното зареждане (без също така да получавате обединено копие на META-INF/MANIFEST.MF файловете от всички зависимости на сървъра)
person Joakim Erdfelt    schedule 21.09.2015
comment
Добавих един отговор по отношение на jar файл, използвайки maven-shaded-plugin, можете ли да коментирате дали е достатъчно добър. И проблемът е, че сега той създава всички зависимости към classpath, следователно размерът се увеличава значително. - person Pranaya Behera; 21.09.2015
comment
Разгледах хранилището и преди, но не можах да разбера защо има 4 модула, настроени за създаване на един изпълним файл. - person Pranaya Behera; 21.09.2015
comment
Добавен коментар за това. maven-shade-plugin е недостатъчно за постигане на крайната цел, просто не е предназначено да се справи с този вид нюансирано сливане и т.н. - person Joakim Erdfelt; 21.09.2015
comment
Схванах го. Нека да се събера по този начин. Ще публикувам, след като го направя. - person Pranaya Behera; 21.09.2015
comment
По същия начин мога и да буркан? - person Pranaya Behera; 21.09.2015

Актуализация :: Това вече е остаряло. Тъй като продължих с това, което предложи @joakim-erdfelt. Както беше споменато от @Jens в коментарите, промених опаковката от war на jar и използвайки maven-shaded-plugin, мога да стартирам приложението без никакви проблеми. Това е модифицираната версия на pom.xml

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <version>${mvn-shade}</version>
  <executions>
      <execution>
          <phase>package</phase>
          <goals>
              <goal>shade</goal>
          </goals>
          <configuration>
              <filters>
                  <filter>
                      <artifact>*:*</artifact>
                      <excludes>
                          <exclude>META-INF/*.SF</exclude>
                          <exclude>META-INF/*.DSA</exclude>
                          <exclude>META-INF/*.RSA</exclude>
                      </excludes>
                  </filter>
              </filters>
              <transformers>
                  <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                      <mainClass>com.igp.core.App</mainClass>
                  </transformer>
              </transformers>
          </configuration>
      </execution>
  </executions>
</plugin>

Обърнете внимание, че премахнах и maven-jar-plugin от списъка с добавки.

person Pranaya Behera    schedule 21.09.2015