返回

如何解决 @ConfigProperties 注解与 @Vetoed 注解的冲突问题?

java

@ConfigProperties@Vetoed 注解的冲突及其解决方案

问题

如果你试图将标注有 @ConfigProperties 注解的 MyConfig 类注入到标注有 @Vetoed 注解的 MyClass 类中,构建过程可能会失败并出现以下错误消息:

...
Caused by: jakarta.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type mycompany.thing.logging.MyConfig and qualifiers [@Default]
         - injection target: parameter 'cfg' of mycompany.thing.logging.MyClass constructor
         - declared on CLASS bean [types=[mycompany.thing.logging.MyClass, java.lang.Object], qualifiers=[@Default, @Any], target=mycompany.thing.logging.MyClass]
         The following classes match by type, but have been skipped during discovery:
         - mycompany.thing.logging.MyConfig was annotated with @Vetoed

解决方法

解决方法是移除 @ConfigProperties 注解,并在 MyConfig 类的每个字段上指定 prefix 参数。修改后的 MyConfig 类如下:

@Dependent
public class MyConfig {

    @ConfigProperty(name = "mycompany.thing.logs.sizeLimit", defaultValue = "5G")
    ByteAmount sizeLimit;

    @ConfigProperty(name = "mycompany.thing.logs.useVDisk", defaultValue = "false")
    boolean useVdisk;

    @ConfigProperty(name = "mycompany.thing.logs.workerInterval", defaultValue = "PT0.1S")
    Duration workerInterval;

    @ConfigProperty(name = "mycompany.thing.logs.maintenanceInterval", defaultValue = "PT15M")
    Duration maintenanceInterval;

    // getters
}

原理

@Vetoed 注解指示 CDI 容器忽略带有该注解的类。当 MyConfig 类被标注有 @Vetoed 注解时,即使它带有 @ConfigProperties 注解,CDI 容器也不会将其识别为配置 bean。因此,MyClass 类无法通过依赖注入获取 MyConfig 实例。

移除 @ConfigProperties 注解并手动在每个字段上指定 prefix 参数,可以使 MyConfig 类仍能从配置中获取值,而无需 CDI 容器将其识别为配置 bean。

常见问题解答

1. 为什么 @Vetoed 注解会影响 @ConfigProperties 注解?

@Vetoed 注解会告诉 CDI 容器忽略带有该注解的类。当 MyConfig 类被标注有 @Vetoed 注解时,CDI 容器就会忽略它,即使它带有 @ConfigProperties 注解,也不会将其识别为配置 bean。

2. 除了移除 @ConfigProperties 注解之外,还有其他解决方法吗?

没有其他解决方法。移除 @ConfigProperties 注解并手动在每个字段上指定 prefix 参数是唯一可行的解决方案。

3. 为什么在每个字段上指定 prefix 参数是必要的?

在每个字段上指定 prefix 参数可以确保 MyConfig 类仍能从配置中获取值。如果不指定 prefix 参数,CDI 容器将无法识别 MyConfig 类中的字段,并且无法将其与配置属性关联。

4. 使用 @ConfigProperties 注解和手动指定 prefix 参数有什么区别?

使用 @ConfigProperties 注解可以自动将相关属性聚合到一个 CDI bean 中。手动指定 prefix 参数需要在每个字段上显式指定属性前缀,但它提供了更大的灵活性,因为它允许你对每个字段使用不同的前缀。

5. 如何在实践中使用此解决方法?

在实践中,你可以按照以下步骤使用此解决方法:

  1. MyConfig 类中移除 @ConfigProperties 注解。
  2. MyConfig 类的每个字段上添加 @ConfigProperty 注解,并指定适当的 prefix 参数。
  3. MyClass 类中,继续使用 @Inject 注释注入 MyConfig 实例。

通过遵循这些步骤,你可以解决 @ConfigProperties 注解和 @Vetoed 注解同时使用时的 Bean 否决问题。