AnnotationConfigApplicationContext.getBean returns a different bean, Spring

青春壹個敷衍的年華 提交于 2019-12-11 10:20:03

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!