更新时间:2022-12-05 11:06:49 来源:极悦 浏览902次
在这个Spring教程中,我们将了解不同类型的bean Spring框架的范围。
bean的范围定义bean的生命周期和能见度的情况下我们使用它。
最新版本的Spring框架定义了6种范围:
单例
原型
请求
会话
应用程序
websocket
最后四范围所提到的,请求、会话,应用程序和websocket,只有在理解网络应用程序可用。
当我们使用单例范围定义bean,容器创建bean的一个实例;所有bean名称的请求将返回相同的对象,这是缓存。任何修改对象将反映在所有bean的引用。这个范围是默认值如果没有指定其他范围。
让我们创建一个实体来例证了范围的概念:
public class Person {
private String name;
// standard constructor, getters and setters
}
之后,我们定义的bean singleton范围通过使用@ scope注释:
@Bean
@Scope("singleton")
public Person personSingleton() {
return new Person();
}
我们也可以使用一个常数,而不是字符串值在以下方式:
@Scope(value = ConfigurableBeanFactory.SCOPE_SINGLETON)
现在我们可以继续编写一个测试表明,两个对象指的是相同的bean将有相同的价值观,即使只有一个人改变他们的国家,他们都是引用同一个bean实例:
private static final String NAME = "John Smith";
@Test
public void givenSingletonScope_whenSetName_thenEqualNames() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("scopes.xml");
Person personSingletonA = (Person) applicationContext.getBean("personSingleton");
Person personSingletonB = (Person) applicationContext.getBean("personSingleton");
personSingletonA.setName(NAME);
Assert.assertEquals(NAME, personSingletonB.getName());
((AbstractApplicationContext) applicationContext).close();
}
作用域。xml文件在这个例子中应该包含的xml定义bean使用:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="personSingleton" class="org.baeldung.scopes.Person" scope="singleton"/>
</beans>
原型的bean将返回一个不同的实例范围每次请求的容器。它通过设置值定义原型在bean定义:@ scope注释
@Bean
@Scope("prototype")
public Person personPrototype() {
return new Person();
}
我们还可以使用一个常数如单例的范围:
@Scope(value = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
现在我们将编写一个类似的测试,显示了两个对象请求与原型相同的bean名称范围。他们会有不同的国家不再是指相同的bean实例:
private static final String NAME = "John Smith";
private static final String NAME_OTHER = "Anna Jones";
@Test
public void givenPrototypeScope_whenSetNames_thenDifferentNames() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("scopes.xml");
Person personPrototypeA = (Person) applicationContext.getBean("personPrototype");
Person personPrototypeB = (Person) applicationContext.getBean("personPrototype");
personPrototypeA.setName(NAME);
personPrototypeB.setName(NAME_OTHER);
Assert.assertEquals(NAME, personPrototypeA.getName());
Assert.assertEquals(NAME_OTHER, personPrototypeB.getName());
((AbstractApplicationContext) applicationContext).close();
}
作用域。xml文件类似于前一节中给出的一个而添加xml定义的bean原型范围:
<bean id="personPrototype" class="org.baeldung.scopes.Person" scope="prototype"/>
正如前面提到的,有四个额外的范围,只有在理解网络应用程序上下文。我们在实践中很少使用这些。
请求范围为一个HTTP请求,创建一个bean实例在会话范围创建一个HTTP会话bean实例。
应用范围创建bean实例的生命周期ServletContext,和websocket创建为一个特定的websocket会话范围。
让我们创建一个类实例化bean的使用:
public class HelloMessageGenerator {
private String message;
// standard getter and setter
}
(1)请求范围
我们可以定义bean的请求范围使用@ scope注释:
@Bean
@Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator requestScopedBean() {
return new HelloMessageGenerator();
}
proxyMode属性是必要的,因为目前的web应用程序上下文的实例化,没有主动请求。Spring创建一个代理作为依赖项注入,并实例化目标bean需要时在一个请求。
我们也可以使用一个@RequestScope由注释,充当一个上述定义的快捷方式:
@Bean
@RequestScope
public HelloMessageGenerator requestScopedBean() {
return new HelloMessageGenerator();
}
接下来,我们可以定义一个控制器requestScopedBean注入引用。我们需要访问相同的请求两次来测试web具体范围。
如果我们显示消息每次请求运行时,我们可以看到,该值重置为零,即使后来改变的方法。这是因为不同的bean实例为每个请求返回。
@Controller
public class ScopesController {
@Resource(name = "requestScopedBean")
HelloMessageGenerator requestScopedBean;
@RequestMapping("/scopes/request")
public String getRequestScopeMessage(final Model model) {
model.addAttribute("previousMessage", requestScopedBean.getMessage());
requestScopedBean.setMessage("Good morning!");
model.addAttribute("currentMessage", requestScopedBean.getMessage());
return "scopesExample";
}
}
(2)会话范围
我们可以定义的bean会话范围以类似的方式:
@Bean
@Scope(value = WebApplicationContext.SCOPE_SESSION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator sessionScopedBean() {
return new HelloMessageGenerator();
}
还有一个专门的由注释我们可以用来简化bean定义:
@Bean
@SessionScope
public HelloMessageGenerator sessionScopedBean() {
return new HelloMessageGenerator();
}
接下来,我们定义了一个控制器与sessionScopedBean参考。再一次,我们需要运行两个请求为了显示消息字段的值是相同的会话。
在这种情况下,当请求是由第一次消息为空值。然而,一旦改变,这个值保留为后续请求返回相同的bean的实例对整个会话。
@Controller
public class ScopesController {
@Resource(name = "sessionScopedBean")
HelloMessageGenerator sessionScopedBean;
@RequestMapping("/scopes/session")
public String getSessionScopeMessage(final Model model) {
model.addAttribute("previousMessage", sessionScopedBean.getMessage());
sessionScopedBean.setMessage("Good afternoon!");
model.addAttribute("currentMessage", sessionScopedBean.getMessage());
return "scopesExample";
}
}
(3)应用范围
应用范围创建bean实例的生命周期ServletContext。
这是类似于单例的范围,但是有一个非常重要的区别对于bean的范围。
当bean是应用程序作用域,同样的bean的实例共享多个基于servlet的应用程序运行在同一ServletContext,而单范围内bean只局限于单个应用程序上下文。
让我们创建bean与应用范围:
@Bean
@Scope(
value = WebApplicationContext.SCOPE_APPLICATION, proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator applicationScopedBean() {
return new HelloMessageGenerator();
}
类似于请求和会话作用域,我们可以使用更短的版本:
@Bean
@ApplicationScope
public HelloMessageGenerator applicationScopedBean() {
return new HelloMessageGenerator();
}
现在让我们创建一个控制器,这个bean引用:
@Controller
public class ScopesController {
@Resource(name = "applicationScopedBean")
HelloMessageGenerator applicationScopedBean;
@RequestMapping("/scopes/application")
public String getApplicationScopeMessage(final Model model) {
model.addAttribute("previousMessage", applicationScopedBean.getMessage());
applicationScopedBean.setMessage("Good afternoon!");
model.addAttribute("currentMessage", applicationScopedBean.getMessage());
return "scopesExample";
}
}
applicationScopedBean在这种情况下,一旦设置,该值为所有后续请求消息将被保留,会话,甚至不同的servlet将访问这个bean的应用程序,它运行在相同的ServletContext。
(4)WebSocket范围
最后,让我们创建的bean websocket范围:
@Bean
@Scope(scopeName = "websocket", proxyMode = ScopedProxyMode.TARGET_CLASS)
public HelloMessageGenerator websocketScopedBean() {
return new HelloMessageGenerator();
}
当第一次访问,WebSocket范围bean存储在WebSocket会话属性。然后返回相同的bean实例时,在整个WebSocket会话bean访问。
我们也可以说,它表现出单的行为,但只局限于一个WebSocket会话。
以上就是关于“Spring作用域的快速指南”的介绍,大家如果想了解更多相关知识,不妨来关注一下本站的Java极悦在线学习技术文档,里面的课程内容细致全面,很适合没有基础的小伙伴学习,希望对大家能够有所帮助哦。
0基础 0学费 15天面授
Java就业班有基础 直达就业
业余时间 高薪转行
Java在职加薪班工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习