Не удается заставить 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, но это убивает меня, почему я не могу заставить это работать.
Ответы
Ответ 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");