在SpringBoot中弃用自带的StandardServletMultipartResolver更换为CommonsMultipartResolver也有坑

还是上篇传统Spring项目换SpringBoot框架中的一个问题,先描述一下问题:

整和SpringBoot后系统中的文件上传都不能用了,统统报错如下:

大致就是Failed to parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: Stream closed这样,通过异常栈信息可以看出当时使用的文件上传解析器是CommonsMultipartResolver,在项目里找了一下配置,由于之前是Spring项目确实是在spring-mvc.xml中配置了这个解析器:

问题就出在这里。

 去Spring的官网上看了一眼,当然,是翻译后看了一眼,MultipartResolver有两种实现:

 而SpringBoot的autoconfigure那一套用哪个实现想必也是约定好的,看了一眼spring-boot-autoconfigure的spring.factories,果然找到了这行:

那就去看一下这个MultipartAutoConfiguration配置类:

看来SpringBoot默认用的是StandardServletMultipartResolver,而且这个@Bean后面还有一个@ConditionalOnMissingBean注解,意思是如果已经有MultipartResolver的实现Bean的就不注册了,这做也是为了同时注册了两个文件上传解析器,IO流默认是只能被读取一次的(当然通过拦截器自己写逻辑可以实现多次取出这里不扩展可以参考https://blog.csdn.net/zhibo_lv/article/details/81875705),也就是说如果是上传文件只能被解析一次,如果又来一个文件解析器不好意思流里面已经没东西了就有问题了。

理论上这里有@ConditionalOnMissingBean注解StandardServletMultipartResolver应该不会被注册了,但是我这个方法里打了断点,同时在CommonsMultipartResolver的构造方法中也打了断点,项目启动的时候居然都进来了,而且是先注册了StandardServletMultipartResolver再注册了CommonsMultipartResolver:

 先注册了StandardServletMultipartResolver再注册CommonsMultipartResolver那@ConditionalOnMissingBean当然就不起作用了,导致这个先后顺序的原因就是因为CommonsMultipartResolver是在XML中配置的Bean,而StandardServletMultipartResolver是在@Configuration配置类中配置的Bean,Spring在加载Bean的时候是先加载注解配置的Bean再从XML中加载Bean,这个在我之前的一篇博客中有详细的写(https://blog.csdn.net/weixin_42447959/article/details/104943589)。放这篇博客里一张图:

里面四个load()方法,第一个是加载注解配置的,第二个是加载XML配置的,可以看出先后顺序,详细的可以参考那篇博客。 

所以如果SpringBoot要用CommonsMultipartResolver不能直接在XML中配置就完事了,当然也别钻牛角尖同时用@Configuration配置类配置看看哪个先,这样会导致同时注册了两个文件解析器,导致Stream Closed。正确的做法是先在yml配置文件中排除默认的MultipartResolver,如图:

spring:
  autoconfigure:
    exclude: org.springframework.boot.autoconfigure.web.servlet.MultipartAutoConfiguration

然后CommonsMultipartResolver用注解配置也好用XML配置也好就随便了。

当然我这里的解决办法就是直接在XML注释了CommonsMultipartResolver的配置,SpringBoot自带的StandardServletMultipartResolver难道不香吗?

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值