illegalstateexception是什么异常_异常源码分析—告诉你学习“源码”究竟有什么用!...
點(diǎn)擊上方“服務(wù)端思維”,選擇“設(shè)為星標(biāo)”
回復(fù)”669“獲取獨(dú)家整理的精選資料集
回復(fù)”加群“加入全國(guó)服務(wù)端高端社群「后端圈」
一、引言
最近接了個(gè)相當(dāng)于外包的項(xiàng)目,在他們項(xiàng)目中集成一個(gè)WebSocket的服務(wù)端,嗯功能其實(shí)不難,但是前方有坑。
本文主要來(lái)記錄一下,如果沒(méi)有了百度,在項(xiàng)目啟動(dòng)就拋異常、或者一些奇奇怪怪的問(wèn)題,靠自己怎么去排查問(wèn)題,同樣有時(shí)候并不是所有的問(wèn)題都能夠通過(guò)搜索引擎來(lái)解決。
除了外力,那我們就只剩下:異常信息、源碼、和本身經(jīng)驗(yàn)。
項(xiàng)目框架用的是SpringBoot,然后集成WebSocket就行,在集成的過(guò)程中,其中有一步需要配置一個(gè)Bean。
@Component
public class WsConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
ServerEndpointExporter serverEndpointExporter = new ServerEndpointExporter();
return serverEndpointExporter;
}然后在項(xiàng)目啟動(dòng)的時(shí)候拋出了異常信息:
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二、問(wèn)題分析
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
通過(guò)異常的第一行就能夠得知,是在Spring創(chuàng)建“serverEndpointExporter”bean的時(shí)候拋出來(lái)的,是這個(gè)WsConfig類,原因是:ServerContainer這個(gè)對(duì)象不可使用。
拋出異常的類是:AbstractAutowireCapableBeanFactory.java:1769
分析到這里就能夠得知,是在spring創(chuàng)建serverEndpointExporter的時(shí)候異常了,那么異常的原因是什么呢?,為什么ServerContainer不可用呢??接著分析
通過(guò)控制臺(tái)點(diǎn)擊到對(duì)應(yīng)的源碼信息如下:AbstractAutowireCapableBeanFactory.java:1769
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction) () -> {
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;
}通過(guò)查看源碼,是在1796行的catch里面拋出的異常的,catch是捕捉到invokeInitMethods這個(gè)方法異常,然后才拋出來(lái)的,這樣就可以開(kāi)始進(jìn)行Debug了。
既然是在創(chuàng)建serverEndpointExporter這個(gè)bean異常的,加一個(gè)篩選條件,beanName等于serverEndpointExporter,這樣就能過(guò)濾創(chuàng)建的其他bean。
斷點(diǎn)卡好了,接下來(lái)就Debug模式來(lái)啟動(dòng)項(xiàng)目,然后F5進(jìn)到invokeInitMethods方法,單步往下執(zhí)行。
最后執(zhí)行到了 ((InitializingBean) bean).afterPropertiesSet(); 這行代碼,bean對(duì)象是ServerEndpointExporter,調(diào)用了這個(gè)對(duì)象的afterPropertiesSet方法。
來(lái)到ServerEndpointExporter這個(gè)java類,其中就會(huì)有afterPropertiesSet方法,首先調(diào)用getServerContainer方法獲取serverContainer對(duì)象。
很明顯這里返回的肯定是null,null != null 結(jié)果肯定是false,最后就是這樣調(diào)用state(false,javax.websocket.server.ServerContainer not available)
通過(guò)state源碼得知,最后就會(huì)拋出這個(gè)異常:java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
三、解決問(wèn)題
通過(guò)文章上述分析,可以確認(rèn)是因?yàn)镾erverEndpointExporter這個(gè)類中有一個(gè)對(duì)象叫做serverContainer,它為null了,所以才會(huì)異常。
接下來(lái)我們就需要去找,serverContainer這個(gè)對(duì)象是在哪里賦值的,找源碼就只有兩處賦值了,這就好辦了。
public class ServerEndpointExporter extends WebApplicationObjectSupport
implements InitializingBean, SmartInitializingSingleton {
@Nullable
private List> annotatedEndpointClasses;
@Nullable
private ServerContainer serverContainer;
// 有一個(gè)Set方法可以為serverContainer賦值
public void setServerContainer(@Nullable ServerContainer serverContainer) {
this.serverContainer = serverContainer;
}
@Nullable
protected ServerContainer getServerContainer() {
return this.serverContainer;
}
// 有一個(gè)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");
}
}通過(guò)IDEA的快捷方式,發(fā)現(xiàn)沒(méi)有其他地方調(diào)用了setServerContainer方法,那么就只有init方法了,那么就把斷點(diǎn)卡在initServletContext方法這。
通過(guò)Bebug就能夠發(fā)現(xiàn),在從servletContext.getAttribute的時(shí)候,根本就沒(méi)有javax.websocket.server.ServerContainer,所以getAttribute返回就是一個(gè)null,最后賦值給了serverContainer,最后就導(dǎo)致異常了。
那為什么javax.websocket.server.ServerContainer會(huì)不存在呢?
來(lái)到這個(gè)ServerContainer對(duì)應(yīng)的java類,原來(lái)是一個(gè)interface,那必然就會(huì)有對(duì)應(yīng)的實(shí)現(xiàn)類,通過(guò)IDEA查看好家伙,到這小編大概就明白了,這個(gè)項(xiàng)目引用了其他jar包,導(dǎo)致了沖突。
最后定位到是哪個(gè)jar沖突了,直接通過(guò)IDEA定位功能就能夠定位到,最后通過(guò)maven helper工具定位到maven引用位置,然后移除掉。
最后刷新一下maven,項(xiàng)目就能夠正常啟動(dòng)啦~~~~~
四、劃重點(diǎn)
本文并不是針對(duì)某一個(gè)異常、或者某一個(gè)具體的問(wèn)題來(lái)進(jìn)行分析,而是分享一下解決這個(gè)異常的一個(gè)過(guò)程。
最初的小編剛畢業(yè)那會(huì),遇到個(gè)異常就百度,運(yùn)氣好的話,很多人都踩過(guò)這個(gè)坑,能夠解決,萬(wàn)一恰好沒(méi)有找到合適的文章,然后、然后就陷入了沉思,也不知道咋辦。
而且通過(guò)別人來(lái)解決的問(wèn)題,肯定沒(méi)有自己解決問(wèn)題的印象深刻,而且通過(guò)自己去找問(wèn)題也是個(gè)有趣的過(guò)程。
也有很多小伙伴問(wèn)過(guò)小編,學(xué)習(xí)一些框架源碼有什么用?會(huì)用不就行了嗎?
怎么說(shuō)呢?當(dāng)然確實(shí)會(huì)用就行了,話又說(shuō)話來(lái),難道你就不好奇它們這些技術(shù)到底是怎么實(shí)現(xiàn)的嗎?看源碼不僅僅能夠?qū)W習(xí)到其他大神編寫(xiě)代碼的風(fēng)格,而且對(duì)于使用也有會(huì)更加深一層次的理解。
久而久之,遇到問(wèn)題,你的第一反應(yīng)并不是直接去百度,而是會(huì)自己主動(dòng)去摸索,到底是為啥子異常的,碰到一些看不懂的源碼,再去百度學(xué)習(xí)一下,進(jìn)行分析。
就這樣不知不覺(jué)你的技術(shù)就會(huì)慢慢得到升華,那個(gè)時(shí)候感覺(jué)就特別明顯了。
— 本文結(jié)束 —
●?漫談設(shè)計(jì)模式在 Spring 框架中的良好實(shí)踐
●?顛覆微服務(wù)認(rèn)知:深入思考微服務(wù)的七個(gè)主流觀點(diǎn)
●?人人都是 API 設(shè)計(jì)者
●?一文講透微服務(wù)下如何保證事務(wù)的一致性
●?要黑盒測(cè)試微服務(wù)內(nèi)部服務(wù)間調(diào)用,我該如何實(shí)現(xiàn)?
關(guān)注我,回復(fù) 「加群」 加入各種主題討論群。
對(duì)「服務(wù)端思維」有期待,請(qǐng)?jiān)谖哪c(diǎn)個(gè)在看
喜歡這篇文章,歡迎轉(zhuǎn)發(fā)、分享朋友圈
在看點(diǎn)這里總結(jié)
以上是生活随笔為你收集整理的illegalstateexception是什么异常_异常源码分析—告诉你学习“源码”究竟有什么用!...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 花影塔罗是谁画的呢?
- 下一篇: 上海商住两用房电费大概一个月多少钱?