单例和应用程序弹簧范围有什么区别?
我知道单例范围为每个应用程序创建一个实例,并且应用程序范围以相同的方式工作,那么主要区别是什么?
我需要一个例子来告诉我区别。
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。我还想指出,我认为我将向您展示的自定义配置没有实际用途,除了提供这两个范围之间差异的具体示例。
下图显示了示例中所有元素之间的关系:
让我们看一下代码。请注意包名!
在包中,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
这有点类似于 Spring 单例 bean,但在两个重要方面有所不同:它是每个 ServletContext 的单例,而不是每个 Spring 'ApplicationContext'(在任何给定的 Web 应用程序中可能有多个),并且它实际上是公开的,因此作为 ServletContext 属性可见。
即Web应用程序可能有多个Spring应用程序上下文,因此有多个具有单例范围的bean实例(每个Spring应用程序上下文一个实例),但只有一个应用程序范围定义的bean。
| 归档时间: |
|
| 查看次数: |
2782 次 |
| 最近记录: |