Spring Singleton范围与应用范围

时间:2018-04-13 14:46:21

标签: spring spring-mvc

单例和应用弹簧范围有什么区别?

我知道单例范围为每个应用程序创建一个实例,并且应用程序范围以相同的方式工作,那么主要区别是什么?

我需要一个例子来向我展示差异。

3 个答案:

答案 0 :(得分:2)

要了解应用程序范围和单例范围之间的区别,您需要了解ServletContext和ApplicationContext是什么。

ServletContext在生活在同一个servlet容器(例如Tomcat)上的所有servlet之间共享。这是一个Java EE类(它属于包javax.servlet)。用@ApplicationScope注释的Bean绑定到ServletContext。

ApplicationContext代表Spring IoC容器,因此它是特定于Spring的类(它属于包org.springframework.context)。单例范围的Bean绑定到ApplicationContext。

同一servlet容器中可以有多个IoC容器,因此可以有多个相同类型的单例bean,但每种类型只有一个应用程序作用域的bean。

我提供了一个使用Spring Boot和Spring MVC的示例。

我们还需要介绍DispatcherServlet。 DispatcherServlet接收HTTP请求,并将其转发到适当的控制器。 ApplicationContext与每个DispatcherServlet相关联。可以将Spring配置为创建多个DispatcherServlet,并将不同的ApplicationContext与其关联。

请注意,在标准配置中,只有一个DispatcherServlet,因此通常无法将单例范围的bean与应用程序范围的bean区分开。我还要指出的是,除了提供这两个作用域之间差异的具体示例之外,我看不到将要展示给您的自定义配置的实际用途。

下图显示了示例中所有元素之间的关系:

this

让我们看一下代码。请注意包装名称!

在包com.example.demo.beans中,我们创建了2个bean。在bean初始化期间会生成一个随机数,以便我们区分它们。

@ApplicationScope
@Component
public class MyApplicationScopeBean {

    private final double id = Math.random();

    public double getId() {
        return id;
    }
}
// Singleton is the default scope
@Component
public class MySingletonBean {

    private final double id = Math.random();

    public double getId() {
        return id;
    }
}

启动类放在com.example.demo中:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        // The first ApplicationContext is instantiated here
        // (it is also returned by the method).
        SpringApplication.run(DemoApplication.class, args);
    }

    /**
     * A new DispatcherServlet is instantiated and registered.
     */
    @Bean
    public ServletRegistrationBean mvc2() {

        // A new ApplicationContext is created, using a dedicated Configuration class.
        AnnotationConfigWebApplicationContext secondApplicationContext = new AnnotationConfigWebApplicationContext();
        secondApplicationContext.register(Mvc2Config.class);

        DispatcherServlet dispatcherServlet = new DispatcherServlet();
        dispatcherServlet.setApplicationContext(secondApplicationContext);

        DispatcherServletRegistrationBean servletRegistrationBean = new DispatcherServletRegistrationBean(dispatcherServlet, "/second/*");
        servletRegistrationBean.setName("second");

        return servletRegistrationBean;
    }
}

在同一包中,我们还放置了将绑定到Spring Boot生成的默认DispatcherServlet的控制器:

@RestController
public class FirstController {

    @Autowired
    private MyApplicationScopeBean applicationScopeBean;

    @Autowired
    private MySingletonBean singletonBean;

    @GetMapping("/first/demo")
    public String output() {
        return "applicationScope=" + applicationScopeBean.getId() + ", singleton=" + singletonBean.getId();
    }
}

在软件包com.example.demo.mvc2中,我们放置了第二个配置类:

@Configuration
@ComponentScan(basePackages = {"com.example.demo.mvc2", "com.example.demo.beans"})
@EnableWebMvc
public class Mvc2Config {
}

然后控制器绑定到第二个DispatcherServlet:

@RestController
public class SecondController {

    @Autowired
    private MyApplicationScopeBean applicationScopeBean;

    @Autowired
    private MySingletonBean singletonBean;

    @GetMapping("/demo")
    public String output() {
        return "applicationScope=" + applicationScopeBean.getId() + ", singleton=" + singletonBean.getId();
    }
}

如果运行代码,则可以看到在两个控制器中应用程序作用域的bean的ID相同,而单例bean的ID发生了变化:

http://localhost:8080/first/demo

applicationScope = 0.8685117272969953,单例= 0.23475401462261436

http://localhost:8080/second/demo

applicationScope = 0.8685117272969953,单例= 0.8390865330171554

答案 1 :(得分:1)

Singleton范围是Spring中的范围。 ApplicationScope也是单例,但它带来了Java Enterprise,例如在Java Server Faces(JSF)中使用

答案 2 :(得分:1)

https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-factory-scopes-application

  

这有点类似于Spring单例bean,但在两个重要方面有所不同:它是每个ServletContext的单例,而不是每个Spring的'ApplicationContext'(在任何给定的Web应用程序中可能有几个),它实际上是公开,因此可以看作是ServletContext属性。

即。 Web应用程序可能有几个Spring应用程序上下文,因此有几个带有singleton范围的bean实例(每个Spring应用程序上下文有一个实例),但只有一个bean用应用程序范围定义。