文章目录
- 🍃Bean的作用域
- 🚩作用域的使用
- 🚩观察Bean的作用域
- 🎈单例作用域
- 🎈多例作用域
- 🎈请求作用域
- 🎈会话作⽤域
- 🎈Application作⽤域
- 🎄Bean的⽣命周期
- ⭕总结
🍃Bean的作用域
Bean的作⽤域是指Bean在Spring框架中的某种⾏为模式.
比如单例作⽤域:表⽰ Bean 在整个Spring 中只有⼀份, 它是全局共享的.那么当其他⼈修改了这个值之后,那么另⼀个⼈读取到的就是被修改的值.
在Spring中⽀持6种作⽤域,后4种在Spring MVC环境才⽣效
-
singleton:单例作⽤域
-
prototype:原型作⽤域(多例作⽤域)
-
request:请求作⽤域
-
session:会话作⽤域
-
Application: 全局作⽤域
-
websocket:HTTP WebSocket 作⽤域
作⽤域 | 说明 |
---|---|
singleton | 每个Spring IoC容器内同名称的bean只有⼀个实例(单例)(默认) |
prototype | 每次使⽤该bean时会创建新的实例(⾮单例) |
request | 每个HTTP 请求⽣命周期内,创建新的实例(web环境中) |
session | 每个HTTP Session⽣命周期内,创建新的实例(web环境中) |
application | 每个ServletContext⽣命周期内,创建新的实例(web环境中) |
websocket | 每个WebSocket⽣命周期内,创建新的实例(web环境中) |
🚩作用域的使用
简单使用如下:
首先我们准备一个 Dog 类如下:
public class Dog {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
接下来我们定义几个不同作用域的 Bean
@Component
public class DogBean {
@Bean
public Dog dog() {
Dog dog = new Dog();
dog.setName("旺财");
return dog;
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
public Dog singleDog(){
Dog dog = new Dog();
return dog;
}
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public Dog prototypeDog(){
Dog dog = new Dog();
return dog;
}
@Bean
@RequestScope
public Dog requestDog() {
Dog dog = new Dog();
return dog;
}
@Bean
@SessionScope
public Dog sessionDog() {
Dog dog = new Dog();
return dog;
}
@Bean
@ApplicationScope
public Dog applicationDog() {
Dog dog = new Dog();
return dog;
}
}
需要注意的是
@RequestScope 等同于
@Scope(value =WebApplicationContext.SCOPE_REQUEST, proxyMode=ScopedProxyMode.TARGET_CLASS)
@SessionScope 等同于
@Scope(value=WebApplicationContext.SCOPE_SESSION, proxyMode=ScopedProxyMode.TARGET_CLASS)
@ApplicationScope 等同于 @Scope(value=WebApplicationContext.SCOPE_APPLICATION,proxyMode=ScopedProxyMode.TARGET_CLASS)
proxyMode⽤来为springbean设置代理.
proxyMode = ScopedProxyMode.TARGET_CLASS
表⽰这个Bean基于CGLIB实现动态代理.
Request,session和application作⽤域的Bean需要设置proxyMode
接下来我们再写一些程序进行测试,测试不同作⽤域的Bean取到的对象是否⼀样,测试程序如下:
@RestController
public class DogController {
@Autowired
private Dog singleDog;
@Autowired
private Dog prototypeDog;
@Autowired
private Dog requestDog;
@Autowired
private Dog sessionDog;
@Autowired
private Dog applicationDog;
@Autowired
private ApplicationContext applicationContext;
@RequestMapping("/single")
public String single(){
Dog contextDog = (Dog)applicationContext.getBean("singleDog");
return "dog:"+singleDog.toString()+"|-- --|contextDog:"+contextDog;
}
@RequestMapping("/prototype")
public String prototype(){
Dog contextDog = (Dog)applicationContext.getBean("prototypeDog");
return "dog:"+prototypeDog.toString()+"|-- --|contextDog:"+contextDog;
}
@RequestMapping("/request")
public String request(){
Dog contextDog = (Dog)applicationContext.getBean("requestDog");
return
"dog:"+requestDog.toString()+"|-- --|contextDog:"+contextDog.toString();
}
@RequestMapping("/session")
public String session(){
Dog contextDog = (Dog)applicationContext.getBean("sessionDog");
return "dog:"+sessionDog.toString()+"|-- --|contextDog:"+contextDog.toString();
}
@RequestMapping("/application")
public String application(){
Dog contextDog = (Dog)applicationContext.getBean("applicationDog");
return "dog:"+applicationDog.toString()+"|-- --|contextDog:"+contextDog.toString();
}
}
🚩观察Bean的作用域
接下来我们来进行访问
🎈单例作用域
- http://127.0.0.1:8080/single
多次访问,得到的都是同⼀个对象,并且 @Autowired 和applicationContext.getBean() 也是同⼀个对象.
🎈多例作用域
- http://127.0.0.1:8080/prototype
观察ContextDog,每次获取的对象都不⼀样(注⼊的对象在Spring容器启动时,就已经注⼊了,所以多次请求也不会发⽣变化)
🎈请求作用域
- http://127.0.0.1:8080/request
在⼀次请求中, @Autowired 和 applicationContext.getBean() 也是同⼀个对象.但是每次请求,都会重新创建对象
🎈会话作⽤域
- http://127.0.0.1:8080/session
在⼀个session中,多次请求,获取到的对象都是同⼀个.
换⼀个浏览器访问,发现会重新创建对象.(另⼀个Session)
🎈Application作⽤域
- http://127.0.0.1:8080/application
在⼀个应⽤中,多次访问都是同⼀个对象
Application scope就是对于整个web容器来说,bean的作⽤域是ServletContext级别的.
这个和singleton有点类似,区别在于:Application scope是ServletContext的单例,singleton是⼀个ApplicationContext的单例.
在⼀个web容器中ApplicationContext可以有多个
🎄Bean的⽣命周期
⽣命周期指的是⼀个对象从诞⽣到销毁的整个⽣命过程,我们把这个过程就叫做⼀个对象的⽣命周期.
Bean的⽣命周期分为以下5个部分:
- 实例化(为Bean分配内存空间)
- 属性赋值(Bean注⼊和装配,⽐如 @AutoWired )
- 初始化
- 执⾏各种通知,如 BeanNameAware ,BeanFactoryAware ,ApplicationContextAware 的接⼝⽅法.
- 执⾏初始化⽅法
-
- xml定义 init-method
-
- 使⽤注解的⽅式 @PostConstruct
-
- 执⾏初始化后置⽅法( BeanPostProcessor )
- 使⽤Bean
- 销毁Bean
- 销毁容器的各种⽅法,如 @PreDestroy , DisposableBean 接⼝⽅法, destroymethod.
实例化和属性赋值对应构造⽅法和setter⽅法的注入.
初始化和销毁是用户能⾃定义扩展的两个阶段,可以在实例化之后,类加载完成之前进⾏⾃定义"事件"处理.
⽐如我们现在需要买⼀栋房⼦,那么我们的流程是这样的:
- 先买房(实例化,从⽆到有)
- 装修(设置属性)
- 买家电,如洗⾐机,冰箱,电视,空调等([各种]初始化,可以⼊住);
- ⼊住(使⽤Bean)
- 卖房(Bean销毁)
执行流程如下图所示:
⭕总结
关于《【JavaEE进阶】 Bean的作用域与生命周期》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!