【问题标题】:Can't get Jetty to scan for annotated classes无法让 Jetty 扫描带注释的类
【发布时间】:2012-08-01 21:52:03
【问题描述】:

我有一个带有嵌入式码头服务器的应用程序,我正在像这样启动它(放置在 main() 中并使用 eclipse 启动):

Server server = new Server(port);

WebAppContext context = new WebAppContext();
context.setResourceBase("web/");
context.setDescriptor("web/WEB-INF/web.xml");
context.setConfigurations(new Configuration[]{
            new AnnotationConfiguration(), new WebXmlConfiguration(),
            new WebInfConfiguration(), new TagLibConfiguration(),
            new PlusConfiguration(), new MetaInfConfiguration(),
            new FragmentConfiguration(), new EnvConfiguration()});

context.setContextPath("/");
context.setParentLoaderPriority(true);
server.setHandler(context);
server.start();
server.join();

我的 web.xml 看起来像这样(暂时为空,我不确定是否可以将其完全删除):

<web-app 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    metadata-complete="false"
    version="3.0">
</web-app>

我有一个像这样设置的简单类:

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(urlPatterns={"/test"})
public class TestServlet extends HttpServlet {

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException  {
        request.getRequestDispatcher("/WEB-INF/html/index.html").forward(request,response);
    }
}

当我在 web.xml 中使用传统的 servlet 映射时,我的应用程序运行良好。但是当我删除 web.xml 映射并使用注释时,我只得到 404。它看起来根本不像在扫描注释。控制台如下所示:

2012-08-01 17:40:37.021:INFO:oejs.Server:jetty-8.1.5.v20120716
2012-08-01 17:40:37.227:INFO:oejpw.PlusConfiguration:No Transaction manager found - if your webapp requires one, please configure one.
2012-08-01 17:40:37.294:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/me/project/web/}
2012-08-01 17:40:37.547:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/me/project/web/}
2012-08-01 17:40:37.547:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/me/project/web/}
2012-08-01 17:40:37.547:INFO:oejsh.ContextHandler:started o.e.j.w.WebAppContext{/,file:/Users/me/project/web/}
2012-08-01 17:40:37.641:INFO:oejs.AbstractConnector:Started SelectChannelConnector@0.0.0.0:8080

我已经从我的研究中检查了一些事情:

  • servlet-3.0 jar 在类路径中
  • web.xml 中的元数据完整设置为 false
  • 我确保在 Web 应用上下文中包含 AnnotationConfiguration

我的想法已经用完了,正要恢复到旧的 web.xml,但是为什么我不能让它工作,这让我很生气。

【问题讨论】:

  • Joakim Erdfelt 的回答真的有效吗?
  • 不适合我(Jetty 9.0)。与@user1569803 相同,并且所有依赖项都已到位。我正在研究替代路线。
  • 不幸的是,我无法再访问出现此问题的项目,因此我无法验证我的情况的答案。如果一些老同事尝试解决方案并成功了,我会为他们标记答案。

标签: annotations jetty embedded-jetty


【解决方案1】:

更新:2021 年 6 月

示例项目已更新为与 Jetty 版本无关。

https://github.com/jetty-project/embedded-servlet-server

它现在有特定版本的 Jetty 的分支。

较早的示例项目已存档。

更新:2015 年 6 月

示例项目已针对 Jetty 9 和 Servlet 3.1 进行了更新

见:https://github.com/jetty-project/embedded-servlet-3.1

原答案:

根据您的描述,以及我使用您的代码创建的示例项目,您所做的一切都是正确的。

示例项目:https://github.com/jetty-project/embedded-servlet-3.0

为了使其正常工作,您需要以下内容(仅提及这一点,因为您的问题未包含此详细信息)

  • JDK 1.6+
  • Jetty-webapps jar(+ 依赖项)来自 Jetty 8.1.x(或更高版本)
  • Jetty 8.1.x(或更高版本)的 jetty-annotations jar(+ 依赖项)

仅根据这些有限的要求,您将看到以下依赖项列表。

