簡體   English   中英

以編程方式解決 Bean 注入問題

[英]Resolve Bean Injection Programmatically

你好,我想找到一種方法,以編程方式在 Spring 容器級別的 bean 工廠中存在的不同實現之間選舉候選人。

使用配置文件,我可以像這樣簡單地實現

我有以下配置文件“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 類似的 Annotation ,iE @Candidate("CH") 與 iE 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 ?

幫助 ?

您可以將所有特定的解析器標記為 @Primary,這將確保 Spring 自動裝配這個解析器,而不是未標記為 @Primary 的默認解析器。 當所選配置文件不存在特定解析器時,它將回退到非 @Primary 默認組件。

請參閱: 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");
}

您可以激活多個配置文件、CH 和 IT,您的實施將失敗。

這是一個國際化問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM