Spring Singleton 作用域与应用程序作用域

S. *_*jim 6 spring spring-mvc

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

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

我需要一个例子来告诉我区别。

xon*_*nya 11

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

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

AnApplicationContext代表一个 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。我还想指出,我认为我将向您展示的自定义配置没有实际用途,除了提供这两个范围之间差异的具体示例。

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

多个单例作用域 bean 的示例

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

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

@ApplicationScope
@Component
public class MyApplicationScopeBean {

    private final double id = Math.random();

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

    private final double id = Math.random();

    public double getId() {
        return id;
    }
}
Run Code Online (Sandbox Code Playgroud)

启动类放在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;
    }
}
Run Code Online (Sandbox Code Playgroud)

在同一个包中,我们还放置了将绑定到 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

控制器绑定到第二个 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

http://localhost:8080/first/demo
Run Code Online (Sandbox Code Playgroud)

应用范围=0.8685117272969953,单例=0.23475401462261436

http://localhost:8080/second/demo
Run Code Online (Sandbox Code Playgroud)

应用范围=0.8685117272969953,单例=0.8390865330171554


Evg*_*eny 4

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应用程序上下文,因此有多个具有单例范围的bean实例(每个Spring应用程序上下文一个实例),但只有一个应用程序范围定义的bean。