源码解析springboot中websocketendpoint的初始化及启动过程
参考:
spring boot整合websocket源码解析
org.springframework.web.socket.server.standard.ServerEndpointExporter#registerEndpoints
/**
* Actually register the endpoints. Called by {@link #afterSingletonsInstantiated()}.
*/
protected void registerEndpoints(){
Set<Class<?>> endpointClasses =new LinkedHashSet<>();
String[] endpointBeanNames = BeanNamesForAnnotation(ServerEndpoint.class);
for(String beanName : endpointBeanNames){
endpointClasses.Type(beanName));
}
for(Class<?> endpointClass : endpointClasses){
registerEndpoint(endpointClass);
}
}
private void registerEndpoint(Class<?> endpointClass){
ServerContainer serverContainer =getServerContainer();
serverContainer.addEndpoint(endpointClass);
}
springboot使⽤编程⽅式javax.websocket.server.ServerContainer来部署websocket endpoint
参考websocket-1.1-maintenance-release-final
6.4 Programmatic Server Deployment
When running on the web container, the addEndpoint methods may be called from a
javax.servlet.ServletContextListener provided by the developer and configured in the deployment descriptor of the web application. The websocket implementation must make the ServerContainer instance corresponding to this application available to the developer as a ServletContext attribute registered under the name javax.websocket.server.ServerContainer.
也就是servletContextListener中调⽤addEndPoint⽅法,并将ServerContainer实例作为ServletContext属性可供开发⼈员使⽤,并以“ javax.websocket.server.ServerContainer”名称注册。
可以类⽐tomcat是如何把spring加载起来的,也是spring在servletContextListener中进⾏了注册,在servlet容器创建的时候将⾃⼰加载起来。
public class ServerEndpointExporter extends WebApplicationObjectSupport
implements InitializingBean, SmartInitializingSingleton {
/**
* Return the JSR-356 {@link ServerContainer} to use for endpoint registration.
*/
@Nullable
protected ServerContainer getServerContainer(){
return this.serverContainer;
}
@Override
protected void initServletContext(ServletContext servletContext){
if(this.serverContainer == null){
this.serverContainer =
(ServerContainer) Attribute("javax.websocket.server.ServerContainer");
}
}
}
这⾥是getAttribute(“javax.websocket.server.ServerContainer”),那么是谁set的呢?
想到估计就是spring boot autoconfiguration的
org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration.TomcatWebSocketConfiguration
@Configuration(proxyBeanMethods =false)
@ConditionalOnClass({ Servlet.class, ServerContainer.class})
@ConditionalOnWebApplication(type = Type.SERVLET)
@AutoConfigureBefore(ServletWebServerFactoryAutoConfiguration.class)
public class WebSocketServletAutoConfiguration {
@Configuration(proxyBeanMethods =false)
@ConditionalOnClass({ Tomcat.class, WsSci.class})
static class TomcatWebSocketConfiguration {
@Bean
@ConditionalOnMissingBean(name ="websocketServletWebServerCustomizer")
TomcatWebSocketServletWebServerCustomizer websocketServletWebServerCustomizer(){
return new TomcatWebSocketServletWebServerCustomizer();
}
}
}
之后看WsSci at.websocket.server.WsSci
在init⽅法中new WsServerContainer,也就是在这⾥执⾏的set操作
/**
* Registers an interest in any class that is annotated with
* {@link ServerEndpoint} so that Endpoint can be published via the WebSocket * server.
websocket和socket*/
@HandlesTypes({ServerEndpoint.class, ServerApplicationConfig.class,
Endpoint.class})
public class WsSci implements ServletContainerInitializer {
@Override
public void onStartup(Set<Class<?>> clazzes, ServletContext ctx){
WsServerContainer sc =init(ctx,true);
}
static WsServerContainer init(ServletContext servletContext,
boolean initBySciMechanism){
WsServerContainer sc =new WsServerContainer(servletContext);
servletContext.addListener(new WsSessionListener(sc));
return sc;
}
}
在哪⾥调⽤的WsSci的init⽅法呢?
在tomcat的启动过程中
异步启动WsServerContainer
at.websocket.server.WsContextListener#contextInitialized⽅法
@Override
public void contextInitialized(ServletContextEvent sce){
ServletContext sc = ServletContext();
// Don't trigger WebSocket initialization if a WebSocket Server
// Container is already present
Attribute(Constants.SERVER_CONTAINER_SERVLET_CONTEXT_ATTRIBUTE)== null){
WsSci.ServletContext(),false);
}
}
通过WsSci的init⽅法,创建WsServerContainer
总结来说
1. 在spring boot内嵌的tomcat容器启动的过程中,会异步启动WsServerContainer,执⾏WsSci的init⽅法,创建
WsServerContainer
2. 在spring boot autoconfiguration WebSocketServletAutoConfiguration的时候,就注册TomcatWebSocketConfiguration这个bean到上下
⽂中
3. 于是在实现了ApplicationContextAware的ServerEndpointExporter这个类的initServletContext()⽅法中就可以取到
WsServerContainer
4. 取到这个ServerContainer之后,当endpoint的bean被spring扫描到了,就可以通过调⽤ServerContainer#addEndpoint()⽅法,
通过编程式的⽅法将 我们⾃⼰创建的websocket endpoint暴露并启动起来
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论