今日在練習使用Spring Boot WebSocket建立一個簡單的聊天室網頁時,在啟動時出現SimpMessageSendingOperations
的bean無法注入的錯誤如下。
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2019-04-27 17:06:38.044 ERROR 8864 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :
***************************
APPLICATION FAILED TO START
***************************
Description:
Field messagingTemplate in idv.matt.demo.listener.WebSocketEventListener required a bean of type 'org.springframework.messaging.simp.SimpMessageSendingOperations' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type 'org.springframework.messaging.simp.SimpMessageSendingOperations' in your configuration.
原因是我在一個自訂用來監聽WebSocket事件的WebSocketEventListener
類別中使用@Autowired
注入SimpMessageSendingOperations
的實例時,在Spring Boot啟動時發現找不到可注入的bean的情況而造成此錯誤。
WebSocketEventListener
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.event.EventListener;
import org.springframework.messaging.simp.SimpMessageSendingOperations;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.messaging.SessionConnectedEvent;
import org.springframework.web.socket.messaging.SessionDisconnectEvent;
@Component
public class WebSocketEventListener {
@Autowired
private SimpMessageSendingOperations messagingTemplate; // 注入時出現錯誤
@EventListener
public void handleWebSocketConnectListener(SessionConnectedEvent event) {
...
}
@EventListener
public void handleWebSocketDisconnectListener(SessionDisconnectEvent event) {
...
}
}
最後發現是Spring Boot啟動時並沒有對掛有@EnableWebSocketMessageBroker
並實作WebSocketMessageBrokerConfigurer
介面的WebSocketConfig
類別進行掃描(此類別負責配置STOMP的訊息代理及WebSocket的end point)。因為我把@Configuration
錯寫成@Configurable
了,所以Spring Boot啟動過程掃描要註冊為bean的類別時忽略了此類別,所以在WebSocketEventListener
要注入成員變數SimpMessageSendingOperations
的bean時發生上述找不到bean的錯誤。
WebSocketConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.simp.config.MessageBrokerRegistry;
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
@Configuration // 原本錯寫成@Configurable,導致Spring Boot不掃描此配置類別
@EnableWebSocketMessageBroker
public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
...
}
@Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
...
}
}
TL;DR
SimpMessageSendingOperations
的實例SimpMessagingTemplate
是在AbstractMessageBrokerConfiguration.brokerMessagingTemplate()
中產生。
@EnableWebSocketMessageBroker
實際上匯入了DelegatingWebSocketMessageBrokerConfiguration
的配置,
而DelegatingWebSocketMessageBrokerConfiguration
繼承了WebSocketMessageBrokerConfigurationSupport
,
WebSocketMessageBrokerConfigurationSupport
繼承了AbstractMessageBrokerConfiguration
,
而AbstractMessageBrokerConfiguration.brokerMessagingTemplate()
則是一個掛有@Bean
,用來宣告bean的方法。
AbstractMessageBrokerConfiguration
public abstract class AbstractMessageBrokerConfiguration implements ApplicationContextAware {
...
@Bean
public SimpMessagingTemplate brokerMessagingTemplate() {
SimpMessagingTemplate template = new SimpMessagingTemplate(brokerChannel());
String prefix = getBrokerRegistry().getUserDestinationPrefix();
if (prefix != null) {
template.setUserDestinationPrefix(prefix);
}
template.setMessageConverter(brokerMessageConverter());
return template;
}
...
}
參考:
沒有留言:
張貼留言