Home > Net >  Can spring handle indirect dependency injection?
Can spring handle indirect dependency injection?

Time:09-06

I am currently trying to understand the way in which spring creates and destroys beans and how it comes up with the right order to do so. Lets assume we have three classes

@Component
class Demo1 {

}
@Component
class Demo2{

   Demo1 demo1;
   
   // specifically not using @Autowired
   public Demo2(Demo1 demo1){
      this.demo1 = demo1;
   }

   public Demo1 getDemo1(){
     return this.demo1
   }
}
@Component
class Demo3 {
   
   Demo1 demo1
   Demo2 demo2;

   public Demo3(Demo1 demo1, Demo2 demo2){
     this.demo1 = demo1;
     this.demo2 = demo2;
   }
}

Config class

@Configuration
class MyConfig {

  @Bean
  public Demo1 demo1(){
    return new demo1()
  }

  @Bean
  public Demo2 demo2(){
    return new Demo2(demo1());
  }

  @Bean
  public Demo3 demo3(){
   Demo2 demo2 = demo2()
   return new Demo3(demo2.getDemo1(), demo2);
  }
}

I understand that this is not the best/right way to do it but I want to know if its equivalent to using @Autowired annotation and if spring is able to resolve the dependency among the beans while creation, that is create in order

  1. demo1
  2. demo2
  3. demo3

and destroy in order

  1. demo3
  2. demo2
  3. demo1

Does changing the order of the functions in MyConfig make any difference ?

Currently I am facing an error where I believe demo1 is getting destroyed before demo2 or demo3

CodePudding user response:

It doesn't matter if you express configuration in XML, properties (yes that is possible, see https://deinum.biz/2018-04-12-on-spring-applicationcontext-and-bean-creation/), java config or annotations. All of those are bean definitions and the relation between those. Spring will have (some kind) of dependency tree.

Beans are constructed in a certain order and destroyed in the reverse order.

The only "wrong" thing in your code is the demo2.getDemo1() but in this case shouldn't make any difference as Demo3 depends on Demo2 which depends on Demo1`. Ideally you would write the configuration in the following way

Configuration
class MyConfig {

  @Bean
  public Demo1 demo1(){
    return new demo1()
  }

  @Bean
  public Demo2 demo2(Demo1 demo1){
    return new Demo2(demo1);
  }

  @Bean
  public Demo3 demo3(Demo2 demo2, Demo1 demo1){
   return new Demo3(demo1, demo2);
  }
}

This code/config makes it easier for Spring to figure out the interdependencies.

In your case, if you are using Spring Boot and have declared those @Bean methods you will actually end up with multiple instances of the beans.

Running your sample produces, for me the following output (I added @PostConstruct and @PreDestroy methods to the classes).

2022-09-06 09:03:48.366  INFO 64364 --- [           main] b.d.d.DestructionOrderApplication        : No active profile set, falling back to 1 default profile: "default"
biz.deinum.destructionorder.DestructionOrderApplication$Demo1@2fb5fe30 - @PostConstruct
biz.deinum.destructionorder.DestructionOrderApplication$Demo1@389562d6 - @PostConstruct
biz.deinum.destructionorder.DestructionOrderApplication$Demo2@5a101b1c - @PostConstruct
biz.deinum.destructionorder.DestructionOrderApplication$Demo2@2160e52a - @PostConstruct
biz.deinum.destructionorder.DestructionOrderApplication$Demo3@29f0802c - @PostConstruct
biz.deinum.destructionorder.DestructionOrderApplication$Demo3@3a60c416 - @PostConstruct
2022-09-06 09:03:48.559  INFO 64364 --- [           main] b.d.d.DestructionOrderApplication        : Started DestructionOrderApplication in 0.311 seconds (JVM running for 0.552)
biz.deinum.destructionorder.DestructionOrderApplication$Demo3@3a60c416 - @PreDestroy
biz.deinum.destructionorder.DestructionOrderApplication$Demo3@29f0802c - @PreDestroy
biz.deinum.destructionorder.DestructionOrderApplication$Demo2@2160e52a - @PreDestroy
biz.deinum.destructionorder.DestructionOrderApplication$Demo2@5a101b1c - @PreDestroy
biz.deinum.destructionorder.DestructionOrderApplication$Demo1@389562d6 - @PreDestroy
biz.deinum.destructionorder.DestructionOrderApplication$Demo1@2fb5fe30 - @PreDestroy

In which you can clearly see the @PostConstruct is called in the right order and the @PreDestroy in the reverse order. You can also see you have 2 instances. Removing the @Component leads to the following output:

2022-09-06 09:06:03.520  INFO 64388 --- [           main] b.d.d.DestructionOrderApplication        : No active profile set, falling back to 1 default profile: "default"
biz.deinum.destructionorder.DestructionOrderApplication$Demo1@72ab05ed - @PostConstruct
biz.deinum.destructionorder.DestructionOrderApplication$Demo2@27e32fe4 - @PostConstruct
biz.deinum.destructionorder.DestructionOrderApplication$Demo3@c3c4c1c - @PostConstruct
2022-09-06 09:06:03.714  INFO 64388 --- [           main] b.d.d.DestructionOrderApplication        : Started DestructionOrderApplication in 0.32 seconds (JVM running for 0.561)
biz.deinum.destructionorder.DestructionOrderApplication$Demo3@c3c4c1c - @PreDestroy
biz.deinum.destructionorder.DestructionOrderApplication$Demo2@27e32fe4 - @PreDestroy
biz.deinum.destructionorder.DestructionOrderApplication$Demo1@72ab05ed - @PreDestroy

  • Related