我想找到一种方法,在Spring容器级别上,以编程方式在bean工厂上的不同实现之间选择候选人。
有了Profiles,我就可以像这样简单地实现它
我有以下配置文件“CH”和“IT”,我希望如果一个Bean配置了IT,那么将回退到默认值。
给定这些类:
默认实现
@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,这是很公平的,因为Default没有被分析,它将被注册,而不会被容器进一步关注。
一些考虑:
如果我将@Profile("default")
添加到DefaultMapper
,这将工作,直到我有另一个默认bean具有仅用CH分析的子类。
另一个Bean的默认实现:
@Component
@Profile("default")
public class DefaultParser {
public void doSomething() {
System.out.println("Parse Default");
}
}
然后是Swiss实现(没有可用的意大利语,或者更好地说,默认值适合意大利语):
@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”)与www.example.com中设置的值相比将适合application.properties即国籍.cantidate= CH。类似于:
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?
帮忙?
2条答案
按热度按时间n6lpvg4x1#
您可以将所有特定的解析器标记为@Primary,这将确保Spring自动连接此解析器,而不是未标记为@Primary的默认解析器。当所选配置文件不存在特定的解析器时,它将返回到非@Primary默认组件。
参见:https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html
piztneat2#
您可以激活多个配置文件,CH和IT,您的实施将失败。
这是一个国际化问题。