Spring Boot配置:在多个@Profile上跳过注册

29
我有一个Spring Boot应用程序,有不同的配置文件设置: devprodqcconsole等。
两个配置类如下设置。 MyConfigurationA 应该在除了 console 之外的所有配置文件中注册。 MyConfigurationB 应该在除了 consoledev 的所有配置文件中注册。
当我使用配置文件 console 运行应用程序时,MyConfigurationA 不会被注册 - 这是可以接受的。但是 MyConfigurationB 被注册了 - 这并不是我想要的。我已经按照以下方式设置了 @Profile 注释,以便在配置文件 consoledev 中不注册 MyConfigurationB
但是,当我使用配置文件 console 运行应用程序时,MyConfigurationB 仍然被注册了。
@Profile({ "!" + Constants.PROFILE_CONSOLE ,  "!" + Constants.PROFILE_DEVELOPMENT })

文档(http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Profile.html)中有一个包含一个配置文件和排除另一个配置文件的示例。在我的示例中,我将两个配置文件都排除了:@Profile({"!p1", "!p2"})

@Profile({"p1", "!p2"}),如果激活了配置文件 'p1' 或者 没有激活配置文件 'p2',就会发生注册。

我的问题是:我们如何跳过两个配置文件的配置注册?@Profile({"!p1", "!p2"}) 是 OR 运算。我们需要 AND 运算。


代码:

@Configuration
@Profile({ "!" + Constants.PROFILE_CONSOLE  })
public class MyConfigurationA {
    static{
        System.out.println("MyConfigurationA registering...");
    }
}

@Configuration
@Profile({ "!" + Constants.PROFILE_CONSOLE ,  "!" + Constants.PROFILE_DEVELOPMENT }) // doesn't exclude both, its OR condition
public class MyConfigurationB {
    static{
        System.out.println("MyConfigurationB registering...");
    }
}

public final class Constants {
    public static final String PROFILE_DEVELOPMENT = "dev";
    public static final String PROFILE_CONSOLE = "console";
    ...
}
4个回答

44

@Profile({"!console", "!dev"}) 表示(非 console)(非 dev),如果你使用'console'配置文件运行应用程序,则为真。
为解决这个问题,您可以创建一个自定义的Condition

public class NotConsoleAndDevCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        return !environment.acceptsProfiles("console", "dev");
    }
}

并通过 @Conditional 注解将条件应用于配置:

@Conditional(NotConsoleAndDevCondition.class)
public class MyConfigurationB {

6
可以使用@Profile注释和配置文件表达式来代替创建自定义条件。配置文件表达式是具有配置文件作为操作数的逻辑表达式。例如: @Profile({"!p1 & !p2"})。参考文献:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Profile.html - Ranjan
截至最新的Spring更新,@RanjanMohanty的答案简明、逻辑清晰且达到了预期效果。 - ashfaq

25

从Spring 5.1开始,您可以在@Profile注释中使用表达式。在@Profile文档中了解更多信息。例如:

@Configuration
@Profile({ "!console & !dev" }) 
public class MyConfigurationB {
    static{
        System.out.println("MyConfigurationB registering...");
    }
}

1
这种方法已经有文档记录,但似乎并没有像宣传的那样有效。 - Fritz Duchardt
1
这种方法仅适用于 Spring 5.1 => Spring Boot 2.1 或更高版本。 - t0r0X

5

随着Spring的更新,接受字符串的acceptsProfiles方法已被弃用。

要执行与Cyril's question中相同的工作,您需要利用new method parameter。这种新格式还使您能够编写比以前更强大的配置文件表达式,从而消除了否定整个acceptsProfiles表达式的需要。

public class NotConsoleAndDevCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        return environment.acceptsProfiles(Profiles.of("!console & !dev"));
    }
}

0

另一种解决方案是,不要排除掉两个配置文件(console,dev),而是包含所有其他配置文件。

@Profile({"qc", "prod"})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接