Spring Injected bean null when creating an object

2019-09-04 10:27发布

问题:

I have an application , and now I am trying to use Spring to refactor it, and I have problem when creating object using new, but I don't know how to solve it.

Here is the realtionship:

I have a Controller, need a CommandService instance, and the CommandService need a RoomService to create AbstractRoom instances to put into RoomService instance's hashmap.

I have two kinds of AbstractRoom called RoomA, RoomB, and they extend from AbstractRoom, and AbstractRoom needs GameService instance.

I will pass a param from commandService to roomService so that the roomservice can create a right room instance.

The problem now, is that I use roomservice.createRoom to create a room which uses new to do that. So Spring can not inject GameService to my Abstract Room thus I have a null gameService.

But CommandService will get some input from user and to delegate to RoomService to create a room for it, so I don't know which Room Instance will be created until the user input something:

CommandService.java:

    private String handleCreateRoom(String userID, int playerCount,
        Mode roomMode) {
        ...
        AbstractRoom theNewRoom=roomService.createRoom(userID, playerCount, roomMode);
        ...        
        }

Here is how I createRoom from RoomService.java:

public AbstractRoom createRoom(String userID,int playerCount,Mode roomMode){
    AbstractRoom room = newRoom(roomMode);// create a room based on the roomMode
    room.initRoom(userID, playerCount);// init the room
    userToRoom.put(userID, room.getRoomNum());//some context 
    return room;
}


public AbstractRoom newRoom(AbstractRoom.Mode roomMode) {
    Integer randomNumObject;
    AbstractRoom newRoom;
    .....
    if(roomMode.equals(Mode.AUTO_JUDGE)||roomMode.equals(Mode.PLAYER_JUDGE)){//wodi room

           newRoom=new RoomA(randomNumObject,roomMode);//RoomA
    }
    ....
    else{//RoomB
        newRoom=new RoomB(randomNumObject);
    }

    roomMap.put(randomNumObject, newRoom);//some context 
    return newRoom;
}

Here is my AbstractRoom.java

public abstract class AbstractRoom {

        protected Mode roomMode;    
        @Autowired
        protected GameService gameService;
        .....
}

And my configuration is :

@Configuration
@EnableAspectJAutoProxy
public class Application {
    @Bean
    public CommandService commandService(){
        return new CommandService();//singleton
    }
    @Bean
    public RoomService roomService(){
        return new RoomService();//singleton
    }       
    @Bean
    public GameService gameService(){
        return new GameService();//singleton
    }

回答1:

Eventually, I solve this problem with letting AbstractRoom as a bean with scope = prototype, and return the instance from roomservice bean.

@Configuration
@EnableAspectJAutoProxy
public class Application {      
    @Bean
    public CommandService commandService(){
        return new CommandService();
    }

    @Bean
    public RoomService roomService(){
        return new RoomService();
    }

    @Bean
    public GameService gameService(){
        return new GameService();
    }

    @Bean
    @Scope("prototype")
    public AbstractRoom room(AbstractRoom.Mode roomMode){
        RoomService roomService = roomService();
        return roomService.newRoom(roomMode);
    }

And in RoomService.java , inject an ApplicationContext, and get Room from the container.

public class RoomService {

    @Autowired
    private ApplicationContext ctx;

    public AbstractRoom createRoom(String userID,int playerCount,Mode roomMode){
        AbstractRoom room = (AbstractRoom)ctx.getBean(AbstractRoom.class,roomMode);
    }
}