Java 如何解决Spring上下文的循环依赖关系?
我有三门课:Java 如何解决Spring上下文的循环依赖关系?,java,spring,kotlin,Java,Spring,Kotlin,我有三门课: open class RedirectProcessor( private val adProcessor: AdProcessor ) { fun run(depth: Int): String = if (depth < 3) adProcessor.run(depth + 1) else "redirect" } 因此,它们相互依赖。我尝试如下配置spring上下文: @Configuration class Config {
open class RedirectProcessor(
private val adProcessor: AdProcessor
) {
fun run(depth: Int): String =
if (depth < 3) adProcessor.run(depth + 1) else "redirect"
}
因此,它们相互依赖。我尝试如下配置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 annotation标记我的服务,并在构造函数中使用@Lazy,它就可以正常工作。但是我需要使用@Bean注释定义Bean,这会导致问题。有什么办法可以解决这个问题吗?我不能说是Kotlin(目前我对Kotlin的了解非常有限),而是使用Java和最新的spring版本(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);
}
}
注意@Lazy
注释在参数上的用法,而不是在bean本身上
侦听器仅用于测试目的。运行应用程序将打印23redirectfallback3redirectfallback
现在为什么它能工作
当spring看到这样一个@Lazy
注释参数时,它会从参数类创建一个运行时生成的代理(使用CGLIB)
这个代理的作用方式是包装bean,并且只有在第一次“需要”时才会完全创建这个bean(请阅读,在本例中我们将调用这个bean的方法)
如果使用@组件
,则与以下声明相同:
@Component
public class FallbackProcessor {
private final AdProcessor adProcessor;
public FallbackProcessor(@Lazy AdProcessor adProcessor) {
this.adProcessor = adProcessor;
}
public String run(int depth) {
...
}
}
另一方面,在上一个示例中,我没有将@Autowired
放在FallbackProcessor
类的构造函数上,只是因为如果只有一个构造函数,spring将“识别”并使用它注入所有依赖项
SO的和线程也可能是相关的(值得一读)。我遇到了相同的问题,
@Autowire
注释由于某种原因无法工作,我不知道
因此,我使用了另一种解决方法:
- 注入
,而不是bean本身ApplicationContext
- 从
ApplicationContext
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)
}
......
}
我试过这种方法。我得到了NPE,因为CGLIB代理在调用过程中没有被替换,所以它有没有可能在我的spring版本中修复了一个bug?也许你可以像我一样尝试spring的上一个版本?还是和科特林有关?(我已经测试了这个解决方案,它在我的机器上运行得很好)我尝试了不同的spring版本,结果是一样的。所以,我想这可能是由Kotlin引起的。所以,解决方案是将AdProcessor中的run方法标记为open
@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);
}
}
@Component
public class FallbackProcessor {
private final AdProcessor adProcessor;
public FallbackProcessor(@Lazy AdProcessor adProcessor) {
this.adProcessor = adProcessor;
}
public String run(int depth) {
...
}
}
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)
}
......
}