简体   繁体   中英

Spring Autowire retrieves the wrong class

I have

public abstract class AbstractClass<T> {
  public abstract MyStatus getStatus();
  public void test() {
     System.out.println(getStatus().testField());
  }
}

for Dogs I have

@Component("dogs")
public class Dogs extends AbstractClass<Dogs>{
   @Autowired
   MyStatus statusField;

   @PostConstruct
   private void init() {
      statusField.setTest("dogs");
   }

   public getStatus() {
     return statusField;
   }
}

for cats I have

@Component("cats")
public class Cats extends AbstractClass<Cats>{
   @Autowired
   MyStatus statusField;

   @PostConstruct
   private void init() {
      statusField.setTest("cats");
   }

   public getStatus() {
     return statusField;
   }
}

and for the StatusContainer I have

@Component
@Data
public class MyStatus<T> {
   public String test; // and other options from the application.properties file
}

I would expect that if I @Autowired Dogs I get for the status field dogs and for the Cats I'll get cats .

public class ClassA {
   @Autowired
   @Qualifier("dogs")
   Dogs myDogEntity;
}

public class ClassB {
   @Autowired
   @Qualifier("cats")
   Cats myCatEntity;
}

Matter of fact is that if I print the information of MyStatus I get everytime cats (or everytime dogs ). I would have exptected that the container is initiated differently and injected with the appropriate instance. But thats not true.

Is there a simple way to have separete containers for different objects instead of injecting the same?

UPDATE Unfortunately I have had some typos in my orginal code. Fixed them - hopefully all.

I finally figured out that the major problem is/was that Spring creates only one instance of a component. In my case MyStatus . Consequently this one instance is injected into the other classes. Any manipulation on this one class will lead to the side effect that it manipulates the other.

My solution: Split the config into two parts - one which is Spring related and one the instance, eg Cats or Dogs will handle indiviudally - without Spring (injection)!!!

Your problem is that by default, the scope is Singleton on Spring and you end up having the same instance of MyStatus in both Dogs and Cats.

There is a simple way of achieving this, for the class MyStatus, you can set the scope to Prototype:

@Data
@Component
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class MyStatus<T> {
   public String test; 
}

This way, you don't need to change anything else. Because Spring will create a new instance for everybody that requests to inject it.

This way, the classes Cats and Dogs will have different instances of MyStatus.

You have to update your code and correct the Typing mistakes, I've posted below with correction.

public class ClassA {
   @Autowired
   @Qualifier("dogs")
   Dogs myDogEntity;
}

public class ClassB {
   @Autowired
   @Qualifier("cats")
   Cats myCatEntity;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM