Spring Boot————BeanCreationNotAllowedException异常分析

引言

在对数据库进行新增记录的JUnit测试时,抛出一个BeanCreationNotAllowedException异常:

异常分析与解决

异常信息太长,图片截不下,粘贴来看:

Exception in thread "pool-2-thread-1" org.springframework.beans.factory.BeanCreationNotAllowedException: Error creating bean with name 'redisConnectionFactory': Singleton bean creation not allowed while singletons of this factory are in destruction (Do not request a bean from a BeanFactory in a destroy method implementation!) 

异常代码:

    @Test
    public void testAddOrUpdateUser() throws InterruptedException {
        JSONObject teacher = new JSONObject();
        teacher.put("role", "teacher");
        teacher.put("teacherName", "王力宏");
        teacher.put("jobTitle", "助理教授");
        teacher.put("gender", "男");
        teacher.put("username", "wanglihong");
        
        SystemResult addOrUpdateUser = userService.addOrUpdateUser(teacher);
        System.out.println(addOrUpdateUser);
    }

 测试方法的关键调用函数是:userService.addOrUpdateUser(teacher); 可是在这个方法内部完全没有用到redis的相关内容,而且奇怪的是:用debug模式运行方法的话完全可以成功

莫名其妙!

来看一下addOrUpdateUser方法:

    @Override
    @SuppressWarnings("rawtypes")
    public SystemResult addOrUpdateUser(Object user) {
        Boolean isTeacher = checkSvc.checkTeacherByRole(user);

        boolean isStudent = !isTeacher;
        String userStr = null;
        Class clazz = null;
        if (isTeacher) {
            // 添加教师
            Teacher teacher = JSONObject.toJavaObject(JSONObject.parseObject(JSONObject.toJSONString(user)),
                    Teacher.class);
            DBProcessor.execute(() -> {

                tchrRep.save(teacher);
            });
            // ......
        } else if (isStudent) {
            // ......
        }
        logger.info("添加或更新<" + clazz.getSimpleName() + "> : " + userStr);
        String resultMessage = "添加或更新" + (isTeacher ? "教师" : "学生") + "成功!";

        return new SystemResult(SysContents.SUCCESS, resultMessage, clazz.getSimpleName().toLowerCase());
    }

我已经简化了部分代码,关键就是执行save方法的前后,可以看出此处的save方法,我为了充分利用并发性,采用了多线程的方式,将保存任务交给了一个ExecutorService——DBProcessor去执行。

交给一个新的线程去执行就是问题所在!

其实,细致分析一下就可以发现,我们采用debug的方式,或者将任务不交给线程去执行,而是串行直接执行任务,就不会有问题,原因就是,分配新的线程执行任务需要一定的性能和时间开销,因此会稍微比JUnit测试方法延迟一些。这样当JUnit方法执行完成立刻退出之后,整个系统环境也就直接退出关闭,没有给新的线程足够的时间去执行任务,因此才会导致插入失败。

顺着这个思路,我在JUnit方法执行到addOrUpdateUser之后sleep 1秒钟,果然顺利通过测试。

至于异常所描述的创建bean失败,我想就是因为JUnit测试结束之后过早退出系统环境的原因。

另外,这个问题网上的出错原因也并不一致,还要根据自己的问题具体分析。

如有疑问,欢迎留言。

相关推荐
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页