AnnotationConfigApplicationContext.getBean()方法返回一个不同的bean,Spring

7 浏览
0 Comments

AnnotationConfigApplicationContext.getBean()方法返回一个不同的bean,Spring

我有一个问题,我有一个ClassA需要注入RoomService,我发现在ClassA中,roomService的id是相同的,这是正常的。但是由于某些原因,我需要roomservice根据一些输入参数为我创建room实例,所以我使用以下配置来实现:

@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();//单例
    }
    @Bean
    @Scope("prototype")
    public AbstractRoom room(AbstractRoom.Mode roomMode){
        RoomService roomService = (RoomService) ctx.getBean(RoomService.class);
        LogUtil.debug("--------from application:" +roomService.id1);//在这里,我发现每次id都不同
        return roomService.newRoom(roomMode);
    }
}

问题是我需要RoomService是单例的,但是我发现在Application.java中,ctx.getBean(roomService)总是返回一个不同的bean,其id也不同。难道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文件:

 

    wodinow
    
        contextConfigLocation
        /WEB-INF/dispatcher-servlet.xml
    
    
        
            org.springframework.web.context.ContextLoaderListener
        
    
    
        dispatcher
        org.springframework.web.servlet.DispatcherServlet
        1
    
    
        dispatcher
        /
    

请帮忙!

0
0 Comments

问题出现的原因:每次调用AnnotationConfigApplicationContext.getBean()方法时都创建了一个新的ApplicationContext实例,但是单例bean只在单个ApplicationContext实例中保证是单例的。

解决方法:如果想要bean是单例的,必须每次都使用相同的ApplicationContext实例来获取它。

文章内容如下:

每次调用AnnotationConfigApplicationContext.getBean()方法时都创建了一个新的ApplicationContext实例,但是单例bean只在单个ApplicationContext实例中保证是单例的。所以如果想要bean是单例的,必须每次都使用相同的ApplicationContext实例来获取它。

根据Spring文档的描述,单例bean的定义如下:

singleton: (Default) 将一个bean定义范围限制为Spring IoC容器中的单个对象实例。

更新1:

可以在room()方法中直接调用roomService()方法来获取room service,而不需要创建ApplicationContext,因为roomService()方法已经被标记为单例作用域。

更新2:

根据更新后的问题,代码中存在一些问题:

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

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

尝试根据这些建议重新编写代码,应该可以解决问题。

在我创建的简单项目中测试了这个方法,它是可行的。但是我没有在Tomcat中运行它。另外,我刚刚查看了您更新的问题。如果您在Tomcat中运行,请不要在配置类中像那样定义静态应用程序上下文。应用程序上下文将自动创建。您如何启动Spring应用程序并注册配置类?是使用web.xml还是使用Java配置(Web应用程序初始化程序)?如果可能,请共享该代码。这可能会有所帮助。

我通过根据第二个答案在roomService中自动注入一个applicationcontext来解决了这个问题,具体方法请参考这个链接:stackoverflow.com/questions/129207/…。请您更新您的答案,并解释为什么我必须注入applicationcontext,而使用Application.java的getInstance方法却不起作用?之后我会接受您的答案。非常感谢!

在更新之前,我最后一个问题。您在room service中注入了applicationcontext吗?

是的,我在roomService中注入了一个applicationcontext,现在它可以正常工作了。但是对于我的当前关系,我需要room的new,因为我需要Spring为我创建room bean,因为room需要注入其他东西,请参考这个问题:stackoverflow.com/questions/26698207/…。所以,请您解释一下什么时候应该使用new ApplicationContext,什么时候不应该使用?因为一开始您似乎同意使用new是可以的。非常感谢!

起初我以为您是在一个独立的应用程序中使用它,因此创建新的上下文应该是可以的。但是在您更新之后,我发现您是在Tomcat中运行应用程序,并且Spring上下文是由Spring自动创建的,所以在这种情况下,不应该像您的示例中那样手动创建上下文。可能之前没有按照您的预期工作是因为您有多个上下文。现在,当您在RoomService中自动注入应用程序上下文时,它引用了与RoomService bean本身所在的相同上下文,因此您的bean可以正确地作为单例使用。

如果这不是Spring控制的bean,但是我需要访问ApplicationContext,我该怎么办?

0