问题
I have a problem that I have a ClassA needs RoomService
to be injected, and it works fine that I find in ClassA, the roomService's id is the same.
While for some reason, I need roomservice to create room instance based on some input param for me, so I use below config to achieve this:
@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);
}
}
The problem is that I need RoomService
to be singleton, but I find that in the Application.java , the ctx.getBean(roomService) always returns a different bean which has different id. Isn't Spring should reuse the same bean? Why is that?
Here is how I create a room in RoomService.java
public AbstractRoom createRoom(String userID,int playerCount,Mode roomMode){
ApplicationContext ctx =Application.getApplicationContext();
AbstractRoom room = (AbstractRoom)ctx.getBean(AbstractRoom.class,roomMode);
}
Update:
I tried reusing the same ctx and it does not work. One hint is that I find my constructor of RoomService()
is called several times(I put a break point in it.) when I run tomcat to start it
Here is my 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>
Please help!
回答1:
Each time you retrieve your RoomService
you are creating a new ApplicationContext
instance. But singleton beans are only guaranteed to be singleton within a single instance of ApplicationContext
.
So if you want the bean to be singleton you must use the same ApplicationContext
instance each time you retrieve it.
From Spring documentation:
singleton: (Default) Scopes a single bean definition to a single object instance per Spring IoC container.
Update 1
You can just call roomService()
in your room()
method to get the room service without creating application context and Spring will ensure that they are the same instance since it is marked as @Bean
which has implicit singleton scope.
Update 2
Based on the updated question here are couple of issues with your code in general:
1. Do not create ApplicationContext
in your configuration class. When you start your Spring application in Tomcat, application context is created for you by Spring. You just need to tell Spring which configuration classes it should register.
2. Remove the room()
bean definition from your configuration class. Method for creating a room should be in RoomService
. So for example if you needed to create a new room in Spring MVC controller you would inject the RoomService
and call createRoom
method on it. The injected service would be singleton. Example:
@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";
}
}
Try to rework your code based on these suggestions and it should work.
来源:https://stackoverflow.com/questions/26698962/annotationconfigapplicationcontext-getbean-returns-a-different-bean-spring