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