Using Thumbnailator and SpringBoot Thread Pool for Image Watermarking and Asynchronous Upload
This article demonstrates how to integrate the Thumbnailator library with SpringBoot, configure a thread pool, and implement asynchronous image processing and upload using FastDFS, providing complete code examples, configuration tips, and common pitfalls to avoid.
The article introduces a backend solution for handling image uploads, adding watermarks, generating thumbnails, and storing them in FastDFS using SpringBoot.
Environment : SpringBoot + FastDFS + Thumbnailator. The FastDFS environment must be set up separately.
Maven dependency for Thumbnailator :
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.8</version>
</dependency>Utility class (PictureUtil) provides three methods:
public void photoMark(File sourceFile, File toFile) throws IOException { /* adds watermark */ }
public void photoSmaller(File sourceFile, File toFile) throws IOException { /* creates thumbnail */ }
public void photoSmallerForVedio(File sourceFile, File toFile) throws IOException { /* video thumbnail */ }Both methods use Thumbnails.of(...).size(...).watermark(...).outputQuality(...).toFile(...) to process images.
SpringBoot thread pool configuration :
@Configuration
@EnableAsync
public class PoolConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.initialize();
executor.setCorePoolSize(4);
executor.setMaxPoolSize(32);
executor.setQueueCapacity(512);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("ThreadPool-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}Note the required annotations @Configuration and @EnableAsync on the configuration class, and @Async on the service methods that should run in the pool.
Controller example for receiving an image:
@ApiOperation("上传业务图片")
@PostMapping("/push/photo/{id}/{name}")
public R pushHousingPhotoMethod(@PathVariable Integer id,
@PathVariable(required = false) String name,
@RequestParam MultipartFile file) throws Exception {
String fileName = file.getOriginalFilename();
String ext = StringUtils.substring(fileName, fileName.lastIndexOf('.'));
File tempPhoto = File.createTempFile(UUIDUtil.make32BitUUID(), ext);
file.transferTo(tempPhoto);
service.pushPhoto(id, name, tempPhoto);
return new R();
}The controller saves the uploaded MultipartFile as a temporary file before delegating to the service; this prevents the file from being deleted before asynchronous processing completes.
Service layer (asynchronous) :
@Async
public void pushHousingPhoto(Integer id, String name, File file) throws Exception {
Long startTime = System.currentTimeMillis();
Integer[] nums = fastDfsService.upLoadPhoto(StringUtils.isBlank(name) ? file.getName() : name, file).get();
SourcePhotosContext context = new SourcePhotosContext();
context.setSourceId(id);
context.setNumber(nums[0]);
context.setNumber2(nums[1]);
sourcePhotosContextService.insertNew(context);
Long endTime = System.currentTimeMillis();
LogUtil.info(this.getClass(), "source ["+id+"] bind photo ["+name+"] success, cost " + (endTime-startTime) + "ms");
}The service uploads the original image, adds a watermark, creates a thumbnail, stores both in FastDFS, and records their IDs in a database table.
FastDFS upload helper shows overloaded methods handling both MultipartFile and File , generating temporary files, applying watermark/thumbnail via PictureUtil , uploading, and cleaning up temporary files.
Common pitfalls highlighted include:
Ensuring @EnableAsync is present on a configuration class and @Async on the service method.
Saving MultipartFile to a temporary file before async processing, because the original temporary file is deleted when the controller returns.
Avoiding unnecessary .get() on Future when using a properly configured thread pool.
Overall, the guide provides a complete, production‑ready pattern for asynchronous image handling in a SpringBoot backend.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.