【问题标题】:AnnotationConfigApplicationContext.getBean returns a different bean, SpringAnnotationConfigApplicationContext.getBean 返回一个不同的bean,Spring
【发布时间】:2014-12-29 04:58:34
【问题描述】:

我有一个问题,我有一个 ClassA 需要注入 RoomService,我在 ClassA 中发现它工作正常,roomService 的 id 是相同的。

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

@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 时,它​​可能会有所不同,因为每次调用 room() 时都会创建并关闭应用程序上下文。我认为 RoomService 保证在单个应用程序上下文实例中是单例的。
  • @BohuslavBurghardt,我试过不调用 ctx.close(),一样。我想我得到了不同的上下文,因为我使用 new 来获取上下文。

标签: java spring inversion-of-control ioc-container spring-ioc


【解决方案1】:

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

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

来自 Spring 文档:

singleton:(默认)将单个 bean 定义限定为 single 每个 Spring IoC 容器的对象实例

更新 1

您可以在您的room() 方法中调用roomService() 来获取客房服务,而无需创建应用程序上下文,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";
    }
}

尝试根据这些建议修改您的代码,它应该可以工作。

【讨论】:

  • @我们是否有一个只有一个 ctx 实例的工厂方法?我会尝试你的方法并在几分钟内回复。
  • 我尝试了你的两个建议,1. 使用相同的 ctx,2. 使用 roomService() 代替 ctx,但都不能解决问题!..它对你有用吗?
  • 而且我发现我的 RoomService 构造函数在我运行 Tomcat 时被多次调用,这是一个线索吗?
  • 它适用于我为测试它而创建的简单项目。但我不在Tomcat中运行它。顺便说一句,我刚刚看了你更新的问题。如果您在 Tomcat 中运行,请不要在配置类中定义静态应用程序上下文。应用程序上下文将自动创建。您如何引导您的 Spring 应用程序并注册您的配置类? web.xml 或使用 Java 配置(Web 应用程序初始化程序)?如果可能,请分享该代码。这可能会有所帮助。
  • 我使用 web.xml,请查看我更新的问题!非常感谢您的帮助!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-11
  • 1970-01-01
相关资源
最近更新 更多