In application.properties
I have:
spring.http.multipart.maxFileSize
spring.http.multipart.maxRequestSize
But I want to have possibility to change this property without application restart.
Is it possible ?
After digging in source code i found a way how to do it for StandardServletMultipartResolver
.
StandardServletMultipartResolver
wraps HttpServletRequest
with StandardMultipartHttpServletRequest
which uses standard servlet api implementation of request.getParts()
for processing multipart request. Internally this method uses MultipartConfigElement
which is set by ServletRegistrationBean
during registration of dispatcher servlet. We are interested in MultipartConfigElement
cause it contains properties we are interested in.
By default ServletRegistrationBean
gets MultipartConfigElement
from MultipartAutoConfiguration
. Default implementation of MultipartConfigElement
doesn't allow to modify its properties so we need to extend this class to add such ability. Further implementation depends on whether you want to modify parameters on per request basis or time to time for the whole application.
Per request basis
MultipartConfigurationContext
stores configuration for a particular request. UpdateMultipartConfigurationFilter
sets multipart properties for given request. UpdatableMultipartConfigElement
uses this information if provided.
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();
}
}
Globally
UpdatableMultipartConfigElement
stores information which can be updated in runtime using rest api call.
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);
}
}