⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 jiannan.blog.csdn.net/article/details/109641881 「IT贱男」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注**微信公众号:【芋道源码】**有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言将得到认真回复。甚至不知道如何读源码也可以请教噢
  4. 新的源码解析文章实时收到通知。每周更新一篇左右
  5. 认真的源码交流微信群。

一、引言

小编最近接了个成功的服务端项目,在他们项目中集成了一个WebSocket,嗯,其实不难,有很多成功案例。

本文主要来记录一下,如果没有百度在自己的项目启动就抛开一些奇怪的问题,或者有一些奇奇怪怪的问题,靠自己怎么排查问题,另一种引擎去清除所有的问题都能够通过搜索来解决。

除了力,那我们就只剩下:“异常信息、来源、和自己的经验”

项目框架用的是SpringBoot,然后集成WebSocket就行,在集成的过程中,其中有一步需要配置一个Bean。

@Component
public class WsConfig {

@Bean
public ServerEndpointExporter serverEndpointExporter() {
ServerEndpointExporter serverEndpointExporter = new ServerEndpointExporter();
return serverEndpointExporter;
}

}

然后在项目启动的时候抛出了异常信息:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverEndpointExporter' defined in class path resource [org/springblade/modules/hol/config/WsConfig.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1769)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:592)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:514)
at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:321)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:226)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:319)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:199)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:863)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:141)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:744)
at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:391)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:312)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:140)
at org.springblade.core.launch.BladeApplication.run(BladeApplication.java:50)
at org.springblade.Application.main(Application.java:18)
Caused by: java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
at org.springframework.util.Assert.state(Assert.java:73)
at org.springframework.web.socket.server.standard.ServerEndpointExporter.afterPropertiesSet(ServerEndpointExporter.java:107)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1828)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1765)
... 16 common frames omitted

二、问题分析

在类路径资源 [org/springblade/modules/hol/config/WsConfig.class] 中定义名称为“serverEndpointExporter”的 bean 创建错误:调用 init 方法失败;嵌套异常是 java.lang.IllegalStateException: javax.websocket.server.ServerContainer 不可用

通过异常的第一行就可以得知,是在 Spring 创建“serverEndpointExporter”beanW 的时候抛出来的,是这个配置类,原因是:ServerContainer 这个对象不可使用。

抛出异常的类是:AbstractAutowireCapableBeanFactory.java:1769

分析这里就可以得知,是在spring创建serverEndpoint的时候异常了, “那么异常的原因是Exporter ,为什么ServerContainer不可用呢?” 接下来分析

通过点击转换的源码信息:AbstractAutowireCapableBeanFactory.java:1769

protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}

Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}

try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
// 1769 这里就是1769行~~
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

return wrappedBean;
}

通过查看源码,是在1796行的catch里面抛出的异常的,catch是捕捉到invokeInitMethods这个异常的方法,然后才抛出来的,这样就可以开始调试了。

我们是在创建serverendpointExporter的,加一个筛选条件beanName为serverEndpointExporter,这样再过滤创建异常的其他bean。

断点卡好,下调试模式来启动项目,然后F5进到vokeInitMethods,单步往下执行。

最后执行到了 ((InitializingBean) bean).afterPropertiesSet(); 这行代码,bean方法对象是ServerEndpointExporter,调用了这个对象的afterPropertiesSet。

这个ServerEndpointExporterjava类,其中就有在获取serverPropertiesSet方法之后,首先调用这个getServerContainer方法获取serverContainer对象。

很明显这里返回的肯定是null,null != null 结果肯定是false,最后就是这样调用state(false,javax.websocket.server.ServerContainer not available)

通过state源知道,最后抛出这个异常:java.lang.IllegalStateContainerException: javax.websocket.server.server not available

三、解决问题

通过这个文章上面的分析可以确认是因为ServerEndpoint类有一个对象为空的ExserverContainer,所以它会为空。

就需要,服务器容器这个对象是在哪里的,找源头就只有两个地方了,这就好办了。

public class ServerEndpointExporter extends WebApplicationObjectSupport
implements InitializingBean, SmartInitializingSingleton {

@Nullable
private List<Class<?>> annotatedEndpointClasses;

@Nullable
private ServerContainer serverContainer;


// 有一个Set方法可以为serverContainer赋值
public void setServerContainer(@Nullable ServerContainer serverContainer) {
this.serverContainer = serverContainer;
}


@Nullable
protected ServerContainer getServerContainer() {
return this.serverContainer;
}


// 有一个init方法可以为serverContainer赋值
@Override
protected void initServletContext(ServletContext servletContext) {
if (this.serverContainer == null) {
this.serverContainer =
(ServerContainer) servletContext.getAttribute("javax.websocket.server.ServerContainer");
}
}


@Override
public void afterPropertiesSet() {
Assert.state(getServerContainer() != null, "javax.websocket.server.ServerContainer not available");
}
}

通过IDEA的快捷方式,发现没有其他地方调用setServerContainer方法,那么只有init方法了,那么就断点卡在initServletContext方法了。

通过Bebug的能力发现,在从servletContext.getAttribute,根本就没有返回javax.websocket.ServerContainer,就是一个null的时候,结果就产生了异常给serverContainer,所以就产生了异常。

「那为什么javax.websocket.server.ServerContainer会不存在呢?」

这个类,原来是一个接口,那个ServerContainer肯定有的实现类,通过IDEA查看好人,到这个小编大概就明白了这个项目的其他jar包,引发了冲突。

最后到是哪个罐子最后突破了,直接通过IDEA功能就能够定位到,通过maven helper工具定位到maven引用位置,然后移除掉。

一下maven,项目就正常启动啦~~~~~~

四、划重点

本文针对某个异常、或者某个具体问题的另外来进行分析,分享解决这个异常的一个过程。

最开始的小井刚毕业那会,遇到个个,运气就过好,人都踩到这个了,解决这个问题,一时也找不到很多合适的文章,然后能力,然后话就坑了咋知道办。

肯定没有其他人通过自己的问题来解决问题,而且通过自己发现问题的过程来解决自己的问题。

也有很多小伙伴问过小编,学习一些框架源码有什么用?会用不就行了吗?

怎么办呢?真的会说到底怎么办呢,那么你的话,这些奇怪的东西是怎么实现的?深层次的理解。

久而久之之,遇到主动问题,你去摸索的第一个反应自己去百度,会直接为啥子看看的异常情况,分析一下不明的源头,再去学习,进行进行。

就这样不知不觉你的技术会慢慢升华,那个时候感觉就特别明显了。

文章目录
  1. 1. 一、引言
  2. 2. 二、问题分析
  3. 3. 三、解决问题
  4. 4. 四、划重点