SpringBoot - BeanDefinitionOverrideException:无效的bean定义
Posted
技术标签:
【中文标题】SpringBoot - BeanDefinitionOverrideException:无效的bean定义【英文标题】:SpringBoot - BeanDefinitionOverrideException: Invalid bean definition 【发布时间】:2019-05-12 09:27:33 【问题描述】:我正在尝试使用 Spring Boot 在本地设置 DynamoDB。最初,我使设置正常工作,并且能够通过存储库写入/保存到 DynamoDB。从那时起,我添加了更多类来构建我的应用程序。现在,当我尝试启动我的应用程序时,出现以下异常:
org.springframework.beans.factory.support.BeanDefinitionOverrideException: Invalid bean definition with name 'agentRepository' defined in null: Cannot register bean definition [Root bean: class [org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] for bean 'agentRepository': There is already [Root bean: class [org.socialsignin.spring.data.dynamodb.repository.support.DynamoDBRepositoryFactoryBean]; scope=; abstract=false; lazyInit=false; autowireMode=0; dependencyCheck=0; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null] bound.
我已经广泛搜索了 SO 和互联网,但没有任何有用的解决方案。错误消息也具有误导性。
我的项目具有以下层次结构
ai.test.as
- as
- agent
- business
- intent
- exception
- Agent.java
- AgentDTO.java
- AgentRespository.java
- AgentController.java
- AgentService.java
- AgentServiceImpl.java
- config
- DynamoDBConfig.java
DynamoDBConfig.java
package ai.test.as.config;
import ai.test.as.agent.AgentRepository;
import ai.test.as.agent.intent.template.TemplateRepository;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient;
import org.socialsignin.spring.data.dynamodb.repository.config.EnableDynamoDBRepositories;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@EnableDynamoDBRepositories(basePackageClasses = AgentRepository.class)
public class DynamoDBConfig
@Value("$aws.dynamodb.endpoint")
private String dynamoDBEndpoint;
@Value("$aws.auth.accesskey")
private String awsAccessKey;
@Value("$aws.auth.secretkey")
private String awsSecretKey;
@Bean
public AmazonDynamoDB amazonDynamoDB()
AmazonDynamoDB dynamoDB = new AmazonDynamoDBClient(getAwsCredentials());
dynamoDB.setEndpoint(dynamoDBEndpoint);
return dynamoDB;
@Bean
public AWSCredentials getAwsCredentials()
return new BasicAWSCredentials(awsAccessKey, awsSecretKey);
AgentRepository.java
package ai.test.as.agent;
import ai.test.as.agent.Agent;
import org.socialsignin.spring.data.dynamodb.repository.EnableScan;
import org.springframework.data.repository.CrudRepository;
@EnableScan
public interface AgentRepository extends CrudRepository<Agent, String>
AgentController.java(使用 AgentRepository 的地方)
@RestController
@RequestMapping(value = "/v1/agents")
public class AgentController
@Autowired
private AgentRepository agentRepository;
@RequestMapping(value = "/test", method = RequestMethod.POST)
public void test()
Agent agent = new Agent();
agent.setAgentNumber("123456");
agent.setId(1);
agentRepository.save(agent);
Spring 建议如下:
> The bean 'agentRepository', defined in null, could not be registered. A bean with that name has already been defined in null and overriding is disabled
.
null
在这里是什么意思?是因为我的应用程序配置有问题吗?还有怎么可能已经注册了?
请给我一些指示,因为我对接下来的步骤感到很困惑。
【问题讨论】:
你试过用 @Component 注释 AgentRepository 吗? 以前我尝试没有使用@Component
注释从 DynamoDB 读写。但尽管如此,我现在按照你提到的那样尝试了,但它不起作用。
关于您的问题,如果 bean 已经注册,您可以使用 ApplicationContext 对象的 getBeanDefinitionNames() 方法打印上下文中的所有 bean。通过在控制台中打印它们,您可以查看使用了哪些 bean 键。网上有很多例子,这里就不分享了
您能否在您的 AgentRepository 类中添加 [@Repository] 或 [@Service] 注释并尝试一下?而且您的 AgentRepository 是一个接口,是否有使用接口而不是类的用例。
嗨,你解决了吗?我刚遇到同样的问题!
【参考方案1】:
从 Spring Boot 2.1 开始必须启用 Bean 覆盖,
https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.1-Release-Notes
Bean 覆盖
默认情况下禁用 Bean 覆盖以防止意外覆盖 bean。如果您依赖覆盖,则需要将 spring.main.allow-bean-definition-overriding 设置为 true。
设置
spring.main.allow-bean-definition-overriding=true
或yml,
spring:
main:
allow-bean-definition-overriding: true
再次启用覆盖。
编辑,
Bean Overriding 是基于 bean 的名称而不是它的类型。例如
@Bean
public ClassA class()
return new ClassA();
@Bean
public ClassB class()
return new ClassB();
在> 2.1中会导致这个错误,默认bean名称取自方法名称。重命名方法或将name
属性添加到Bean
注释将是有效的修复方法。
【讨论】:
嘿,谢谢您的回答。但是我可以知道为什么我应该覆盖 bean 吗?我确信我只创建了AgentRepository
的一个 bean。那么什么被覆盖了?
阅读那个不是它所遵守的异常。它抱怨DynamoDBRepositoryFactoryBean
bean。我假设它已经通过引导应用程序注册,并且不需要@EnableDynamoDBRepositories(basePackageClasses = AgentRepository.class)
。也向那些拒绝投票的人解释原因。
认为它很脏,因为它是 Spring Framework 中的一个特性,并且被广泛使用。删除 EnableDynamoDBRepositories(basePackageClasses = AgentRepository.class)
我解决了它,但如果我不得不猜测它可能会再次触发 bean 的创建,我将无法访问 Dynamo 设置,但如果它没有解决它,我会提出问题并提供一个例子。
@DarrenForsythe 仅供参考我尝试删除 @EnableDynamoDBRepositories
并删除了覆盖属性,但问题仍然存在。所以我认为无论如何都需要上述注释。
我假设这是一个第三方库给定的包,我会通过一个简单的例子联系维护者。可能依赖于压倒一切的功能【参考方案2】:
例如,使用这种方法启用 bean 覆盖
@SpringBootTest(properties = "spring.main.allow-bean-definition-overriding=true")
或
@SpringBootApplication (properties = "spring.main.allow-bean-definition-overriding=true")
【讨论】:
请注意,如果它是一个测试 bean,您的解决方案几乎相同,不要依赖 bean 命名。重命名它,如果需要,使用主要注入它 你能解释一下为什么这是必要的吗?【参考方案3】:我认为我在使用 MongoDB 时遇到了同样的问题。至少错误消息看起来完全一样,而且我也只有一个 MongoDB 存储库,如下所示:
public interface MyClassMongoRepository extends MongoRepository<MyClass, Long>
问题是由之前在另一个数据库中使用过的类 MyClass 引起的。 Spring 在创建 MongoRepository 之前默默地创建了一些 JpaRepository。两个存储库具有相同的名称,这会导致冲突。
解决方案是制作 MyClass 的副本,将其移动到 MongoRepository 的包中并删除任何 JPA 特定的注释。
【讨论】:
是的,这可以解决问题,但是它将您的代码与持久性提供程序 (MongoDB) 联系在一起,这违背了 JPA 的目的。 @AhmadAbdelghany,我知道这一点,但我只是想为不想更改全局选项来解决本地问题的开发人员提供另一种选择。【参考方案4】:我在尝试通过 spring-data-jdbc 将 PostgreSQL 数据库添加到已经使用 MongoDB 的现有项目时偶然发现了同样的问题。
问题似乎在于 MongoDB 和 PostgreSQL 的存储库被两个模块(spring-mongo 和 spring-jdbc)扫描。他们都试图创造一些豆子并发生冲突。
在我的例子中,MongoDB 存储库和 PostgreSQL 存储库在同一个包中。
接受的答案为我解决了问题 - 但我从这个启动日志中得到了一些提示:
Finished Spring Data repository scanning in 319ms. Found 4 repository interfaces
Finished Spring Data repository scanning in 319ms. Found 5 repository interfaces
这很奇怪,因为我只有 1 个 PostgreSQL 存储库和 4 个 MongoDB 存储库。
我将 PostgreSQL 存储库移动到与 MongoDB 存储库不同的包中,并将 PostgreSQL 存储库的基本包配置为新包。 就我而言:
@EnableJdbcRepositories(basePackageClasses = MyOnlyPostgreSQLRepository.class) // TODO: Use the real package or a dedicated base class
这为我解决了这个问题(没有为 bean 覆盖设置属性 - 我更喜欢)。启动日志现在还显示了正确数量的存储库(1 和 4)。
【讨论】:
是的,我可以确认使用@EnableJpaRepositories(basePackages = "A.repository", "A.common.repository") 添加一个额外的@Configuration bean,解决了我的问题(我在主项目(包 A.repository)和该项目引用的中间库(包 A.common.repository)中都定义了 Repository 对象)【参考方案5】:在我的例子中,2 个 maven 依赖项是用同一个 Bean 定义的。
我在为我的所有项目发布mvn dependency:tree
时发现了这一点。
【讨论】:
【参考方案6】:我遇到了同样的问题,问题是多个存储库工厂试图向它们注册所有存储库接口。就我而言,它是JpaRepositoryFactoryBean
和DynamoDBRepositoryFactoryBean
。如其他答案中所述,您可以在以下指示的日志中看到:
[INFO] Bootstrapping Spring Data DynamoDB repositories in DEFAULT mode.
[INFO] Finished Spring Data repository scanning in 64ms. Found 2 DynamoDB repository interfaces.
[INFO] Bootstrapping Spring Data JPA repositories in DEFAULT mode.
解决办法是:
-
通过检查compatibility matrix 确保您使用的是兼容版本的 spring-data-dynamodb / spring-boot / spring-data
确保每个存储库只创建一次。就我而言,我必须添加
@SpringBootApplication
@EnableAutoConfiguration(exclude =
DataSourceAutoConfiguration.class,
DataSourceTransactionManagerAutoConfiguration.class,
HibernateJpaAutoConfiguration.class)
配置可能在不同版本中有所不同,具体取决于您的应用程序中有多少个存储库。阅读Multi-Repository-configuration 可能会有所帮助
【讨论】:
以上是关于SpringBoot - BeanDefinitionOverrideException:无效的bean定义的主要内容,如果未能解决你的问题,请参考以下文章
[转]Spring中property-placeholder的使用与解析
SpringBoot入门到精通-SpringBoot自动配置原理
SpringBoot入门到精通-SpringBoot启动流程