【问题标题】:Unsatisfied dependency expressed through constructor parameter 2通过构造函数参数 2 表示的不满足的依赖关系
【发布时间】:2020-01-06 16:21:14
【问题描述】:

我将 spring 从版本 2.1.1 升级到 2.2.0 。 从那时起,当我启动我的应用程序时,我遇到了以下错误: 原因:org.springframework.beans.factory.NoUniqueBeanDefinitionException:没有可用的“ParentService”类型的合格 bean:预期的单个匹配 bean,但找到了 2:MasterService,SlaveService。

ParentService 是一个接口:

public interface ParentService{
..
}

主服务:

@Service
@MasterProfile
public class MasterService implements ParentService{
.....
}

从服务:

@Service
@SlaveProfile
public class SlaveService implements ParentService{
.....
}

MasterProfile 注释:

@Profile("MASTER")
public @interface MasterProfile {

}

从属配置文件:

@Profile("SLAVE")
public @interface SlaveProfile{

}

我将带有以下标志的配置文件传递给我的应用程序:

-Dspring.profiles.include=MASTER

根据Spring 2.2 release notes,他们做了一些改动,并且在maven中默认启用了fork。因此,传递参数的唯一方法是使用参数 -Dspring-boot.run.jvmArguments 。我使用了-Dspring-boot.run.jvmArguments=-Dspring.profiles.include=MASTER,但仍然失败..

【问题讨论】:

  • 但我有 @Profile 注释,应该可以帮助 spring 确定要自动写入的 bean。正如我所提到的,在 2.1.1 版本中它起作用了。
  • 它们是我自己的注解,只是上面带有@profile注解的简单接口
  • 与 MasterProfile 相同,只是名称不同。将其添加到主帖
  • "以下配置文件处于活动状态:test,native。"这意味着它没有得到配置文件(主或从)。与将配置文件传递给 spring 的方式有关的东西
  • 但如果我想激活多个配置文件?

标签: java spring spring-boot


【解决方案1】:

将配置文件作为参数传递取决于您运行应用的方式。请注意,您提到的文档指的是maven spring-boot plugin

  • 使用 maven 插件:mvn spring-boot:run -Dspring-boot.run.jvmArguments=-Dspring.profiles.include=MASTER
  • 经典Java应用程序:java -Dspring.profiles.include=MASTER -jar ./myapp.jar

在两个 cmd 行中,您可以传递多个参数,如果以, 分隔。请参阅文档:https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-profile-specific-properties

自从升级以来,您现在必须像这样定义您的自定义配置文件注释:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME) // Only this one is really needed
@Profile("SLAVE")
public @interface SlaveProfile {
}

说明:
在 java 中,注解具有 RetentionPolicy,类似于范围。 (见:https://docs.oracle.com/javase/7/docs/api/java/lang/annotation/RetentionPolicy.html)。
如果没有设置任何 RetentionPolicy,默认行为是对 JVM 不可见的注解(即在运行时)。

当您想运行您的应用程序时,您首先要对其进行编译,这意味着将您的.java 文件转换为.class 文件。您的类只是一堆字节码,将您的人类可读文件转换为计算机语言。

然后,当 Spring 加载 ApplicationContext 时,它在引擎盖下的工作以及其他许多事情是读取您的 .class 文件。在这个过程中(见类名:org.springframework.asm.ClassReader)Spring 加载你声明的注解。根据我上面所说,在运行时,您最终会得到“两种”注释:

  • InvisibleAnnotation:@Retention(RetentionPolicy.COMPILE)
  • VisibleAnnotation:@Retention(RetentionPolicy.RUNTIME)

总结并了解它之前为何有效:

  • Spring-boot 2.1.0使用spring-core-5.1.2,它在运行时解释可见和不可见注释,这解释了为什么您的@SlaveProfile@MasterProfile 具有预期的行为。
  • Spring-boot 2.2.0使用spring-core-5.2.0,它在运行时只解释可见的注释,这解释了为什么你的@SlaveProfile@MasterProfile没有预期的行为。

假设 Spring“默默地”修复了一个错误,该错误在不应该读取 Invisible Annotation 时却没有提及。

希望对你有帮助!

【讨论】:

  • 我像您在第二个示例中那样运行该应用程序。不过,它似乎没有通过参数。请注意,它仅在我更改 pom.xml 中的 springboot 版本后才会发生。这是因为他的升级..
  • 请提供您的确切命令行。当你运行你的应用程序时你看到了什么?您是否在控制台的请求中看到类似:The following profiles are active: MASTER 的内容?
  • 我看到了这条消息,但是对于其他配置文件(测试、本机),我在该行中看不到主配置文件。我无法共享整个命令,但我使用的是我在评论中提到的参数。肯定是和spring版本升级有关的事情
  • 所以我需要在不同的命令中传递配置文件并使用注释 @Retention(RetentionPolicy.RUNTIME) ?或者只是注释就足够了?问题不在于我在消息“以下配置文件处于活动状态...”中没有看到配置文件
  • 如果你只添加@Retention(RetentionPolicy.RUNTIME),那么你的profiles就会被激活。您说您使用的是“第二个示例”,即java -D...,但发行说明中提到由 Maven 插件运行的 Spring Boot 应用程序现在默认分叉。哪个,你显然不是。
【解决方案2】:

添加@Profile 不会阻止bean 被实例化。这导致了异常。将@Primary 添加到应用程序不应默认使用的任何bean。

例如,将 @Primary 添加到 MasterProfile bean。

【讨论】:

    猜你喜欢
    • 2019-11-09
    • 1970-01-01
    • 2015-09-06
    • 1970-01-01
    • 2018-10-27
    • 1970-01-01
    • 2021-12-10
    • 2023-03-15
    • 2017-09-24
    相关资源
    最近更新 更多