Я не могу сказать о Kotlin (мои знания о kotlin довольно ограничены на данный момент), но о Java с последней доступной весенней версией (5.2.6.RELEASE)
У меня он работает со следующим переводом вашего примера с "kotlin на 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
аннотированный параметр - он создает сгенерированный во время выполнения прокси (с 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
в последнем примере, только потому, что, если есть единственный конструктор, spring "распознает это" и использует его для внедрения всех зависимостей.
в следующем руководстве и это несколько старое поток SO также может иметь значение (стоит прочитать).