Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

spring-boot-starter-websocket doesn't work in standalonemode #1722

Closed
BigMichi1 opened this issue Oct 16, 2014 · 3 comments
Closed

spring-boot-starter-websocket doesn't work in standalonemode #1722

BigMichi1 opened this issue Oct 16, 2014 · 3 comments
Assignees
Labels
type: documentation A documentation update
Milestone

Comments

@BigMichi1
Copy link
Contributor

I have an application defined this way:

@ComponentScan
@Configuration
@EnableAutoConfiguration
public class Application extends SpringBootServletInitializer {
    private static final Class<Application> APPLICATION_CLASS = Application.class;

    public static void main(final String[] args) {
        SpringApplication.run(APPLICATION_CLASS, args);
    }

    @Override
    protected SpringApplicationBuilder configure(final SpringApplicationBuilder application) {
        return application.sources(APPLICATION_CLASS);
    }
}

and a ServerEndpoint:

@ServerEndpoint(value = "/websocket")
public class WebSocketTest {
    private static Set<Session> clients = Collections.synchronizedSet(new HashSet<Session>());

    @OnMessage
    public void onMessage(String message, Session session) throws IOException {
        synchronized (clients) {
            for (Session client : clients) {
                if (!client.equals(session)) {
                    client.getBasicRemote().sendText(message);
                }
            }
        }
    }

    @OnOpen
    public void onOpen(Session session) {
        clients.add(session);
    }

    @OnClose
    public void onClose(Session session) {
        clients.remove(session);
    }
}

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>websocket</groupId>
    <artifactId>websocket</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.2.0.M1</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-websocket</artifactId>
        </dependency>
    </dependencies>

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

now when i run this war as a standalone application i am unable to connect to the websocket, when i deploy this war to a standalone tomcat connection can be successfull established. there seems to be something missing in the embedded configuration when using websockets in standalone mode

@wilkinsona
Copy link
Member

Tomcat uses a ServletContainerInitializer to find classes annotated with @ServerEndpoint. Spring Boot doesn't support ServerContainerInitializerswhen you're using an embedded web container (see #321 for more details).

You need to make all of your endpoints Spring beans and use Spring's ServerEndpointExporter instead. Unfortunately, there's a bug that stops the exporter from working out-of-the-box with Spring Boot. There's a workaround, however. Add the following bean to Application:

    @Bean
    public ServletContextAware endpointExporterInitializer(final ApplicationContext applicationContext) {
        return new ServletContextAware() {
            @Override
            public void setServletContext(ServletContext servletContext) {
                ServerEndpointExporter exporter = new ServerEndpointExporter();
                exporter.setApplicationContext(applicationContext);
                exporter.afterPropertiesSet();
            }
        };
    }

@wilkinsona wilkinsona added this to the 1.1.9 milestone Oct 16, 2014
@wilkinsona wilkinsona added the type: documentation A documentation update label Oct 16, 2014
@wilkinsona
Copy link
Member

I've seen this a few times now. At the least we should document the behaviour difference and what to do in the embedded case.

@wilkinsona
Copy link
Member

I've now realised that the workaround is only viable as long as you're not trying to use ServerEndpointConfig beans. ServerEndpointExporter needs to be exposed as a Bean in the application context for that to work as they're processed as part of ServerEndpointExporter's implementation of the BeanPostProcessor contract

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: documentation A documentation update
Projects
None yet
Development

No branches or pull requests

2 participants