[英]Resolve Bean Injection Programmatically
Hallo i would like to find a way to elect programmatically a Candidate between different implementation present on the bean factory, at Spring Container Level.你好,我想找到一种方法,以编程方式在 Spring 容器级别的 bean 工厂中存在的不同实现之间选举候选人。
With Profiles i can achieve that simply like this使用配置文件,我可以像这样简单地实现
I Have the following Profiles "CH" and "IT" and i want that if a Bean Profiled with IT is there, then will fallback to default.我有以下配置文件“CH”和“IT”,我希望如果存在带有 IT 的 Bean 配置文件,则将回退到默认值。
Given those classes:鉴于这些类:
The Default Implementation默认实现
@Component
public class DefaultMapper {
public void doSomething() {
System.out.println("Map Default");
}
}
The Swiss Implementation瑞士实施
@Component
@Profile("CH")
public class SwissMapper extends DefaultMapper {
@Override
public void doSomething() {
System.out.println("do something swiss");
}
}
The Italian Implementation:意大利实施:
@Component
@Profile("IT")
public class ItalianMapper extends DefaultMapper {
@Override
public void doSomething() {
System.out.println("do pasta");
}
}
Now if i run it with @ActiveProfiles("IT")
it throws a NoUniqueBeanDefinitionException, which is fair enough, since the Default is not profiled, and it will be registered without any further attention by the container.现在,如果我用
@ActiveProfiles("IT")
运行它,它会抛出一个 NoUniqueBeanDefinitionException,这很公平,因为默认值没有被分析,并且它将被注册而不会受到容器的任何进一步关注。
Some Consideration:一些考虑:
if i add @Profile("default")
to DefaultMapper
this will work until i have another default bean has a subclass profiled ONLY with CH.如果我将
@Profile("default")
添加到DefaultMapper
这将起作用,直到我有另一个默认 bean 的子类仅使用 CH 进行了分析。
Default Implementation of another Bean:另一个 Bean 的默认实现:
@Component
@Profile("default")
public class DefaultParser {
public void doSomething() {
System.out.println("Parse Default");
}
}
Then the Swiss implementation (No italian is available, or better said the default fits for italian):然后是瑞士的实现(没有意大利语可用,或者最好说默认适合意大利语):
@Component
@Profile("CH")
public class SwissParser extends DefaultParser {
@Override
public void doSomething() {
System.out.println("Ässe Ässe");
}
} }
Now if i run it with @ActiveProfiles("IT")
it throws a No BeanDefinitionException, which is fair enough, but not that fair, since the "default" is not chained as ActiveProfiles and for IT i have no implementation.现在,如果我用
@ActiveProfiles("IT")
运行它,它会抛出一个 No BeanDefinitionException,这足够公平,但不是那么公平,因为“默认”没有链接为 ActiveProfiles,对于 IT 我没有实现。 the CH profile here will work since has a profiled implementation for each default class.此处的 CH 配置文件将起作用,因为每个默认类都有一个配置文件实现。
Said That I would like a better way to cover this scenario without: - Having to define on the Default Classes such @Profile({"default","IT", "<all other profiles which have NOT a specialized implementation"}
, or @Profile("!CH")
where i exclude those profiles which have a specialization. - @Primary
i think is not a soultion, because on the DefaultMapper
i have to Specialization which will be marked as @Primary
and the container doesn't like it at all ;)说我想要一种更好的方法来覆盖这种情况,而无需: - 必须在默认类上定义,例如
@Profile({"default","IT", "<all other profiles which have NOT a specialized implementation"}
,或@Profile("!CH")
其中我排除了那些具有专业化的配置文件。 - @Primary
我认为不是一个灵魂,因为在DefaultMapper
我必须专业化,它将被标记为@Primary
并且容器不喜欢它根本;)
Then I would like to solve this where i can decide for ALL the injected Classes, when the resolution of the Beans is ambigous then i would like to programmatically decide (in container) which implementation i would like to pick.然后我想解决这个问题,我可以决定所有注入的类,当 Bean 的解析不明确时,我想以编程方式决定(在容器中)我想选择哪个实现。 I think an Annotation likewise to @Profile , iE @Candidate("CH") will suit compared to a value set in application.properties in a iE nationality.cantidate=CH.
我认为与 @Profile 类似的 Annotation ,iE @Candidate("CH") 与 iE nationality.cantidate=CH 中 application.properties 中设置的值相比更适合。 Something like:
就像是:
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);
}
}
I've done in the past Something similar with CDI SPI extension wich is elegant, and also i could cover this in another way with @Specializes
from CDI, but i cannot find the same easy way on Spring (i don't have so much experience on it), BeanFactory?我过去做过类似 CDI SPI 扩展的事情,非常优雅,我也可以用 CDI 的
@Specializes
以另一种方式覆盖这个,但我在 Spring 上找不到同样简单的方法(我没有那么多经验就可以了),BeanFactory? BeanFactoryPostProcessor ? BeanFactoryPostProcessor ?
Help ?帮助 ?
You can mark all your specific Parsers as @Primary this will make sure Spring autowires this one instead of the default one which is not marked as @Primary.您可以将所有特定的解析器标记为 @Primary,这将确保 Spring 自动装配这个解析器,而不是未标记为 @Primary 的默认解析器。 When no specific Parsers exist for the chosen profile it will fall back to the non @Primary default component.
当所选配置文件不存在特定解析器时,它将回退到非 @Primary 默认组件。
See: https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html请参阅: https : //docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Primary.html
@Component
public class DefaultParser {
public void doSomething() {
System.out.println("Parse Default");
}
}
@Component
@Primary
@Profile("CH")
public class SwissParser extends DefaultParser {
@Override
public void doSomething() {
System.out.println("Ässe Ässe");
}
You can activate multiple profiles, CH and IT and your implementation will fail.您可以激活多个配置文件、CH 和 IT,您的实施将失败。
It is a internationalization problem.这是一个国际化问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.