我有一个问题,我有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";
}
}
尝试根据这些建议重新编写代码,它应该可以工作。