我有一个问题,我有ClassA需要注入RoomService,并且在ClassA中找到它,它的正常工作是,roomService的ID是相同的。

出于某种原因,我需要roomservice为我根据一些输入参数创建房间实例,因此我使用下面的config来实现这一点:

@Configuration
@EnableAspectJAutoProxy
public class Application {

private static ApplicationContext ctx = new AnnotationConfigApplicationContext(Application.class);

    public static ApplicationContext getApplicationContext(){
    return ctx;
}

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

    @Bean
    @Scope("prototype")
    public AbstractRoom room(AbstractRoom.Mode roomMode){
        RoomService roomService = (RoomService) ctx.getBean(RoomService.class);
        LogUtil.debug("--------from application:" +roomService.id1);//here, I find the id is different every time
        return roomService.newRoom(roomMode);
    }
}


问题是我需要RoomService成为单例,但是我发现在Application.java中,ctx.getBean(roomService)始终返回具有不同id的另一个bean。 Spring不应该重用同一个bean吗?这是为什么?

这是我在RoomService.java中创建房间的方法

public AbstractRoom createRoom(String userID,int playerCount,Mode roomMode){

    ApplicationContext ctx =Application.getApplicationContext();
    AbstractRoom room = (AbstractRoom)ctx.getBean(AbstractRoom.class,roomMode);

}


更新:
我尝试重用相同的ctx,但它不起作用。一个提示是,当我运行tomcat启动它时,我发现RoomService()的构造函数被调用了几次(我在其中插入了一个断点。)

这是我的web.xml

 <!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>wodinow</display-name>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/dispatcher-servlet.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

</web-app>


请帮忙!

最佳答案

每次检索RoomService时,您都在创建一个新的ApplicationContext实例。但是,单例bean仅保证在ApplicationContext的单个实例中是单例。

因此,如果希望bean是单例的,则每次检索它都必须使用相同的ApplicationContext实例。

从Spring文档中:


  singleton :(默认)将单个Bean定义范围限定为单个
  每个Spring IoC容器的对象实例。


更新1

您只需在roomService()方法中调用room()即可获得客房服务,而无需创建应用程序上下文,Spring将确保它们是同一实例,因为它被标记为具有隐式单例作用域的@Bean

更新2

根据更新后的问题,以下是您的代码通常存在的几个问题:

1.不要在配置类中创建ApplicationContext。当您在Tomcat中启动Spring应用程序时,Spring将为您创建应用程序上下文。您只需要告诉Spring它应该注册哪些配置类即可。

2.从配置类中删除room() bean定义。创建房间的方法应在RoomService中。因此,例如,如果您需要在Spring MVC控制器中创建一个新房间,则可以注入RoomService并在其上调用createRoom方法。注入的服务将是单例。例:

@Controller
@RequestMapping("/rooms")
public class RoomController {

    @Autowired
    private RoomService roomService;

    @RequestMapping(value="/create", method=POST)
    public String createRoom() {
        roomService.createRoom(/* Parameters for room creation */);
        return "redirect:/somelocation";
    }
}


尝试根据这些建议重新编写代码,它应该可以工作。

07-27 18:44