Есть ли способ вызвать метод в bean-компоненте после инициализации всего контекста Spring

У меня есть проблема, и вот в чем ее суть: (в цикле задействовано больше классов, но это можно представить так)

@service
public class serviceDispatcher{
    @Autowired
    private BeanA a;

    @Autowired
    private BeanB b;

    public BeanA getBeanA(){
        return a;
    }

    public BeanB getBeanB(){
        return b;
    }
}

@Service
public class BeanA{
    @Autowired
    ServiceDispatcher sd;

    @PostConstruct
    private void init(){
        sd.getBeanB().method;
    }
}

поэтому, очевидно, я получаю нулевой указатель, поскольку BeanB b еще не разрешен. Я также использовал afterPropertiesSet, и это то же самое. Мой вопрос заключается в том, есть ли способ запустить метод init() после инициализации всего контекста, чтобы я не получил этот нулевой указатель? Я осознаю тот факт, что эта циклическая зависимость является проблемой и должна быть решена, но я просто рефакторинг огромного проекта для использования Spring DI, и изменение дизайна, логики и бизнеса требует длительного процесса запроса, чтобы это было сделано другие команды.


person MohammadZoghi    schedule 15.07.2018    source источник
comment
Я не думаю, что ваш пример достаточно хорош. Я имею в виду, что здесь есть циклическая зависимость, в которой ServiceDispatcher требуется BeanA в качестве зависимости, а взамен BeanA требуется ServiceDispather в качестве зависимости. Думаю, вам стоит пересмотреть свой подход.   -  person akortex91    schedule 15.07.2018
comment
@Aris, как я объяснил в вопросе, изменение дизайна и логики занимает очень много времени в моей рабочей среде, поскольку проект слишком большой, и этим должны заниматься другие команды. Поэтому мне нужен способ обойти это и избежать изменения циклической зависимости.   -  person MohammadZoghi    schedule 15.07.2018
comment
Я не знаю, поможет ли это, но попробуйте внедрить с помощью конструктора вместо внедрения поля и используйте аннотацию @Lazy. Вы можете прочитать здесь для получения дополнительной информации: baeldung.com/circular-dependencies-in-spring< /а>   -  person akortex91    schedule 15.07.2018


Ответы (3)


Вам нужно будет подписаться на ContextRefreshedEvent для выполнения вашего кода после полной инициализации контекста Spring.

@Component
class N51348516 implements ApplicationListener<ContextRefreshedEvent> {

    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        System.out.println(event.getApplicationContext());
    }
}

Но я предполагаю, что вам действительно нужно сделать ваш bean ленивым с помощью @Lazy, чтобы вы могли получить к ним правильный доступ.

person Bohdan Levchenko    schedule 15.07.2018
comment
Это делает именно то, что мне нужно. спасибо Богдан Левченко - person MohammadZoghi; 17.07.2018

Я не понимаю, почему вам нужно использовать serviceDispatcher в первую очередь. Вы можете попробовать напрямую ввести BeanB в BeanA:

@Service
public class BeanA{
   private BeanB beanB;

   @Autowired
   public BeanA(BeanB b){
      beanB = b;
      beanB.someMethod();
   }
}
person Merve Sahin    schedule 15.07.2018
comment
Я объяснил в вопросе, что я не могу изменить дизайн. BeanA и BeanB не могут быть зависимы друг от друга, потому что они находятся в разных бизнес-подсистемах. - person MohammadZoghi; 15.07.2018

Для класса BeanA добавьте аннотацию @DependsOn("beanB")

person Amit    schedule 15.07.2018