$ mvn dependency:tree
[INFO] Scanning for projects...
[INFO]                                                                         
[INFO] ------------------------------------------------------------------------
[INFO] Building sample-webapp 1-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] 
[INFO] --- maven-dependency-plugin:2.1:tree (default-cli) @ sample-webapp ---
[INFO] com.company.sample:sample-webapp:war:1-SNAPSHOT
[INFO] +- org.eclipse.jetty.orbit:javax.servlet:jar:3.0.0.v201112011016:provided
[INFO] +- org.eclipse.jetty:jetty-webapp:jar:8.1.5-SNAPSHOT:test
[INFO] |  +- org.eclipse.jetty:jetty-xml:jar:8.1.5-SNAPSHOT:test
[INFO] |  |  \- org.eclipse.jetty:jetty-util:jar:8.1.5-SNAPSHOT:test
[INFO] |  \- org.eclipse.jetty:jetty-servlet:jar:8.1.5-SNAPSHOT:test
[INFO] |     \- org.eclipse.jetty:jetty-security:jar:8.1.5-SNAPSHOT:test
[INFO] |        \- org.eclipse.jetty:jetty-server:jar:8.1.5-SNAPSHOT:test
[INFO] |           +- org.eclipse.jetty:jetty-continuation:jar:8.1.5-SNAPSHOT:test
[INFO] |           \- org.eclipse.jetty:jetty-http:jar:8.1.5-SNAPSHOT:test
[INFO] |              \- org.eclipse.jetty:jetty-io:jar:8.1.5-SNAPSHOT:test
[INFO] \- org.eclipse.jetty:jetty-annotations:jar:8.1.5-SNAPSHOT:test
[INFO]    +- org.eclipse.jetty:jetty-plus:jar:8.1.5-SNAPSHOT:test
[INFO]    |  +- org.eclipse.jetty.orbit:javax.transaction:jar:1.1.1.v201105210645:test
[INFO]    |  \- org.eclipse.jetty:jetty-jndi:jar:8.1.5-SNAPSHOT:test
[INFO]    |     \- org.eclipse.jetty.orbit:javax.mail.glassfish:jar:1.4.1.v201005082020:test
[INFO]    |        \- org.eclipse.jetty.orbit:javax.activation:jar:1.1.0.v201105071233:test
[INFO]    +- org.eclipse.jetty.orbit:javax.annotation:jar:1.1.0.v201108011116:test
[INFO]    \- org.eclipse.jetty.orbit:org.objectweb.asm:jar:3.1.0.v200803061910:test
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 1.771s
[INFO] Finished at: Fri Aug 10 18:17:46 MST 2012
[INFO] Final Memory: 6M/180M
[INFO] ------------------------------------------------------------------------

您很可能只是缺少依赖项或 JDK 要求。

【讨论】:

  • 我遇到了同样的问题,你的回答解决了;我在类路径上缺少 jetty-annotations 并且我没有适当的 Configuration 集(AnnotationConfiguration)。谢谢!
【解决方案2】:

AnntationConfiguration 类通过其scanForAnnotations(WebAppContext) 方法扫描注释。 在方法AnnotationConfiguration 类中扫描以下路径。

  • 容器罐
  • WEB-INF/类
  • WEB-INF/库

因此,如果您希望扫描生产代码中的 servlet 类(即目录 src/main/java 中的源代码),请将生产代码作为 WEB-INF/classes 添加到 WebAppContext 的元数据中。

试试下面的代码,将您的代码添加到WebAppContext 的元数据中。

URL classes = getClass()
        .getProtectionDomain()
        .getCodeSource()
        .getLocation();

WebAppContext context = new WebAppContext();
context.getMetaData()
    .setWebInfClassesDirs(
        Arrays.asList(Resource.newResource(classes)));

