Spring 启动配置跳过注册多个@Profile

Spring Boot Configuration skip registration on multiple @Profile

我有一个 Spring 使用不同配置文件设置的启动应用程序: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"}), registration will occur if profile 'p1' is active OR if profile 'p2' is not active.

我的问题是:我们怎样才能跳过两个配置文件的配置注册? @Profile({"!p1", "!p2"}) 正在进行或运算。这里需要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";
    ...
}

@Profile({"!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 {

对于较新版本的 Spring,接受字符串的 acceptsProfiles 方法已被弃用。

做与 , you would need to leverage the 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"));
    }
}

从 Spring 5.1 开始,您可以使用 expressions in @Profile annotation. Read more in the @Profile documentation。示例:

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

另一种解决方案是不排除 2 个配置文件(控制台、开发),您可以只包括所有其他配置文件

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