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
}
解决方案
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);
}
}