记一次SpringBoot启动异常,jar冲突问题的排查分析

共 11598字,需浏览 24分钟

 ·

2022-07-24 21:34

你知道的越多,不知道的就越多,业余的像一棵小草!

你来,我们一起精进!你不来,我和你的竞争对手一起精进!

编辑:业余草

jiannan.blog.csdn.net

推荐:https://www.xttblog.com/?p=5351

一、引言

小编最近接了个相当于外包的项目,在他们项目中集成一个 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

二、问题分析

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

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

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

分析到这里就能够得知,是在spring创建serverEndpointExporter的时候异常了,「那么异常的原因是什么呢?,为什么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这个方法异常,然后才抛出来的,这样就可以开始进行Debug了。

既然是在创建serverEndpointExporter这个bean异常的,加一个筛选条件,beanName等于serverEndpointExporter,这样就能过滤创建的其他bean。

断点卡好了,接下来就Debug模式来启动项目,然后F5进到invokeInitMethods方法,单步往下执行。

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

来到ServerEndpointExporter这个java类,其中就会有afterPropertiesSet方法,首先调用getServerContainer方法获取serverContainer对象。

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

通过state源码得知,最后就会抛出这个异常:java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available

三、解决问题

通过文章上述分析,可以确认是因为ServerEndpointExporter这个类中有一个对象叫做serverContainer,它为null了,所以才会异常。

接下来我们就需要去找,serverContainer这个对象是在哪里赋值的,找源码就只有两处赋值了,这就好办了。

public class ServerEndpointExporter extends WebApplicationObjectSupport
  implements InitializingBeanSmartInitializingSingleton 
{

    @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.server.ServerContainer,所以getAttribute返回就是一个null,最后赋值给了serverContainer,最后就导致异常了。

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

来到这个ServerContainer对应的java类,原来是一个interface,那必然就会有对应的实现类,通过IDEA查看好家伙,到这小编大概就明白了,这个项目引用了其他jar包,导致了冲突。

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

最后刷新一下maven,项目就能够正常启动啦~~~~~

四、划重点

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

最初的小编刚毕业那会,遇到个异常就百度,运气好的话,很多人都踩过这个坑,能够解决,万一恰好没有找到合适的文章,然后、然后就陷入了沉思,也不知道咋办。

而且通过别人来解决的问题,肯定没有自己解决问题的印象深刻,而且通过自己去找问题也是个有趣的过程。

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

怎么说呢?当然确实会用就行了,话又说话来,难道你就不好奇它们这些技术到底是怎么实现的吗?看源码不仅仅能够学习到其他大神编写代码的风格,而且对于使用也有会更加深一层次的理解。

久而久之,遇到问题,你的第一反应并不是直接去百度,而是会自己主动去摸索,到底是为啥子异常的,碰到一些看不懂的源码,再去百度学习一下,进行分析。

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

浏览 112
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报