【问题标题】:Spring Injected bean null when creating an object with new ,how to solve it?使用new创建对象时Spring注入bean null,如何解决?
【发布时间】:2014-11-02 10:14:59
【问题描述】:

我有一个应用程序,现在正在尝试使用Spring对其进行重构,使用new创建对象时遇到问题,但我不知道如何解决。

这里是关系:

我有一个Controller,需要一个CommandService 实例,而CommandService 需要一个RoomService 来创建AbstractRoom 实例以放入RoomService 实例的hashmap。

我有两种AbstractRoom,分别称为RoomA、RoomB,它们是从AbstractRoom扩展而来的,而AbstractRoom需要GameService实例。

我会将一个参数从 commandService 传递给 roomService,以便 roomservice 可以创建正确的房间实例。

现在的问题是,我使用 roomservice.createRoom 创建了一个使用new 的房间。所以 Spring 不能将 GameService 注入到我的 Abstract Room 中,因此我有一个 null gameService。

但是 CommandService 会从用户那里获得一些输入并委托给RoomService 为其创建一个房间,所以在用户输入之前我不知道会创建哪个房间实例:

CommandService.java:

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

这是我从 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;
}

这是我的 AbstractRoom.java

public abstract class AbstractRoom {

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

而我的配置是:

@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
    }

【问题讨论】:

  • 我不会让 Room 依赖于服务。那看起来不对。如果你真的需要,那么在房间构造函数中显式传递服务,或者将 Room 设置为原型 bean 并使用 Spring 应用程序上下文来获取实例。
  • "将 Room 设为原型 bean,并使用 Spring 应用程序上下文获取实例。"我想这就是我现在想要的,但我是 Spring 的新手,你能告诉我如何在答案中做到这一点吗?谢谢!
  • @JBNizet,谢谢!现在我使用 new AnnotationConfigApplicationContext(Application.class).getBean(RoomService.class),在声明 AbstratRoom 的 bean 时,但是我还有一个问题,我的服务现在不是单例了! stackoverflow.com/questions/26698962/…
  • 您只创建一次应用程序上下文。在你需要的地方自动装配,就像我链接到的答案一样。

标签: java spring dependency-injection refactoring inversion-of-control


【解决方案1】:

最终,我解决了这个问题,让 AbstractRoom 作为一个范围 = 原型的 bean,并从 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);
    }

然后在 RoomService.java 中注入一个ApplicationContext,然后从容器中获取 Room。

public class RoomService {

    @Autowired
    private ApplicationContext ctx;

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-07-17
    • 2014-12-15
    • 2011-01-06
    • 1970-01-01
    • 2013-02-12
    相关资源
    最近更新 更多