Отсутствует ServletContext в конфигурации CometD (версия 3.1.2) с использованием веб-приложения Spring Boot (версия 1.5.4)

Все работает нормально при использовании учебника для начинающих, описанного в Справочнике CometD. Версии Spring, CometD и Jetty гармонируют друг с другом.

Теперь я (новичок с весенней загрузкой) хочу настроить веб-приложение Spring Boot (версия 1.5.4) с CometD (версия 3.1.2). И я также хочу выполнить настройку с помощью аннотаций без web.xml, как указано здесь.

Для этого я нашел проект github «Livechat», который предоставляет «Пример того, как подготовить WebsocketConfiguration» для CometD в проекте Spring Boot — мне не удалось его запустить.

Все мои попытки не смогли запустить простое загрузочное приложение Spring с аннотированной конфигурацией CometD.

Итак, я прошу помощи в настройке приложения Spring Boot:

  • на основе версии 1.5.4
  • CometD (версия 3.1.2)
  • Работает на обоих: причал 9.x и tomcat (если возможно)
  • Использование аннотаций вместо web.xml

Вот основное исключение, которое я получил во время своих тестов: Missing ServletContext

Caused by: java.lang.IllegalArgumentException: Missing ServletContext
at org.cometd.websocket.server.WebSocketTransport.init(WebSocketTransport.java:60) ~[cometd-java-websocket-javax-server-3.1.2.jar:na]
at org.cometd.server.BayeuxServerImpl.initializeServerTransports(BayeuxServerImpl.java:255) ~[cometd-java-server-3.1.2.jar:na]
at org.cometd.server.BayeuxServerImpl.doStart(BayeuxServerImpl.java:135) ~[cometd-java-server-3.1.2.jar:na]
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) ~[jetty-util-9.4.6.v20170531.jar:9.4.6.v20170531]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_121]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1758) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1695) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624) ~[spring-beans-4.3.9.RELEASE.jar:4.3.9.RELEASE]
... 29 common frames omitted

Веб-приложение.java:

@ComponentScan
@SpringBootApplication
@EnableScheduling
public class WebApplication extends SpringBootServletInitializer implements WebApplicationInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(WebApplication.class);
    }

    public static void main(String[] args) throws Exception {
        SpringApplication.run(WebApplication.class, args);
    }

    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(servletContext);
    }
}

CometDConfiguration.java (как описано в «Справочнике CometD», глава «9.3.3.26. Конфигурация Spring на основе аннотаций»):

@Component
public class CometDConfiguration implements DestructionAwareBeanPostProcessor, ServletContextAware {
    private BayeuxServer bayeuxServer;
    private ServerAnnotationProcessor processor;

    @Inject
    private void setBayeuxServer(BayeuxServer bayeuxServer) {
        this.bayeuxServer = bayeuxServer;
    }

    @PostConstruct
    private void init() {
        this.processor = new ServerAnnotationProcessor(bayeuxServer);
    }

    @Override
    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
        processor.processDependencies(bean);
        processor.processConfigurations(bean);
        processor.processCallbacks(bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String name) throws BeansException {
        return bean;
    }

    @Override
    public boolean requiresDestruction(Object bean) {
        return true;
    }

    @Override
    public void postProcessBeforeDestruction(Object bean, String name) throws BeansException {
        processor.deprocessCallbacks(bean);
    }

    @Bean(initMethod = "start", destroyMethod = "stop")
    public BayeuxServer bayeuxServer() {
        BayeuxServerImpl bean = new BayeuxServerImpl();
//        bean.setOption(BayeuxServerImpl.LOG_LEVEL, "3");
        return bean;
    }

    @Override
    public void setServletContext(ServletContext servletContext) {
        servletContext.setAttribute(BayeuxServer.ATTRIBUTE, bayeuxServer);
    }
}

pom.xml:

<?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.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>war</packaging>

    <name>demo</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.4.RELEASE</version>
        <relativePath /> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
        <cometd-version>3.1.2</cometd-version>
        <jetty-version>9.4.6.v20170531</jetty-version>
    </properties>

    <dependencies>

        <!-- Web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jetty</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!-- JSP and JSTL SUPPORT -->
        <dependency>
                <groupId>javax.servlet</groupId>
                <artifactId>jstl</artifactId>
                <scope>provided</scope>
        </dependency>

        <!-- Cometd dependencies -->
        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>bayeux-api</artifactId>
            <version>${cometd-version}</version>
        </dependency>
        <dependency>
            <groupId>org.cometd.javascript</groupId>
            <artifactId>cometd-javascript-jquery</artifactId>
            <version>${cometd-version}</version>
            <type>war</type>
        </dependency>
        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>cometd-java-server</artifactId>
            <version>${cometd-version}</version>
        </dependency>
        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>cometd-java-websocket-javax-server</artifactId>
            <version>${cometd-version}</version>
        </dependency>
        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>cometd-java-annotations</artifactId>
            <version>${cometd-version}</version>
        </dependency>
        <dependency>
            <groupId>org.cometd.java</groupId>
            <artifactId>cometd-java-oort</artifactId>
            <version>${cometd-version}</version>
        </dependency>

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

        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>apache-jstl</artifactId>
          <version>${jetty-version}</version>
          <type>pom</type>
        </dependency>
        <dependency>
          <groupId>org.eclipse.jetty</groupId>
          <artifactId>apache-jsp</artifactId>
          <version>${jetty-version}</version>
          <type>jar</type>
    </dependency>       

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.25</version>
        </dependency>


    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>

                <configuration>
                    <scanIntervalSeconds>10</scanIntervalSeconds>
                    <webAppConfig>
                        <contextPath>/cometd-primer</contextPath>
                    </webAppConfig>
                </configuration>
            </plugin>
        </plugins>
    </build>


</project>

person eppjo    schedule 04.07.2017    source источник
comment
Удалось воспроизвести, похоже, проблема с порядком инициализации. Я изучаю это, следите за обновлениями.   -  person sbordet    schedule 05.07.2017
comment
См. также: stackoverflow.com/questions/34525337/   -  person sbordet    schedule 06.07.2017
comment
Spring boot запускает встроенный контейнер сервлетов после разрешения инъекций зависимостей bean-компонентов, и поэтому ServletContext еще не доступен. Это отличается от обычного Spring (и документации CometD, на которую вы ссылаетесь), потому что вы обычно запускаете контейнер Servlet и, следовательно, ServletContext before Spring. Я не знаю, есть ли способ сообщить Spring Boot разрешить bean-компоненты после запуска встроенного контейнера сервлетов.   -  person sbordet    schedule 06.07.2017
comment
Большое спасибо за изучение этого. По ссылке выше не было ответа 1,5 года.   -  person eppjo    schedule 07.07.2017
comment
Должен ли я прекратить попытки запустить приложение Spring Boot? Вы видите шанс запустить его? И как могло случиться, что проект livechat, о котором я упоминал в вопросе, смог запустить приложение загрузки Spring с более старой версией Spring, CometD и Jetty?   -  person eppjo    schedule 07.07.2017
comment
На следующей неделе я встречусь с группой экспертов по Spring Boot и дам вам знать, что они скажут. Глядя на исходный код Spring Boot, становится очевидным, что они действительно запускали контейнер после разрешения внедрения зависимостей. Это означает, что вы можете хотя бы запустить CometD в Spring Boot без настройки BayeuxServer в коде (но в web.xml).   -  person sbordet    schedule 09.07.2017
comment
Есть новости по этой теме?   -  person eppjo    schedule 11.08.2017