项目运行环境:Spring Boot + Mybatis/Mybatis-plus + PageHelper

项目前提:本项目引入了一个由其它Spring Boot项目打包成的JAR包(这个很关键

问题描述

在IDEA中调试程序,分页正常;但通过WAR包部署时报错:“在系统中发现了多个分页插件,请检查系统配置”,具体报错信息如下:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException: 
### Error querying database.  Cause: java.lang.RuntimeException: 在系统中发现了多个分页插件,请检查系统配置!
### Cause: java.lang.RuntimeException: 在系统中发现了多个分页插件,请检查系统配置!

错误的解决方法

根据网上的方法尝试设置@SpringBootApplication(exclude = PageHelperAutoConfiguration.class),之后独立WAR包部署的项目可以正常运行,但是在IDEA中分页功能却失效了。

解决方法

上面的解决方法虽然没能最终解决问题,但是提供了一个思路,提示可能是自动配置的过程中出了问题

在上面的解决方法中设置@SpringBootApplication(exclude = PageHelperAutoConfiguration.class)之后独立WAR包部署的项目可以正常运行,但是在IDEA中分页功能却失效了。说明确实是自动配置的问题,自动配置是需要的,但是如果配置两次的话就会报出“多个分页插件”的错误!

问题分析

  1. 不管是在IDEA中调试还是独立WAR包部署,测试环境和生产环境基本一致,唯一不同是本地测试用的是Spring Boot的内置Tomcat启动的,而生产环境是运行在独立Tomcat中的。
    而用内置Tomcat启动类启动没有问题,但是WAR包部署到独立Tomcat就会出现这个报错,所以要看看有什么区别。

  2. 在将Spring Boot项目打包成WAR包时需要配置Application启动类继承SpringBootServletInitializer,并重写configure方法,而configure方法的作用就是要指定启动资源。

  3. 根据前面的分析可以猜测,是PageHelper相关的资源被指定了两次,所以启动的时候加载了两次这个资源,两次都自动配置了PageHelper插件,从而导致报错。所以可以根据这个思路去寻找项目中有哪些地方继承了SpringBootServletInitializer,并重写了configure方法

  4. 很简单地,可以猜到可能是自己引入的那个由其它Spring Boot项目打包成的JAR包出的问题。
    正常来说,将一个Spring Boot项目打包成JAR包时要删除其Application启动类,但是在某次打包时由于疏忽忘记了这个步骤,所以导致之后生成的WAR包中有两个继承了SpringBootServletInitializer的类,所以导致PageHelper插件被配置了两次。
    在这里插入图片描述

  5. 修改将被打包成JAR包的Spring Boot项目,去掉多余的Application,即可解决问题。

说明

本人追溯到的原因只是一种情况,但是可以按照这个思路去找问题。


拓展部分

PageHelper的自动配置类源码分析:PageHelperAutoConfiguration

@Configuration
@ConditionalOnBean(SqlSessionFactory.class)
@EnableConfigurationProperties(PageHelperProperties.class)
@AutoConfigureAfter(MybatisAutoConfiguration.class)
public class PageHelperAutoConfiguration {
 
    @Autowired
    private List<SqlSessionFactory> sqlSessionFactoryList;
 
    @Autowired
    private PageHelperProperties properties;
 
    /**
     * 接受分页插件额外的属性
     *
     * @return
     */
    @Bean
    @ConfigurationProperties(prefix = PageHelperProperties.PAGEHELPER_PREFIX)
    public Properties pageHelperProperties() {
        return new Properties();
    }
 
    @PostConstruct
    public void addPageInterceptor() {
        PageInterceptor interceptor = new PageInterceptor();
        Properties properties = new Properties();
        //先把一般方式配置的属性放进去
        properties.putAll(pageHelperProperties());
        //在把特殊配置放进去,由于close-conn 利用上面方式时,属性名就是 close-conn 而不是 closeConn,所以需要额外的一步
        properties.putAll(this.properties.getProperties());
        interceptor.setProperties(properties);
        for (SqlSessionFactory sqlSessionFactory : sqlSessionFactoryList) {
            sqlSessionFactory.getConfiguration().addInterceptor(interceptor);
        }
    }
}
  1. 从源码也可以看出两次自动配置会加入了两个拦截器PageInterceptor,所以才会提示“多个插件”;
  2. 加上exclude=PageHelperAutoConfiguration.class之后,相当于排除了PageHelperAutoConfiguration.class,即不让PageHelper自动配置,所以取消自动配置后又出现分页失效的问题。

参考

https://blog.csdn.net/ejiao1233/article/details/83995511

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