我的 ErrorHandler 上的 Jetty Maven 插件 ClassNotFoundException

Jetty Maven plugin ClassNotFoundException on my ErrorHandler

我已经按照此 reciepe

创建了一个自定义错误处理程序

当我站在我的项目中并执行命令时 ls target/classes/foo/bar/error/MyErrorHandler*

然后显示:target/classes/foo/bar/error/MyErrorHandler.class

我添加了自定义 jetty.xml 内容:

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN" "http://www.eclipse.org/jetty/configure.dtd">

<Configure class="org.eclipse.jetty.server.handler.ContextHandler">
    <Set name="errorHandler">
        <New class="foo.bar.error.MyErrorHandler"/>
    </Set>
</Configure>

这是我的pom.xml

<plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <configuration>
                   <classesDirectory>target/classes</classesDirectory>
                    <httpConnector>
                        <port>9999</port>
                    </httpConnector>
                    <jettyXml>src/test/resources/jetty-errorhandler.xml</jettyXml>
                </configuration>

当我运行mvn jetty:run -X

我收到以下错误:

[DEBUG] parse: file:/home/vagrant/git/seopp/seopp-kunde/src/test/resources/jetty-errorhandler.xml
[DEBUG] parsing: sid=file:/home/vagrant/git/seopp/seopp-kunde/src/test/resources/jetty-errorhandler.xml,pid=null
[DEBUG] resolveEntity(-//Jetty//Configure//EN, http://www.eclipse.org/jetty/configure.dtd)
[DEBUG] Redirected entity http://www.eclipse.org/jetty/configure.dtd --> jar:file:/var/cache/maven_repository/org/eclipse/jetty/jetty-xml/9.2.11.v20150529/jetty-xml-9.2.11.v20150529.jar!/org/eclipse/jetty/xml/configure_9_0.dtd
[WARNING] Config error at <Set name="errorHandler">
        <New class="foo.bar.error.MyErrorHandler"/>
    </Set>
[INFO] Jetty server exiting.

Caused by: java.lang.ClassNotFoundException: foo.bar.error.MyErrorHandler
    at org.codehaus.plexus.classworlds.strategy.SelfFirstStrategy.loadClass(SelfFirstStrategy.java:50)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.unsynchronizedLoadClass(ClassRealm.java:271)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:247)
    at org.codehaus.plexus.classworlds.realm.ClassRealm.loadClass(ClassRealm.java:239)
    at org.eclipse.jetty.util.Loader.loadClass(Loader.java:86)
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.nodeClass(XmlConfiguration.java:364)
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.newObj(XmlConfiguration.java:754)
    at org.eclipse.jetty.xml.XmlConfiguration$JettyXmlConfiguration.itemValue(XmlConfiguration.java:1125)

怎么找不到我的MyErrorHandle文件? 它在我的 target/classes 目录中,路径正确。

我最终让它工作了,尽管我仍然想知道是否存在更好的解决方案。 对我来说,该解决方案似乎与一般的 Maven 插件 class 路径管理更相关,而不是 Jetty 本身。 Maven 插件将其实际定义为插件依赖项的内容添加到它们的 classpath 中。它显然也适用于 Jetty 插件(除非它还实现了一些通过配置启用的其他机制,仍有待发现)。

我创建了一个示例项目并使用了您提供的配置,具有相同的 ClassNotFoundException。我解决了它,将项目本身添加为 Jetty 插件的依赖项(唯一的解决方案?),即提供自定义处理程序的项目 class.

工作 POM 下方:

<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.sample</groupId>
    <artifactId>jetty-error</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <build>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.8.v20150217</version>
                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <webApp>
                        <contextPath>/jetty-error</contextPath>
                    </webApp>
                    <httpConnector>
                        <port>7777</port>
                    </httpConnector>
                    <classesDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/classes</classesDirectory>
                    <jettyXml>src/main/resources/jetty.xml</jettyXml>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.eclipse.jetty</groupId>
                        <artifactId>jetty-util</artifactId>
                        <version>9.2.8.v20150217</version>
                    </dependency>
                    <dependency>
                        <groupId>com.sample</groupId>
                        <artifactId>jetty-error</artifactId>
                        <version>0.0.1-SNAPSHOT</version>
                        <scope>system</scope>
                        <systemPath>${basedir}/lib/jetty-error-0.0.1-SNAPSHOT.jar</systemPath>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

    <dependencies>
        <dependency>
            <groupId>org.eclipse.jetty</groupId>
            <artifactId>jetty-server</artifactId>
            <version>9.2.8.v20150217</version>
        </dependency>
    </dependencies>
</project>

注意:我的包装是 war,但应该没什么区别。在这种情况下,我还为插件依赖使用了一个 system 范围,没关系,这只是为了快速使其工作(我的公司 maven 存储库有问题并且 maven 没有在缓存中查找它首先,但我不想进一步调查,这不是本次练习的目标)。

因此,为了进行快速测试,我临时从项目中创建了一个 jar 并添加到 lib 目录中,但它可以作为构建的一部分轻松自动化(我真的想证明它需要成为 Jetty Maven 插件的一部分而不是 Jetty 服务器的一部分才能通过 jetty:run).

下面是我的简单错误处理程序:

package com.sample.jetty;

import java.io.IOException;
import java.io.Writer;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.handler.ErrorHandler;

public class MyErrorHandler extends ErrorHandler {

    public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
            throws IOException {
        response.getOutputStream().println("error!");
    }

    public void handleErrorPage(HttpServletRequest request, Writer writer, int code, String message)
            throws IOException {
        writer.write("error!");
    }

    public void writeErrorPage(HttpServletRequest request, Writer writer, int code, String message, boolean showStacks)
            throws IOException {
        writer.write("error!");
    }

    public void writeErrorPageHead(HttpServletRequest request, Writer writer, int code, String message)
            throws IOException {
        writer.write("error!");
    }

    public void writeErrorPageBody(HttpServletRequest request, Writer writer, int code, String message,
            boolean showStacks) throws IOException {
        writer.write("error!");
    }

    public void writeErrorPageMessage(HttpServletRequest request, Writer writer, int code, String message, String uri)
            throws IOException {
        writer.write("error!");
    }

    public void writeErrorPageStacks(HttpServletRequest request, Writer writer) throws IOException {
        writer.write("error!");
    }

}

否 class 未发现在您的配置中使用它的异常。我还通过以下码头配置将其设置为全局 (jetty.xml):

<?xml version="1.0"?>
<!DOCTYPE Configure PUBLIC "-//Jetty//Configure//EN"
"http://www.eclipse.org/jetty/configure_9_0.dtd">
<Configure id="Server" class="org.eclipse.jetty.server.Server">

  <Call name="addBean">
    <Arg>
      <New class="com.sample.jetty.MyErrorHandler">
        <Set name="server"><Ref refid="Server" /></Set>
      </New>
    </Arg>
  </Call>
</Configure>

然后输入了错误的地址(即 http://localhost:7777/whatever),然后我从自定义错误处理程序中收到了 error! 消息(有效!)。

所以,结论是:class 必须是插件 classpath 的一部分,因为确实 运行 jetty:run 我们是 运行 Maven 插件。

我上面的示例可以进一步改进(在更标准的 maven approach/folder(即非系统范围)中生成 jar/loading jar;使用多模块 maven 项目,出现错误模块中的处理程序和另一个模块中的 jetty 插件,以便依赖该模块;等等),但原理可能是相同的。这是一项具有挑战性的调查。遗憾的是在线教程和文档对此主题没有太大帮助。