Подтвердить что ты не робот

Не удается заставить Jetty отсканировать аннотированные классы

У меня есть приложение со встроенным сервером причала, которое я запускаю так (помещается в 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. Но когда я удаляю сопоставления web.xml и использую аннотации, я получаю только 404s. Это не похоже на просмотр аннотаций вообще. Консоль выглядит так:

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 [email protected]:8080

Некоторые вещи, которые я проверил уже из моих исследований:

  • Сервлет-3.0 jar находится в пути к классам
  • набор метаданных - false в web.xml
  • Я включил функцию AnnotationConfiguration в контексте веб-приложения.

У меня закончились идеи, и я собираюсь вернуться к старому web.xml, но это убивает меня, почему я не могу заставить это работать.

4b9b3361

Ответ 1

Обновление: июнь 2015

Пример проекта обновлен для 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-аннотации jar (+ зависимости) от Jetty 8.1.x(или новее)

Только из этих ограниченных требований вы увидите следующий список зависимостей.

$ 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.

Ответ 2

AnntationConfiguration класс сканирует аннотации с помощью метода scanForAnnotations(WebAppContext). В методе AnnotationConfiguration класс сканирует следующий путь.

  • контейнерные контейнеры
  • WEB-INF/классы
  • WEB-INF/LIBS

Итак, если вы хотите, чтобы ваши классы сервлетов в вашем производственном коде (т.е. источники в каталоге src/main/java) были отсканированы, добавьте ваш производственный код в метаданные WebAppContext как WEB-INF/classes.

Попробуйте приведенный ниже код, чтобы добавить код в метаданные WebAppContext.

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

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

Ответ 3

У меня была такая же проблема, но после многих чтений я получил решение! ВАЖНО: не забудьте указать в своем пути сборки следующие банки:

Причал-все-9.0.6.v20130930.jar

мол-аннотаций-9.0.6.v20130930.jar

org.objectweb.asm-3.1.0.v200803061910.jar

javax.servlet-апи-3.0.1.jar

причал-плюс-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();

   }

}

Ответ 4

Основываясь на предыдущем примере, представленном Joakim, я загрузил измененную версию, которая поддерживает аннотации во встроенном причале без упаковки проекта в военный файл. Этот проект готов к развертыванию только в 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

Ответ 5

Я придумал другой подход, довольно специфичный для Jetty и Spring. Вместо того, чтобы сканировать Jetty для классов, я вручную вызывал классы initializer в startContext() методе настраиваемого Jetty ServletContextHandler. Код выглядит следующим образом:

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");