前排提示:照旧博主菜,见地短浅,没遇到过这个题目。。。
因由
前段时间学习websocket和sse,写demo用了spring框架。后来又写了新的spring单位测试类demo去测试,效果启动后报错,报错信息提示websocket的干系错误,大概意思时由于测试环境缺少WebSocket干系配置或依赖所导致。
报错信息
- java.lang.IllegalStateException: Failed to load ApplicationContext
- at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:98)
- at org.springframework.test.context.support.DefaultTestContext.getApplicationContext(DefaultTestContext.java:124)
- at org.springframework.test.context.web.ServletTestExecutionListener.setUpRequestContextIfNecessary(ServletTestExecutionListener.java:190)
- at org.springframework.test.context.web.ServletTestExecutionListener.prepareTestInstance(ServletTestExecutionListener.java:132)
- at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:248)
- at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:227)
- at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:289)
- at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
- at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:291)
- at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:246)
- at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
- at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
- at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
- at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
- at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
- at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
- at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
- at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
- at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
- at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
- at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
- at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
- at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
- at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
- at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
- at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
- at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
- at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
- Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'serverEndpointExecutor' defined in class path resource [com/realpractice/demo/config/WebSocketConfiguration.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:1804)
- at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620)
- at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542)
- at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335)
- at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234)
- at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333)
- at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208)
- at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:955)
- at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918)
- at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583)
- at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:745)
- at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:420)
- at org.springframework.boot.SpringApplication.run(SpringApplication.java:307)
- at org.springframework.boot.test.context.SpringBootContextLoader.loadContext(SpringBootContextLoader.java:144)
- at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContextInternal(DefaultCacheAwareContextLoaderDelegate.java:141)
- at org.springframework.test.context.cache.DefaultCacheAwareContextLoaderDelegate.loadContext(DefaultCacheAwareContextLoaderDelegate.java:90)
- ... 27 more
- Caused by: java.lang.IllegalStateException: javax.websocket.server.ServerContainer not available
- at org.springframework.util.Assert.state(Assert.java:76)
- at org.springframework.web.socket.server.standard.ServerEndpointExporter.afterPropertiesSet(ServerEndpointExporter.java:107)
- at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1863)
- at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1800)
- ... 42 more
复制代码 这是博主用的很简单的一个测试类:- import xxx.xxx.xxx.config.RedisConfig;
- import org.junit.Test;
- import org.junit.runner.RunWith;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.boot.test.context.SpringBootTest;
- import org.springframework.data.redis.core.RedisTemplate;
- import org.springframework.test.context.ActiveProfiles;
- import org.springframework.test.context.ContextConfiguration;
- import org.springframework.test.context.junit4.SpringRunner;
- import java.io.Serializable;
- @RunWith(SpringRunner.class)
- @SpringBootTest(classes = DemoApplication.class)
- @ContextConfiguration(classes = RedisConfig.class) // 启用自定义配置
- public class RedisTest {
- @Autowired
- private RedisTemplate<String, String> redisTemplate;
- @Test
- public void test() {
- redisTemplate.opsForValue().set("test", "test");
- System.out.println(redisTemplate.opsForValue().get("test"));
- }
- }
复制代码 启动后报错:
刚开始有点懵,我都没测你websocket,你给我报个websocket的错。
学习一波。。。
根本原因是由于测试环境下没有websocket的环境,以是测试的时候必要表明掉它。并且测试中不选择让websocket加载有很多种方式,这个我们稍后再说。先来看看spring本身,既然报了websocket的错,阐明spring本身去加载到了项目config目录下全部利用@Configuration注解的配置类。那么抛出我们第一个题目:为什么非 WebSocket 的测试类会加载 WebSocket 配置?
题目
为什么测试类会加载 WebSocket 配置?
这就不得不提到springboot的自动加载机制:
@SpringBootTest 会加载整个应用的上下文(包罗全部 @Component, @Configuration, @Service 等)。
只要你的 WebSocketConfig 类被 @Configuration 或 @EnableWebSocket 标记,它就会被扫描并初始化。
那有的朋侪又要问了,那我知道了springboot的自动加载机制,正常启动项目websocket也没错,为什么一利用测试就报错呢?不是说@SpringBootTest会加载整个应用的上下文吗?
嗯,博主看了下,原因似乎是底层的依赖冲突,导致spring加载了错误的实现类。【具体原因的博主本身还没真正的测试过,就不妄下结论了。感爱好的朋侪直接欣赏器搜刮:“javax.websocket.server.ServerContainer not available”,跟着打波断点走下流程肯定能更明白整个逻辑】
多说一些关于sprngboot的干系知识把:
spring的组件扫描规则说白了就是"约定优于配置"的具体表现,即spring默认去加载全部大概的组件,镌汰显式配置。
尚有一点是"上下文完备性":即spring确保测试环境和生产环境划一,克制因部门组件未加载导致测试效果禁绝确。
但也会带来一些副作用:测试启动变慢 和 依赖耦合,导致终极加载了不须要的组件,大概因它的初始化失败导致整个测试类失败。
办理
好好好,说了这么多怎么办理这个题目呢?
一
起首简单粗暴的办法就是在测试时把websocket干系代码全部表明掉,正常启动时再取消表明就可以了。(下下策)
二
我们可以把websocket的config写成根据差别配置选择是否加载,让其判定当前是否是测试环境,如果是则不加载websocket干系业务代码:
三
(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
通过注解参数 完全初始化 WebSocket 的基础办法,包罗 ServerContainer。
明确指定了主配置类,并启动一个真实的嵌入式 web 服务器(而不仅仅是 mock 环境),并随机选择一个可用端口。
。。。总之是可以运行的。。。
内容尚有待增补,有题目标朋侪可以批评一起互换一下。文章如有错误屈驾读者朋侪们指正,博主老实担当学习。谢谢各人。🌠
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
|