创建名称为 'amazonS3Client' 的 bean 时出错:当前正在创建请求的 bean:是否存在无法解析的循环引用?
Error creating bean with name 'amazonS3Client': Requested bean is currently in creation: Is there an unresolvable circular reference?
一切都开始了,因为 Spring Cloud AWS 没有正确配置 SimpleStorageProtocolResolver。此 class 负责在使用 ResourceLoader 时处理 s3:// 协议。有关详细信息,请参阅问题:cannot be cast to org.springframework.core.io.WritableResource on Spring AWS example.
所以,我不得不手动创建它。但我也在使用 LocalStack 解决方案 (https://github.com/localstack/localstack),并且由于 Spring Cloud AWS 没有手动配置端点的选项,我不得不(猜猜是什么?)创建 AmazonS3Client 手动.
问题来了,当我在 class S3Configuration class(见下文)中创建两个 bean 时,Spring 框架只是跳过 bean 创建。而且,当我尝试将它连接到 S3Handler class(见下文)时,会发生此错误:Error creating a bean with name 'amazonS3Client':请求的 bean 当前正在创建中:是否存在无法解析的循环引用?
但是,又一次,整件事来了,那些 classes 之间没有循环引用。
我已经简化了项目,所以我可以在这里post它:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/>
</parent>
<groupId>io.mobi7.ms</groupId>
<artifactId>mobi7-temp-ms-ibutton-worker</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<spring-cloud-version>2.1.4.RELEASE</spring-cloud-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws</artifactId>
<version>${spring-cloud-version}</version>
</dependency>
</dependencies>
</project>
S3Configuration.java
package io.mobi7.ms.ibutton.worker;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.aws.core.io.s3.SimpleStorageProtocolResolver;
import org.springframework.cloud.aws.core.region.RegionProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
@Configuration
public class S3Configuration {
@Bean("amazonS3Client") // THIS METHOD IS NOT BEING CALLED!!!
public AmazonS3 amazonS3Client(AWSCredentialsProvider credentialsProvider,
RegionProvider regionProvider,
@Value("${cloud.aws.s3.default-endpoint}") String endpoint) {
return AmazonS3ClientBuilder.standard()
.withCredentials(credentialsProvider)
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration(endpoint, regionProvider.getRegion().getName()))
.build();
}
@Autowired // THIS METHOD IS NOT BEING CALLED!!!
public void configureResourceLoader(@Qualifier("amazonS3Client") AmazonS3 amazonS3Client,
DefaultResourceLoader resourceLoader) {
SimpleStorageProtocolResolver simpleStorageProtocolResolver = new SimpleStorageProtocolResolver(amazonS3Client);
// As we are calling it by hand, we must initialize it properly.
simpleStorageProtocolResolver.afterPropertiesSet();
resourceLoader.addProtocolResolver(simpleStorageProtocolResolver);
}
}
S3Handle.java
package io.mobi7.ms.ibutton.worker;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class S3Handler {
private AmazonS3 amazonS3Client;
@Autowired
public S3Handler(@Qualifier("amazonS3Client") AmazonS3 amazonS3Client) {
this.amazonS3Client = amazonS3Client;
}
public List<String> listFiles(String bucketName) {
return amazonS3Client.listObjects(bucketName).getObjectSummaries().stream().map(S3ObjectSummary::getKey)
.collect(Collectors.toList());
}
}
Application.java
package io.mobi7.ms.ibutton.worker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.NONE).run(args);
}
@Autowired
public void listFiles(S3Handler s3Handler) {
s3Handler.listFiles("default-s3-bucket").forEach(System.out::println);
}
}
application.properties
cloud.aws.region.static=us-east-1
cloud.aws.stack.auto=false
cloud.aws.s3.default-endpoint=http://localhost:4572
任何想法,为什么会这样?
@Autowired
注解标记了构造对象状态的方法(例如setter或方法注入)。请参阅 "Autowired Methods" 部分 here。
您使用 Autowired 注释的两种方法均未用于此需求。
这个问题是关于Spring的。可以删除所有其他标签。
更新: 涵盖了类似案例 。
不管那里的建议是什么,我都不会保留单个 GOD 配置 class,而是将您的配置 class 拆分为 2 classes - S3 客户端的工厂和资源加载器的配置.
一切都开始了,因为 Spring Cloud AWS 没有正确配置 SimpleStorageProtocolResolver。此 class 负责在使用 ResourceLoader 时处理 s3:// 协议。有关详细信息,请参阅问题:cannot be cast to org.springframework.core.io.WritableResource on Spring AWS example.
所以,我不得不手动创建它。但我也在使用 LocalStack 解决方案 (https://github.com/localstack/localstack),并且由于 Spring Cloud AWS 没有手动配置端点的选项,我不得不(猜猜是什么?)创建 AmazonS3Client 手动.
问题来了,当我在 class S3Configuration class(见下文)中创建两个 bean 时,Spring 框架只是跳过 bean 创建。而且,当我尝试将它连接到 S3Handler class(见下文)时,会发生此错误:Error creating a bean with name 'amazonS3Client':请求的 bean 当前正在创建中:是否存在无法解析的循环引用?
但是,又一次,整件事来了,那些 classes 之间没有循环引用。
我已经简化了项目,所以我可以在这里post它:
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE</version>
<relativePath/>
</parent>
<groupId>io.mobi7.ms</groupId>
<artifactId>mobi7-temp-ms-ibutton-worker</artifactId>
<version>1.0.0-SNAPSHOT</version>
<properties>
<spring-cloud-version>2.1.4.RELEASE</spring-cloud-version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws</artifactId>
<version>${spring-cloud-version}</version>
</dependency>
</dependencies>
</project>
S3Configuration.java
package io.mobi7.ms.ibutton.worker;
import com.amazonaws.auth.AWSCredentialsProvider;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.aws.core.io.s3.SimpleStorageProtocolResolver;
import org.springframework.cloud.aws.core.region.RegionProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.DefaultResourceLoader;
@Configuration
public class S3Configuration {
@Bean("amazonS3Client") // THIS METHOD IS NOT BEING CALLED!!!
public AmazonS3 amazonS3Client(AWSCredentialsProvider credentialsProvider,
RegionProvider regionProvider,
@Value("${cloud.aws.s3.default-endpoint}") String endpoint) {
return AmazonS3ClientBuilder.standard()
.withCredentials(credentialsProvider)
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration(endpoint, regionProvider.getRegion().getName()))
.build();
}
@Autowired // THIS METHOD IS NOT BEING CALLED!!!
public void configureResourceLoader(@Qualifier("amazonS3Client") AmazonS3 amazonS3Client,
DefaultResourceLoader resourceLoader) {
SimpleStorageProtocolResolver simpleStorageProtocolResolver = new SimpleStorageProtocolResolver(amazonS3Client);
// As we are calling it by hand, we must initialize it properly.
simpleStorageProtocolResolver.afterPropertiesSet();
resourceLoader.addProtocolResolver(simpleStorageProtocolResolver);
}
}
S3Handle.java
package io.mobi7.ms.ibutton.worker;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.stream.Collectors;
@Component
public class S3Handler {
private AmazonS3 amazonS3Client;
@Autowired
public S3Handler(@Qualifier("amazonS3Client") AmazonS3 amazonS3Client) {
this.amazonS3Client = amazonS3Client;
}
public List<String> listFiles(String bucketName) {
return amazonS3Client.listObjects(bucketName).getObjectSummaries().stream().map(S3ObjectSummary::getKey)
.collect(Collectors.toList());
}
}
Application.java
package io.mobi7.ms.ibutton.worker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(WebApplicationType.NONE).run(args);
}
@Autowired
public void listFiles(S3Handler s3Handler) {
s3Handler.listFiles("default-s3-bucket").forEach(System.out::println);
}
}
application.properties
cloud.aws.region.static=us-east-1
cloud.aws.stack.auto=false
cloud.aws.s3.default-endpoint=http://localhost:4572
任何想法,为什么会这样?
@Autowired
注解标记了构造对象状态的方法(例如setter或方法注入)。请参阅 "Autowired Methods" 部分 here。
您使用 Autowired 注释的两种方法均未用于此需求。
这个问题是关于Spring的。可以删除所有其他标签。
更新: 涵盖了类似案例
不管那里的建议是什么,我都不会保留单个 GOD 配置 class,而是将您的配置 class 拆分为 2 classes - S3 客户端的工厂和资源加载器的配置.