【发布时间】:2017-10-25 09:37:29
【问题描述】:
您好,我想找到一种方法,以编程方式在 Spring 容器级别的 bean 工厂上的不同实现之间选择候选人。
使用 Profiles 我可以像这样简单地实现这一目标
我有以下配置文件“CH”和“IT”,我希望如果有一个带有 IT 配置的 Bean,那么将回退到默认值。
鉴于这些类:
默认实现
@Component
public class DefaultMapper {
public void doSomething() {
System.out.println("Map Default");
}
}
瑞士实施
@Component
@Profile("CH")
public class SwissMapper extends DefaultMapper {
@Override
public void doSomething() {
System.out.println("do something swiss");
}
}
意大利实施:
@Component
@Profile("IT")
public class ItalianMapper extends DefaultMapper {
@Override
public void doSomething() {
System.out.println("do pasta");
}
}
现在,如果我使用@ActiveProfiles("IT") 运行它,它会抛出 NoUniqueBeanDefinitionException,这很公平,因为默认值没有被分析,并且它将被注册而不会被容器进一步关注。
一些考虑:
如果我将@Profile("default") 添加到DefaultMapper,这将一直有效,直到我有另一个默认 bean 的子类仅使用 CH 进行配置。
另一个 Bean 的默认实现:
@Component
@Profile("default")
public class DefaultParser {
public void doSomething() {
System.out.println("Parse Default");
}
}
然后是瑞士的实现(没有意大利语可用,或者更好地说默认适合意大利语):
@Component
@Profile("CH")
public class SwissParser extends DefaultParser {
@Override
public void doSomething() {
System.out.println("Ässe Ässe");
}
}
现在,如果我使用@ActiveProfiles("IT") 运行它,它会抛出 No BeanDefinitionException,这很公平,但不是那么公平,因为“默认”没有链接为 ActiveProfiles,对于 IT,我没有实现。此处的 CH 配置文件将起作用,因为每个默认类都有一个配置文件实现。
说过
我想要一种更好的方法来涵盖这种情况,而无需:
- 必须在默认类上定义 @Profile({"default","IT", "<all other profiles which have NOT a specialized implementation"} 或 @Profile("!CH") 我排除那些具有专业化的配置文件。
- @Primary 我认为这不是灵魂,因为在 DefaultMapper 上我必须进行专业化,这将被标记为 @Primary 并且容器根本不喜欢它;)
然后 我想解决这个问题,我可以决定所有注入的类,当 Bean 的分辨率不明确时,我想以编程方式决定(在容器中)我想选择哪个实现。我认为与@Profile 类似的注释,即@Candidate("CH") 将适合与在i.E nationality.cantidate=CH 中的application.properties 中设置的值相比。比如:
public class MyExtension extends UnknowSpringType {
@Override
Object resolveAmbigousDependency(final Context ctx, final Resolution resolution) {
final List<Class> clazzes = resolution.getResolvedClasses();
for (final Class clazz : clazzes) {
if (clazz.isAnnotationPresent(Candidate.class) && clazz.getAnnotation(Candidate.class).getVaue().equals(candidateApplicationPropertyValue)) {
return clazz;
}
return getDefaultImplementation(clazzes);
}
}
我过去做过与 CDI SPI 扩展类似的事情,它很优雅,而且我可以用 CDI 的 @Specializes 以另一种方式来解决这个问题,但我在 Spring 上找不到同样简单的方法(我没有没有这么多经验),BeanFactory? BeanFactoryPostProcessor ?
帮助?
【问题讨论】:
标签: java spring spring-boot spring-profiles