Home > OS >  Spring @Autowire property for class that needs to be instantiated
Spring @Autowire property for class that needs to be instantiated

Time:04-07

public class Player {
   @Autowired gameService

   @Getter @Setter String name;

   public Player(String name) {
      this.name = name
   }

   public doSomething() {
      gameService.something() // gameService is null!
   }

}
@Service 
class GameService { public void something() {...} }

If I were to do new Player("John").doSomething() java complains that this.gameService is null. Player class is needed to be instantiated.

Is it possible to make gameService autowire to the service correctly?

CodePudding user response:

If I were to do new Player("John").doSomething()

When you create the java instance by your self, this instance is unknown to Spring framework. So Spring will not enrich it with any dependencies it contains.

For your class to contain dependencies via @Autowired you have to let spring create this instance. Spring in actuality will create a proxy to the class you provide and not the actual class that you have written. One way to achieve that is to mark your class Player with @Component and then you must also retrieve the instance player from Spring framework to correctly contain it's dependencies.

Keep in mind that with default @Comopnent the Player will become a singleton for spring, which doesn't exactly match to the logical use I see you want to have for this class. Either you want it to be a prototype or even better I think you have to move the use of gameService outside of Player class.

Probably you could have the method something() in GameService taking as parameter a Player and doing the same thing. Then you can autowire everywhere the gameService which sounds like it should be a singleton.

CodePudding user response:

You can make Player a component which makes autowiring available:

@Component
public class Player {
   @Autowired 
   GameService gameService

Additionally, dependency injection best practices are to use constructor based injection:

@Component
public class Player {
   private final GameService gameService;
   
   @Autowired
   public Player(GameService gameService){
      this.gameService = gameService;
   }

CodePudding user response:

Since you want gameService to be @Autowired, I believe you want some processing to be done based on Player object on that gameService. If yes, instead of calling gameService.something(), call gameService.something(player).

Here is a possible solution:

@Component
public class Player {
    @Autowired GameService gameService;

    @Getter
    @Setter
    String name;

    public Player() {
    }

    public Player(String name) {
        this.name = name;
    }

    public void doSomething(Player player) {
        gameService.something(player);
    }
}

In caller side however, it should be something like:

@Autowired
Player player;
...

public void callPlayer() {
   Player johnPlayer = new Player("John");
   player.doSomething(johnPlayer);
}

The reason for doing this is let spring create Player component and have dependency injection and you leverage spring created component.

Hope this will help.

  • Related