如何在运行时更改 spring.http.multipart.maxFileSize?

How to change spring.http.multipart.maxFileSize in Runtime?

application.properties我有:

spring.http.multipart.maxFileSize
spring.http.multipart.maxRequestSize

但我希望有可能在不重启应用程序的情况下更改此 属性。

可能吗?

在深入研究源代码后,我找到了一种方法 StandardServletMultipartResolver

StandardServletMultipartResolverStandardMultipartHttpServletRequest 包装 HttpServletRequest,它使用 request.getParts() 的标准 servlet api 实现来处理多部分请求。在内部,此方法使用 MultipartConfigElement,它在调度程序 servlet 注册期间由 ServletRegistrationBean 设置。我们对 MultipartConfigElement 感兴趣,因为它包含我们感兴趣的属性。

默认情况下 ServletRegistrationBeanMultipartAutoConfiguration 获取 MultipartConfigElementMultipartConfigElement 的默认实现不允许修改其属性,因此我们需要扩展此 class 以添加此类功能。进一步的实施取决于您是要根据每个请求修改参数还是不时为整个应用程序修改参数。

按要求计算

MultipartConfigurationContext 存储特定请求的配置。 UpdateMultipartConfigurationFilter 为给定请求设置多部分属性。 UpdatableMultipartConfigElement 使用此信息(如果提供)。

public class MultipartConfigurationContext {

    private static ThreadLocal<Integer> maxFileSize = new ThreadLocal<>();

    public static void setMaxFileSize(Integer val) {
        maxFileSize.set(val);
    }

    public static Integer getMaxFileSize() {
        return maxFileSize.get();
    }

    public static void clear() {
        maxFileSize.set(null);
    }
}

public class UpdatableMultipartConfigElement extends MultipartConfigElement {

    private final long maxFileSize;

    public UpdatableMultipartConfigElement(String location, long maxFileSize, long maxRequestSize, int fileSizeThreshold) {
        super(location, maxFileSize, maxRequestSize, fileSizeThreshold);
        this.maxFileSize = maxFileSize;
    }

    @Override
    public long getMaxFileSize() {
        return MultipartConfigurationContext.getMaxFileSize() == null
                ? maxFileSize : MultipartConfigurationContext.getMaxFileSize();
    }
}

public class UpdateMultipartConfigurationFilter extends OncePerRequestFilter implements Ordered {

    // this filter must be before OrderedHiddenHttpMethodFilter
    public static final int ORDER = FilterRegistrationBean.REQUEST_WRAPPER_FILTER_MAX_ORDER - 20000;

    @Override
    public int getOrder() {
        return ORDER;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        // gets file size from request if present and sets it to MultipartConfigurationContext
        MultipartConfigurationContext.setMaxFileSize(150_000);

        filterChain.doFilter(request, response);

        MultipartConfigurationContext.clear();
    }
}

@Configuration
@EnableConfigurationProperties(MultipartProperties.class)
public class MultipartConfiguration {

    private final MultipartProperties multipartProperties;

    public MultipartConfiguration(MultipartProperties multipartProperties) {
        this.multipartProperties = multipartProperties;
    }

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigElement multipartConfigElement = multipartProperties.createMultipartConfig();
        return new UpdatableMultipartConfigElement(multipartConfigElement.getLocation(), multipartConfigElement.getMaxFileSize(),
                multipartConfigElement.getMaxRequestSize(), multipartConfigElement.getFileSizeThreshold());
    }

    @Bean
    public UpdateMultipartConfigurationFilter updateMultipartConfigurationFilter() {
        return new UpdateMultipartConfigurationFilter();
    }
}

全球

UpdatableMultipartConfigElement 存储可以在运行时使用 rest api 调用更新的信息。

public class UpdatableMultipartConfigElement extends MultipartConfigElement {

    private volatile long maxFileSize = -1;

    public UpdatableMultipartConfigElement(String location, long maxFileSize, long maxRequestSize, int fileSizeThreshold) {
        super(location, maxFileSize, maxRequestSize, fileSizeThreshold);
    }

    @Override
    public long getMaxFileSize() {
        return maxFileSize == -1 ? super.getMaxFileSize() : maxFileSize;
    }

    public void setMaxFileSize(long maxFileSize) {
        this.maxFileSize = maxFileSize;
    }
}

@Configuration
@EnableConfigurationProperties(MultipartProperties.class)
public class MultipartConfiguration {

    private final MultipartProperties multipartProperties;

    public MultipartConfiguration(MultipartProperties multipartProperties) {
        this.multipartProperties = multipartProperties;
    }

    @Bean
    public MultipartConfigElement multipartConfigElement() {
        MultipartConfigElement multipartConfigElement = multipartProperties.createMultipartConfig();
        return new UpdatableMultipartConfigElement(multipartConfigElement.getLocation(), multipartConfigElement.getMaxFileSize(),
                multipartConfigElement.getMaxRequestSize(), multipartConfigElement.getFileSizeThreshold());
    }
}

@RestController
public class ConfigurationController {

    @Autowired
    private UpdatableMultipartConfigElement updatableMultipartConfigElement;

    @RequestMapping("/configuration")
    public void configuration(@RequestParam("maxFileSize") long maxFileSize) {
        updatableMultipartConfigElement.setMaxFileSize(maxFileSize);
    }

}