是否可以以一种不被一组配置文件使用的方式配置bean?目前我可以这样做(我相信):
@Profile("!dev, !qa, !local")
是否有更简洁的符号来实现这一目标?我们假设我有很多个人资料。另外,如果我有一个Mock和一些服务(或其他)的具体实现,我可以只注释其中一个,并假设另一个将用于所有其他情况?换句话说,这是必要的:
@Profile("dev, prof1, prof2")
public class MockImp implements MyInterface {...}
@Profile("!dev, !prof1, !prof2") //assume for argument sake that there are many other profiles
public class RealImp implements MyInterface {...}
我可以只注释其中一个,并在另一个上添加@Primary
注释吗?
本质上我想要这个:
@Profile("!(dev, prof1, prof2)")
提前致谢!
答案 0 :(得分:16)
自Spring 5.1 (自Spring Boot 2.1以来)开始,可以在配置文件字符串注释内使用 profile表达式(有关详细信息,请参见Profile.of(..)中的描述详细信息。)
因此,要从特定配置文件中排除bean,可以使用如下表达式:
@Profile("!dev & !prof1 & !prof2")
也可以使用其他逻辑运算符,例如:
@Profile("test | local")
答案 1 :(得分:12)
简短的回答是:你不能。
但由于@Conditional
注释,存在一个简洁的解决方法。
public abstract class ProfileCondition extends SpringBootCondition {
@Override
public ConditionOutcome getMatchOutcome(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
if (matchProfiles(conditionContext.getEnvironment())) {
return ConditionOutcome.match("A local profile has been found.");
}
return ConditionOutcome.noMatch("No local profiles found.");
}
protected abstract boolean matchProfiles(final Environment environment);
}
public class DevProfileCondition extends ProfileCondition {
private boolean matchProfiles(final Environment environment) {
return Arrays.stream(environment.getActiveProfiles()).anyMatch(prof -> {
return prof.equals("dev") || prof.equals("prof1")) || prof.equals("prof2"));
});
}
}
public class ProdProfileCondition extends ProfileCondition {
private boolean matchProfiles(final Environment environment) {
return Arrays.stream(environment.getActiveProfiles()).anyMatch(prof -> {
return !prof.equals("dev") && !prof.equals("prof1")) && !prof.equals("prof2"));
});
}
}
@Conditional(value = {DevProfileCondition.class})
public class MockImpl implements MyInterface {...}
@Conditional(value = {ProdProfileCondition.class})
public class RealImp implements MyInterface {...}
但是,这种方法需要Springboot。
答案 2 :(得分:1)
据我所知,你想要做的是能够用特定配置文件的一些存根/模拟bean替换你的一些bean。有两种方法可以解决这个问题:
第一种选择是可行但困难的。这是因为在@Profile
注释中提供多个配置文件时,Spring的默认行为是OR
条件(不是您在案例中需要的AND
)。 Spring的这种行为更直观,因为理想情况下,每个配置文件应该对应于应用程序的每个配置(生产,单元测试,集成测试等),因此每次只能有一个配置文件处于活动状态。这是OR在配置文件之间比AND
更有意义的原因。因此,您可以通过嵌套配置文件来解决此限制,但是您的配置会非常复杂且难以维护。
因此,我建议你采用第二种方法。为您的应用程序的每个配置设置一个配置文件。对于每个配置,所有相同的bean都可以驻留在不指定@Profile
的类中。因此,这些bean将由所有配置文件实例化。对于每个不同配置应该是不同的剩余bean,您应该为每个Spring配置文件创建一个单独的@Configuration
类,并将所有这些类设置为相应的配置文件@Profile
。这样,在每种情况下都可以很容易地记录注入的内容。
这应该如下所示:
@Profile("dev")
public class MockImp implements MyInterface {...}
@Profile("prof1")
public class MockImp implements MyInterface {...}
@Profile("prof2")
public class MockImp implements MyInterface {...}
@Profile("the-last-profile") //you should define an additional profile, not rely on excluding as described before
public class RealImp implements MyInterface {...}
最后,@Primary
注释用于覆盖现有bean。如果有两个具有相同类型的bean,如果没有@Primary
注释,则会从Spring获得实例化错误。如果为其中一个bean定义@Primary
注释,则不会出现错误,并且会在需要此类型的任何位置注入此bean(另一个将被忽略)。如您所见,这仅在您拥有单个配置文件时才有用。否则,这也将成为第一选择。
TL; DR :是的,你可以。对于每种类型,为每个配置文件定义一个bean,并添加仅@Profile
注释,仅包含此配置文件。
答案 3 :(得分:-1)
您只需使用RealImp
(或您自己的个人资料名称)标记@Profile("Production")
课程,这样您就不需要指定所有其他个人资料。
我可以只注释其中一个,然后粘上一个@Primary注释 另一个呢?
是的,您也可以@Primary
使用RealImp
课程,但要确保在整个项目中使用相同的概念,即换句话说,如果你将一些bean实际实现类(用于实际生产环境)标记为@Profile("Production")
,其中一些标记为@Primary
,那么项目将处于混乱状态。