[英]How to resolve circular dependency for Spring context?
我有三個班級:
open class RedirectProcessor(
private val adProcessor: AdProcessor
) {
fun run(depth: Int): String =
if (depth < 3) adProcessor.run(depth + 1) else "redirect"
}
open class FallbackProcessor(
private val adProcessor: AdProcessor
) {
fun run(depth: Int): String =
if (depth < 3) adProcessor.run(depth + 1) else "fallback"
}
open class AdProcessor(
private val redirectProcessor: RedirectProcessor,
private val fallbackProcessor: FallbackProcessor
) {
fun run(depth: Int): String =
depth.toString() +
redirectProcessor.run(depth) +
fallbackProcessor.run(depth)
}
因此,它們相互依賴。 我嘗試配置 spring 上下文如下:
@Configuration
class Config {
@Bean
@Lazy
fun redirectProcessor(): RedirectProcessor = RedirectProcessor(adProcessor())
@Bean
@Lazy
fun fallbackProcessor(): FallbackProcessor = FallbackProcessor(adProcessor())
@Bean
fun adProcessor() = AdProcessor(
redirectProcessor = redirectProcessor(),
fallbackProcessor = fallbackProcessor()
)
}
我知道我必須使用 @Lazy 注釋。 如果我用 @Component 注釋標記我的服務並在構造函數中使用 @Lazy 它工作正常。 但是我需要使用 @Bean 注釋來定義 bean,這會導致問題。 有什么辦法可以解決嗎?
I can't say for Kotlin (my knowledge of kotlin is rather limited at this point), but in Java with the last available spring version (5.2.6.RELEASE)
我已經將它與您的示例的以下“kotlin to java”翻譯一起使用:
public class RedirectProcessor {
private final AdProcessor adProcessor;
public RedirectProcessor(AdProcessor adProcessor) {
this.adProcessor = adProcessor;
}
public String run(int depth) {
if(depth < 3) {
return adProcessor.run(depth + 1);
}
else {
return "redirect";
}
}
}
public class FallbackProcessor {
private final AdProcessor adProcessor;
public FallbackProcessor(AdProcessor adProcessor) {
this.adProcessor = adProcessor;
}
public String run(int depth) {
if(depth < 3) {
return adProcessor.run(depth + 1);
}
else {
return "fallback";
}
}
}
public class AdProcessor {
private RedirectProcessor redirectProcessor;
private FallbackProcessor fallbackProcessor;
public AdProcessor(RedirectProcessor redirectProcessor, FallbackProcessor fallbackProcessor) {
this.redirectProcessor = redirectProcessor;
this.fallbackProcessor = fallbackProcessor;
}
public String run (int depth) {
return depth + redirectProcessor.run(depth) + fallbackProcessor.run(depth);
}
}
然后訣竅是以不同的方式使用配置(但從 Java 配置規則的角度來看,這是完全“合法”的方式):
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Bean
public RedirectProcessor redirectProcessor (@Lazy AdProcessor adProcessor) {
return new RedirectProcessor(adProcessor);
}
@Bean
public FallbackProcessor fallbackProcessor (@Lazy AdProcessor adProcessor) {
return new FallbackProcessor(adProcessor);
}
@Bean
public AdProcessor adProcessor (RedirectProcessor redirectProcessor, FallbackProcessor fallbackProcessor) {
return new AdProcessor(redirectProcessor, fallbackProcessor);
}
@EventListener
public void onApplicationStarted(ApplicationStartedEvent evt) {
AdProcessor adProcessor = evt.getApplicationContext().getBean(AdProcessor.class);
String result = adProcessor.run(2);
System.out.println(result);
}
}
注意@Lazy
注釋在參數上的使用,而不是在 bean 本身上。
偵聽器僅用於測試目的。 運行應用程序打印23redirectfallback3redirectfallback
現在為什么它起作用了?
當 spring 看到這樣的@Lazy
注釋參數時,它會根據參數 class 創建運行時生成的代理(使用 CGLIB)。
此代理以包裝 bean 的方式運行,並且僅當它第一次“需要”時才會完全創建此 bean(請閱讀,在這種情況下我們將調用此 bean 的方法)。
如果您使用@Component
它與以下聲明相同:
@Component
public class FallbackProcessor {
private final AdProcessor adProcessor;
public FallbackProcessor(@Lazy AdProcessor adProcessor) {
this.adProcessor = adProcessor;
}
public String run(int depth) {
...
}
}
附帶說明一下,我沒有在最后一個示例中將@Autowired
放在FallbackProcessor
class 的構造函數上,只是因為如果有一個構造函數 spring 將“識別”並使用它來注入所有依賴項。
我遇到了同樣的問題, @Autowire
注釋由於某種我不知道的原因不起作用。
所以我使用了另一種解決方法:
ApplicationContext
而不是 bean 本身ApplicationContext
檢索 bean 實例代碼如:
class ServiceA(
private val serviceB: ServiceB
) {
......
}
class ServiceB(
private val applicationContext: ApplicationContext
) {
private val serviceA: ServiceA by lazy {
// we need this logic for only once
// so "property delegated by lazy ..." is perfect for this purpose
applicationContext.getBean(ServiceA::class.java)
}
......
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.