【讨论】:

    【解决方案3】:

    我也遇到了同样的问题,但经过多次阅读后,我得到了解决方案!重要提示:请记住在您的构建路径中包含以下 jar:

    jetty-all-9.0.6.v20130930.jar

    jetty-annotations-9.0.6.v20130930.jar

    org.objectweb.asm-3.1.0.v200803061910.jar

    javax.servlet-api-3.0.1.jar

    jetty-plus-9.0.6.v20130930.jar

    public class Main {
    
       public static void main(String[] args) throws Exception {
    
           //Create the server
           Server server = new Server(8080);
    
           ClassList clist = ClassList.setServerDefault(server);
    
           //clist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", "org.eclipse.jetty.plus.webapp.EnvConfiguration",    "org.eclipse.jetty.plus.webapp.PlusConfiguration");
           clist.addBefore(JettyWebXmlConfiguration.class.getName(), AnnotationConfiguration.class.getName());
    
           //Here is the trick to scan current classpath!
           webapp.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", 
                ".*/build/classes/");
    
           webapp.setContextPath("/");
           webapp.setResourceBase("./WebContent");
    
    
           server.setHandler(webapp);
    
           server.start();
           server.join();
    
       }
    
    }
    

    【讨论】:

    • 对我来说,虽然 webapp 变量没有定义,但它可以工作!我让它工作了,因为 webapp 是 org.eclipse.jetty.webapp.WebAppContext 的一个实例
    【解决方案4】:

    基于 Joakim 提供的上一个示例,我上传了一个修改后的版本,该版本支持嵌入式码头中的注释,而无需将项目打包到 war 文件中。该项目已准备好部署到刚刚运行的 Heroku:

    $java -cp target/classes:"target/dependency/*" com.example.Launcher
    

    如果您对细节感兴趣,重要的几行来自 com.example.Launcher:

    context.setConfigurations(new Configuration[] {
                new AnnotationConfiguration(), new WebXmlConfiguration(),
                new WebInfConfiguration(),
                new PlusConfiguration(), new MetaInfConfiguration(),
                new FragmentConfiguration(), new EnvConfiguration() });
    
    // Important! make sure Jetty scans all classes under ./classes looking for annotations. 
    //'Classes' directory is generated running 'mvn package'
    context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*/classes/.*");
    

    您可以根据要扫描注释的类相应地更改 JarPattern。

    这里有完整的例子:https://github.com/pablormier/embedded-jetty-annotations-example

    【讨论】:

    • 行 context.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern",".*/classes/.*");对我来说是关键。只是设置配置不起作用。谢谢。
    【解决方案5】:

    我想出了一种不同的方法,它专门针对 Jetty 和 Spring。我没有让 Jetty 扫描类,而是在自定义 Jetty ServletContextHandlerstartContext() 方法中手动调用 initializer 类。代码如下:

    public class CustomServletContextHandler extends ServletContextHandler {
    
       @Override
       protected void startContext() throws Exception {
    
           SpringServletContainerInitializer initer = new SpringServletContainerInitializer();
    
            HashSet<Class<?>> classes = new HashSet<>();
            // Add annotated classes here such as
            //classes.add(SpringSecurityInitializer.class);
            //classes.add(SpringWebInitilializer.class);
    
            try {
                initer.onStartup(classes, this.getServletContext());
            }catch(Exception e)
            {
                e.printStackTrace();
            }
    
            super.startContext();
        }
    }
    

    然后在创建上下文时,使用自定义处理程序:

     ServletContextHandler ctx = new CustomServletContextHandler();
     ctx.setContextPath("/");
     ...
    

    【讨论】:

      【解决方案6】:

      在我们的例子中,这些行有助于 Jetty 启动代码:

          ClassList cl = Configuration.ClassList.setServerDefault(server);
          cl.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", "org.eclipse.jetty.annotations.AnnotationConfiguration");
      

      【讨论】:

        【解决方案7】:

        你可以

        1. 如果您不需要静态资源,请提供EmptyResource.INSTANCE

        2. 添加 AnnotationConfiguration 并覆盖 scanForAnnotations 方法,将类路径资源添加到 WebAppContext 元数据,可能带有根包的路径以进行扫描

          WebAppContext webapp = new WebAppContext();
              webapp.setContextPath("/");
              webapp.setBaseResource(EmptyResource.INSTANCE);
              webapp.setConfigurations(new Configuration[]{
                      new AnnotationConfiguration(){
                          @Override
                          protected void scanForAnnotations(WebAppContext context) throws Exception {
                              Resource classPathResource =    Resource.newResource(EmbeddedServerApp.class.getResource("/my/learn/jetty/servlet").toURI());
                              context.getMetaData().addContainerResource(classPathResource);
                              super.scanForAnnotations(context);
                          }
                      },
              });
              server.setHandler(webapp);
              server.start();
          

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2012-09-03
          • 2012-10-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-02-17
          相关资源
          最近更新 更多