使用AWS SDK for Java对接Minio时S3AsyncClient与S3TransferManager区域问题
问题分析与解决:Spring Boot对接Minio时AWS SDK区域加载失败
错误日志
Unable to load region from software.amazon.awssdk.regions.providers.SystemSettingsRegionProvider@ee630de:Unable to load region from system settings. Region must be specified either via environment variable (AWS_REGION) or system property (aws.region). s.a.a.r.p.AwsRegionProviderChain : Unable to load region from software.amazon.awssdk.regions.providers.AwsProfileRegionProvider@22590efb:No region provided in profile: default s.a.a.r.p.AwsRegionProviderChain: Unable to load region from software.amazon.awssdk.regions.providers.InstanceProfileRegionProvider@6c5be4c6:Unable to contact EC2 metadata service.
用户配置与代码
application.properties
minio.access.url=http://localhost:9000 minio.access.name=minioadmin minio.access.secret=minioadmin aws.region=us-east-1
Minio配置类
import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.s3.S3AsyncClient; import java.net.URI; import static software.amazon.awssdk.transfer.s3.SizeConstant.MB; @Configuration public class MinioConfig { @Value("${minio.access.url}") private String minioUrl; @Value("${minio.access.name}") private String accessKey; @Value("${minio.access.secret}") private String accessSecret; @Bean public S3AsyncClient generateMinioClient(){ return S3AsyncClient.crtBuilder() .endpointOverride(URI.create(minioUrl)) .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(accessKey, accessSecret))) .region(Region.EU_CENTRAL_2) .targetThroughputInGbps(20.0) .minimumPartSizeInBytes(8 * MB) .build(); } }
服务类代码
import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import software.amazon.awssdk.transfer.s3.S3TransferManager; import software.amazon.awssdk.transfer.s3.model.CompletedFileUpload; import software.amazon.awssdk.transfer.s3.model.UploadFileRequest; import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener; import java.net.URI; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture; @Service @AllArgsConstructor public class FileStorageService { private final StorageSystem storageSystem; public CompletableFuture<CompletedFileUpload> uploadFile(String username, String fileName, URI fileUri) { try (S3TransferManager transferManager = S3TransferManager.create()) { UploadFileRequest request = UploadFileRequest.builder() .putObjectRequest(req -> req.bucket(username).key("key")) .addTransferListener(LoggingTransferListener.create()) .source(Paths.get(fileName)) .build(); return transferManager.uploadFile(request).completionFuture(); } } }
问题原因
核心问题是你自定义的S3AsyncClient没有被S3TransferManager使用。当前代码中S3TransferManager.create()会默认创建全新的S3客户端实例,这个实例会走AWS SDK默认的区域提供者链(系统环境变量、AWS配置文件、EC2元数据服务)加载区域,而本地Minio环境下这些渠道都没有配置区域,因此抛出加载失败错误。
另外,application.properties中设置的aws.region不会生效,因为默认创建的S3客户端不会读取Spring配置属性,且自定义客户端并未传递给S3TransferManager。
解决方案
1. 修改服务类,注入自定义的S3AsyncClient
将FileStorageService中的StorageSystem替换为自定义的S3AsyncClient,并使用该客户端创建S3TransferManager:
import lombok.AllArgsConstructor; import org.springframework.stereotype.Service; import software.amazon.awssdk.services.s3.S3AsyncClient; import software.amazon.awssdk.transfer.s3.S3TransferManager; import software.amazon.awssdk.transfer.s3.model.CompletedFileUpload; import software.amazon.awssdk.transfer.s3.model.UploadFileRequest; import software.amazon.awssdk.transfer.s3.progress.LoggingTransferListener; import java.nio.file.Paths; import java.util.concurrent.CompletableFuture; @Service @AllArgsConstructor public class FileStorageService { private final S3AsyncClient s3AsyncClient; public CompletableFuture<CompletedFileUpload> uploadFile(String username, String fileName) { try (S3TransferManager transferManager = S3TransferManager.builder() .s3Client(s3AsyncClient) .build()) { UploadFileRequest request = UploadFileRequest.builder() .putObjectRequest(req -> req.bucket(username).key("key")) .addTransferListener(LoggingTransferListener.create()) .source(Paths.get(fileName)) .build(); return transferManager.uploadFile(request).completionFuture(); } } }
(注:移除了未使用的URI参数,可根据实际需求调整)
2. 统一Region配置
Minio对Region校验宽松,可选择:
- 使用
Region.of("us-east-1")(Minio默认区域),与application.properties配置保持一致 - 继续使用
Region.EU_CENTRAL_2(当前代码配置),只要是AWS SDK认可的Region字符串即可,Minio会正常处理。
无需额外配置,只要保证S3TransferManager使用自定义的S3AsyncClient实例,区域问题即可解决。
补充说明
application.properties中的aws.region对自定义客户端无效,因为自定义客户端的Region是通过.region()方法显式指定的,优先级高于系统配置。Region.of("us-east-1")是正确用法,只要是AWS SDK认可的Region字符串都可,Minio仅将其作为标识使用,不做严格校验。
内容的提问来源于stack exchange,提问作者wallhack
相关产品推荐
相关产品推荐

