복붙노트

[SPRING] JSR-356 WebSocket @ServerEndpoint와 Spring 3 bean의 통합

SPRING

JSR-356 WebSocket @ServerEndpoint와 Spring 3 bean의 통합

완전히 새로운 JSR-356 WebSockets 지원없이 Spring 3.2.5를 사용하고 있습니다.

Spring 컨텍스트가 아닌 서블릿 컨테이너 자체에 의해 인스턴스화되는 @ServerEndpoint WebSocket 서버에서 싱글 톤 Bean 참조를 갖고 싶습니다.

그것을하는 깔끔한 방법은 무엇입니까?

내 현재 솔루션 : 정적 필드에 인스턴스가있는 @Service 싱글 톤 Bean을 만들었습니다.

@Service
public class WebSocketSupportBean {
    private volatile static WebSocketSupportBean instance = null;

    public static WebSocketSupportBean getInstance() {
        return instance;
    }

    public WebSocketSupportBean() {
        instance = this;
    }

정적 메소드에 의해 @ServerEndpoint를 가져오고, null이 반환되면 사용자 연결을 끊습니다 (서버 시작 중에 Bean이 생성되지 않지만 사용자가 연결하는 경우).

해결법

  1. ==============================

    1.스프링 프레임 워크 3.x로 웹 소켓을 설정할 수 있습니다.

    스프링 프레임 워크 3.x로 웹 소켓을 설정할 수 있습니다.

    스프링 코어 4.0으로 릴리스 된 Rossen Stoyanchev의 SpringConfiguration을 기반으로하는 방법을 보여주기위한 작은 개념 증명 (proof-of-concept) 애플리케이션을 개발했습니다.

    응용 프로그램은 uri / wstest를 사용하여 @Autowired spring bean을 사용하여 인사말 단어를 선택하고 websocket 메시지에 회신하는 websocket 서버 끝점을 설정합니다.

    websocket 연결이 시작되고 웹 소켓을 지원하는 브라우저에서 실행중인 html 페이지 (index.html)가 보내는 메시지입니다.

    엔드 포인트 등록은 컨텍스트 초기화시 ServletContextListener에 의해 이루어지며 엔드 포인트가 인스턴스화되면 스프링으로 연결됩니다.

    @WebListener
    public class MyApplication implements ServletContextListener {
    
        private final static String SERVER_CONTAINER_ATTRIBUTE = "javax.websocket.server.ServerContainer";
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
    
            ServletContext container = sce.getServletContext();
    
            final ServerContainer serverContainer = (ServerContainer) container.getAttribute(SERVER_CONTAINER_ATTRIBUTE);
            try {
                serverContainer.addEndpoint(new MyEndpointConfig(MyEndpoint.class, "/wstest"));
            } catch (DeploymentException e) {
                e.printStackTrace();
            }
        }
    }
    

    엔드 포인트는 다음과 같습니다.

    @Component
    public class MyEndpoint extends Endpoint {
    
        @Autowired
        MyService myService;
    
        @Override
        public void onOpen(Session session, EndpointConfig config) {
    
            session.addMessageHandler(new MyMessageHandler(session));
        }
    
    
        class MyMessageHandler implements MessageHandler.Whole<String> {
    
            final Session session;
    
            public MyMessageHandler(Session session) {
                this.session = session;
            }
    
            @Override
            public void onMessage(String message) {
                try {
                    String greeting = myService.getGreeting();
                    session.getBasicRemote().sendText(greeting + ", got your message (" + message + "). Thanks ! (session: " + session.getId() + ")");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    

    Github 페이지에서 전체 소스를 확인하고 실행할 준비가되었습니다.

  2. ==============================

    2.시험

    시험

    @ServerEndpoint(value = "/ws", configurator = SpringConfigurator.class)
    

    그리고 Maven 종속성을 추가하십시오.

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-websocket</artifactId>
    </dependency>
    
  3. ==============================

    3.@ServerEndpoint 객체를 SpringBeanAutowiringSupport로 확장 할 수 있습니다. 그런 다음 Spring 기반의 웹 애플리케이션 내에서 이런 방식으로 생성 된 bean을 인식하게한다.

    @ServerEndpoint 객체를 SpringBeanAutowiringSupport로 확장 할 수 있습니다. 그런 다음 Spring 기반의 웹 애플리케이션 내에서 이런 방식으로 생성 된 bean을 인식하게한다.

      @PostConstruct
        public void init() {
            SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        }
    

    이렇게하면 @Autowired 주석이 올바르게 작동합니다.

    @Autowired MyService myService;
    
  4. ==============================

    4.이거 해봐, 나에게 효과적이야.

    이거 해봐, 나에게 효과적이야.

    @Component
    @ServerEndpoint(value = "/instantMessageServer",configurator = SpringConfigurator.class)
    public class InstantMessageServer{
    private static IChatService chatService;
        @Autowired
        public InstantMessageServer(IChatService chatService){
            this.chatService = chatService;
        }
        public InstantMessageServer(){}
    }
    

    이 솔루션은 https://spring.io/blog/2013/05/23/spring-framework-4-0-m1-websocket-support에서 찾았습니다. @ServerEndpoint 주석으로 주석 처리 된 클래스는 SpringConfigurator로 httpsession을 얻습니다. 거기에는 메소드 수정 핸들러가 없습니다. SpringConfigurator를 확장하고이 메소드를 재정 의하여 별도의 구성자를 만들 수도 있습니다. Spring-websocket 및 메시징 API를 사용하여 실시간 웹 응용 프로그램을 만드는 것이 좋습니다.

    public class ModifiedServerEndpointConfigurator extends SpringConfigurator{
        @Override
        public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
            HttpSession httpSession = (HttpSession) request.getHttpSession();
            sec.getUserProperties().put(HttpSession.class.getName(),httpSession);
            super.modifyHandshake(sec, request, response);
        }
    }
    
  5. ==============================

    5.스프링 설정에 Bean 정의를 추가해야한다.

    스프링 설정에 Bean 정의를 추가해야한다.

    내가 JSR 356 websocket @ServerEndpoint를 통합하기 위해 찾은 해결책은 스프링 구성에 @Bean을 등록하여 수행 할 수있는 Spring에 의해 WebSocket 끝점에 대한 Servlet 컨테이너의 검색을 해제하는 것입니다. 이 봄까지 webSocket의 일부인 봄 STOMP websocket에 의해 일반 JSR 356 websocket을 대체하지 않습니다.

    @ServerEndpoint(value="/chatMessage")
    public class ChatEndpoint{
    // Normal websocket body goes here.
    }
    

    구성에 Bean을 다음과 같이 추가 :

    @Configuration
    public class WebsocketConfig{
      @Bean
      public ChatEndpoint chatEndpoint(){
         return new ChatEndpoint();
      }
      // main one is ServerEndpointExporter which prevents Servlet container's scan for WebSocket
      @Bean
      public ServerEndpointExporter endpointExporter(){
         return new ServerEndpointExporter();
      }
    }
    

    이 모든 것이 당신을 위해 완료되었습니다. 그러나 @ServerEndpoint에서 configurator = SpringConfigurator.class를 제거해야합니다. 나는 Spring Websocket 4.0.0을 사용하고 있으며 잘 동작한다. 이 링크를 볼 수도 있습니다.

    괜찮 으면 컨셉으로이 링크를 따라 가세요.

    일반적으로 스프링의 기본 구성과는 별도로 websocket 구성을 만들어야합니다.

  6. from https://stackoverflow.com/questions/22435622/integrating-jsr-356-websocket-serverendpoint-with-spring-3-beans by cc-by-sa and MIT license