[英]Dynamic dependency injection in spring
我正在尋找一種方法來創建一個可以“部分”自動裝配的非單件彈簧豆。
@Component
class Example {
private SpringBean1 bean1;
private SpringBean2 bean2;
private String dynamicDependancy;
@Autowired
public Example(SpringBean1 bean1, SpringBean2 bean2, String dynamicDepedency) {
this.bean1 = bean1;
this.bean2 = bean2;
this.dynamicDepedency = dynamicDepedency;
}
}
我想要這樣的事情,因為有時只有在運行時才知道依賴。 我有一種方法可以創建一種創建靜態成員類的工廠,這樣我就可以測試靜態成員類:
@Component
class ExampleFactory {
private SpringBean1 bean1;
private SpringBean2 bean2;
@Autowired
public ExampleFactory(SpringBean1 bean1, SpringBean2 bean2) {
this.bean1 = bean1;
this.bean2 = bean2;
}
public Example from(String dynamicDependency) {
return new Example(bean1, bean2, dynamicDependency);
}
static class Example {
private SpringBean1 bean1;
private SpringBean2 bean2;
private String dynamicDependancy;
public Example(SpringBean1 bean1, SpringBean2 bean2, String
dynamicDependancy) {
this.bean1 = bean1;
this.bean2 = bean2;
this.dynamicDependancy = dynamicDependancy;
}
}
}
我正在查看Prototype范圍,並使用getBean(java.lang.String,java.lang.Object)使得更難使用依賴注入。 我想知道是否有任何“春天的方式”來做這些事情。
謝謝。
更新:我找到了另一個解決方案,並在另一篇文章中發布了答案: https : //stackoverflow.com/a/52021965/2580829
使用由Spring注入的工廠然后公開創建Example
實例的方法的基本方法是我如何做到這一點,所以它基本上是正確的。 如果您希望Spring使用其現代功能透明地完成此操作,您可以將@Configuration
類與查找方法注入結合使用,以從單例范圍的bean創建Example
on-demand的實例。
一,配置類:
@Configuration
public class DemoConfiguration {
@Autowired IFooBean fooBean;
@Autowired IBarBean barBean;
@Bean()
@Scope("prototype")
Example newExample(String name) {
return new Example(fooBean, barBean, name);
}
}
這里應該沒有什么太令人驚訝的了,除了newExample
的name
參數。 您可以像我上面那樣自動裝配容器可以滿足的依賴項( fooBean
和barBean
),但是由於配置類的實例與Spring的任何其他bean一樣,您還可以使用任何其他機制:將ObjectFactory
或ObjectProvider
注入配置讓它實現ApplicationContextAware
,甚至為它們使用查找方法注入。 如果您需要避免fooBean
和barBean
初始化,如果它們被自動裝配到配置bean中,那么這將非常有用。
不要忘記將工廠方法的范圍設置為"prototype"
,否則Spring將返回您使用的第一個bean,即使您為name
傳遞了不同的值。
Example
本身的實現類似於你問題中的實現:
public class Example {
IFooBean fooBean;
IBarBean barBean;
String name;
public Example(IFooBean fooBean, IBarBean barBean, String name) {
System.out.printf("%s(fooBean=%s, barBean=%s, name=%s)\n", this, fooBean, barBean, name);
this.fooBean = fooBean;
this.barBean = barBean;
this.name = name;
}
}
然后,在您實際需要Example
實例的位置,使用@Lookup
注入工廠方法:
public interface IUsesExample {
void doThing();
}
@Component
public class UsesExample implements IUsesExample {
@Lookup
protected Example getExample(String name) {return null;};
public void doThing() {
System.out.printf("%s.doThing(getExample() = %s)\n", this, getExample("aaa"));
System.out.printf("%s.doThing(getExample() = %s)\n", this, getExample("bbb"));
}
}
要使用@Component
和掃描,這必須是一個具體的類,這意味着我們需要一個getExample()
的虛擬實現; Spring將使用CGLIB替換它,調用上面DemoConfiguration
定義的工廠方法。 Spring將正確地將參數從lookup方法傳遞給factory方法。
出於測試目的,我只使用不同的name
值調用getExample()
兩次,以證明我們每次都注入了正確的東西,從而得到一個不同的實例。
使用以下小型Spring Boot應用程序對此進行測試:
@SpringBootApplication
public class DemoApplication {
@Autowired IUsesExample usesExample;
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@PostConstruct
void run() {
usesExample.doThing();
}
}
給出以下輸出:
com.example.demo.FooBean@fd46303
com.example.demo.BarBean@6a62689d
com.example.demo.Example@66629f63(fooBean=com.example.demo.FooBean@fd46303, barBean=com.example.demo.BarBean@6a62689d, name=aaa)
com.example.demo.UsesExample$$EnhancerBySpringCGLIB$$68b994e8@6c345c5f.doThing(getExample() = com.example.demo.Example@66629f63)
com.example.demo.Example@6b5966e1(fooBean=com.example.demo.FooBean@fd46303, barBean=com.example.demo.BarBean@6a62689d, name=bbb)
com.example.demo.UsesExample$$EnhancerBySpringCGLIB$$68b994e8@6c345c5f.doThing(getExample() = com.example.demo.Example@6b5966e1)
那是:
FooBean
被創建 BarBean
被創建 name
創建一個Example
Example
返回到UseExample
Example
,使用相同的FooBean
和BarBean
,並且這次將name
設置為"bbb"
。 我假設您熟悉如何設置基於Java的配置和組件掃描以及上述示例所依賴的所有其他管道。 我使用Spring Boot以簡單的方式獲得整個shebang。
如果您正在從其他原型范圍的bean創建Example
s,那么可能有一種方法可以通過范圍傳遞僅運行時依賴項的值,但我不知道在哪里開始回答如何執行此操作,尤其是在不知道的情況下bean的實際范圍以及它們之間的關系。 無論哪種方式,上述解決方案似乎更簡單易懂。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.