Bug description
Summary
When using @Profile with @PostConstruct, I see the following error saying, there is a circular dependency. This error is not correct as there is no circular dependency.
Error info
The dependencies of some of the beans in the application context form a cycle:
application (field private com.truncated.---ExtractService)
↓
----Service defined in file [/truncated/service/----Service.class]
↓
s3Helper defined in file [/truncated/S3Helper.class]
┌─────┐
| awsLocalConfig
└─────┘
S3Helper.java class uses s3Client bean.
Working spring version: 2.5.8
Failing spring version: 2.6.6
Failing code
Project contains both AwsLocalConfig.java and AwsConfig.java
Local config
Creates S3Client and sets up s3 bucket locally using @PostConstruct
@Configuration
@Slf4j
@Profile("local")
public class AwsLocalConfig {
private static final String LOCALSTACK_URL = "http://127.0.0.1:4566";
@Value("${config.aws.region}")
String region;
@Value("${config.aws.access_key}")
String awsS3AccessKey;
@Value("${config.aws.secret_key}")
String awsS3SecretKey;
@Value("${config.aws.s3bucket}")
String s3BucketName;
@Bean
@Qualifier("s3Client")
public AmazonS3 s3Client() {
return s3ClientBasicCredentials();
}
@Bean
@Qualifier("s3ClientBasicCredentials")
public AmazonS3 s3ClientBasicCredentials() {
AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(
new BasicAWSCredentials(awsS3AccessKey, awsS3SecretKey));
EndpointConfiguration endpointConfiguration = new EndpointConfiguration(LOCALSTACK_URL, region);
return AmazonS3ClientBuilder.standard()
.withCredentials(credentialsProvider)
.withEndpointConfiguration(endpointConfiguration)
.build();
}
@PostConstruct
public void prepareLocalStackResources() {
AmazonS3 amazonS3 = s3ClientBasicCredentials();
amazonS3.createBucket(s3BucketName);
log.info(String.format("S3 Bucket %s created successfully in localstack", s3BucketName));
}
}
Non local config (dev/qa/stg/prod)
Creates S3Client bean and project starts up without issues as there is no usage of @PostConstruct.
Works even in 2.6.6 version
@Configuration
@Slf4j
@Profile("!local")
public class AwsConfig {
@Value("${config.aws.region}")
String region;
@Value("${config.aws.access_key}")
String awsS3AccessKey;
@Value("${config.aws.secret_key}")
String awsS3SecretKey;
@Bean
@Qualifier("s3Client")
public AmazonS3 s3Client() {
log.info("AWS_ROLE_ARN env variable value is: " + System.getenv("AWS_ROLE_ARN"));
log.info("AWS_ROLE_SESSION_NAME env variable value is: " + System.getenv("AWS_ROLE_SESSION_NAME"));
AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard()
.withCredentials(WebIdentityTokenCredentialsProvider.create())
.withRegion(region)
.build();
log.info("AWS S3 Account owner display name is :" + amazonS3.getS3AccountOwner().getDisplayName());
log.info("AWS S3 Account owner id is:" + amazonS3.getS3AccountOwner().getId());
return amazonS3;
}
@Bean
@Qualifier("s3ClientBasicCredentials")
public AmazonS3 s3ClientBasicCredentials() {
AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(
new BasicAWSCredentials(awsS3AccessKey, awsS3SecretKey));
return AmazonS3ClientBuilder.standard()
.withRegion(region)
.withCredentials(credentialsProvider)
.build();
}
}
Temporary Solution
Not using @PostConstruct and calling prepareLocalStackResources() inside s3ClientBasicCredentials() bean creation method.
Works without issues in 2.6.6 version
@Configuration
@Slf4j
@Profile("local")
public class AwsLocalConfig {
private static final String LOCALSTACK_URL = "http://127.0.0.1:4566";
@Value("${config.aws.region}")
String region;
@Value("${config.aws.access_key}")
String awsS3AccessKey;
@Value("${config.aws.secret_key}")
String awsS3SecretKey;
@Value("${config.aws.s3bucket}")
String s3BucketName;
@Bean
@Qualifier("s3Client")
public AmazonS3 s3Client() {
return s3ClientBasicCredentials();
}
@Bean
@Qualifier("s3ClientBasicCredentials")
public AmazonS3 s3ClientBasicCredentials() {
AWSCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(
new BasicAWSCredentials(awsS3AccessKey, awsS3SecretKey));
EndpointConfiguration endpointConfiguration = new EndpointConfiguration(LOCALSTACK_URL, region);
AmazonS3 s3 = AmazonS3ClientBuilder.standard()
.withCredentials(credentialsProvider)
.withEndpointConfiguration(endpointConfiguration)
.build();
prepareLocalStackResources(s3);
return s3;
}
public void prepareLocalStackResources(AmazonS3 amazonS3) {
amazonS3.createBucket(s3BucketName);
log.info(String.format("S3 Bucket %s created successfully in localstack", s3BucketName));
}
}
Comment From: neerajsu
Seems like this issue with already raised in spring-framework here -> https://github.com/spring-projects/spring-framework/issues/27876. So closing out, since this is a duplicate.