2

I have a problem and this is the gist of it: (there are more classes involved in the loop but it can be represented this way)

@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;
    }
}

so obviously I get a null pointer since BeanB b is not yet resolved. I also used afterPropertiesSet and it is the same. My question is that if there is a way to run the init() method after the whole context is initialized so that I don't get this null pointer? I am aware of the fact that having this circular dependency is trouble and needs to be solved but I'm just refactoring a huge project to use Spring DI and changing the design, logic and business requires a long process of asking it to be done by other teams.

MohammadZoghi
  • 578
  • 1
  • 7
  • 17
  • I don't think that your example is quite good. I mean there is cyclic dependency here, in which `ServiceDispatcher` needs `BeanA` as a dependency and in return `BeanA` needs `ServiceDispather` as a dependency. I think you should reconsider your approach. – akortex Jul 15 '18 at 12:50
  • @Aris as I explained in the question changing the design and logic is very time consuming in my work environment since the project is too big and this should be done by other teams. So I need a way to work around this and avoid changing the circular dependency. – MohammadZoghi Jul 15 '18 at 13:09
  • I don't know if this would help, but try injecting using a constructor instead of field injection and use the `@Lazy` annotation. You can read up here for more: http://www.baeldung.com/circular-dependencies-in-spring – akortex Jul 15 '18 at 13:14

3 Answers3

3

You will have to subscribe to ContextRefreshedEvent event in order to execute your code once spring context is full initialized.

@Component
class N51348516 implements ApplicationListener<ContextRefreshedEvent> {

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

But I guess what you really need is to make your bean lazy with @Lazy annotation so you will be able to access them correctly.

Bohdan Levchenko
  • 3,411
  • 2
  • 24
  • 28
0

I don't understand why you need to use the serviceDispatcher in the first place. You could try to directly inject BeanB into BeanA:

@Service
public class BeanA{
   private BeanB beanB;

   @Autowired
   public BeanA(BeanB b){
      beanB = b;
      beanB.someMethod();
   }
}
Merve Sahin
  • 1,008
  • 2
  • 14
  • 26
  • I explained in the question that I cannot change the design. BeanA and BeanB cannot be dependent to one another because they are in different business subsystem. – MohammadZoghi Jul 15 '18 at 13:38
0

For the class BeanA, add the annotation @DependsOn("beanB")

Amit
  • 496
  • 7
  • 11