Spring 原理
- [1. Bean的作⽤域](#1. Bean的作⽤域)
-
- [1.1 概念](#1.1 概念)
- [1.2 Bean的作⽤域](#1.2 Bean的作⽤域)
- [2. Bean的⽣命周期](#2. Bean的⽣命周期)
1. Bean的作⽤域
1.1 概念
在Spring IoC&DI阶段, 我们学习了Spring是如何帮助我们管理对象的.
- 通过 @Controller , @Service , @Repository , @Component , @Configuration ,@Bean 来声明Bean对象。
- 通过 ApplicationContext 或者 BeanFactory 来获取对象
- 通过 @Autowired , Setter ⽅法或者构造⽅法等来为应⽤程序注⼊所依赖的Bean对象
我们来简单回顾⼀下
- 通过 @Bean 声明bean , 把bean存在Spring容器中
java
public class Dog {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
java
@Configuration
public class BeanConfig {
@Bean
public Dog dog() {
Dog dog = new Dog();
dog.setName("旺财");
return dog;
}
}
- 从Spring容器中获取Bean

也可以通过在代码中直接注⼊ApplicationContext的⽅式来获取Spring容器

修改代码, 从Spring容器中多次获取Bean

观察运⾏结果:

发现输出的bean对象地址值是⼀样的, 说明每次从Spring容器中取出来的对象都是同⼀个.
这也是"单例模式"
单例模式: 确保⼀个类只有⼀个实例,多次创建也不会创建出多个实例
默认情况下, Spring容器中的bean都是单例的, 这种⾏为模式, 我们就称之为Bean的作⽤域.
Bean 的作⽤域是指 Bean 在 Spring 框架中的某种⾏为模式
⽐如单例作⽤域: 表⽰ Bean 在整个 Spring 中只有⼀份, 它是全局共享的. 那么当其他⼈修改了这个值之后, 那么另⼀个⼈读取到的就是被修改的值.
修改上述代码, 给UserController添加属性name\
修改测试代码

观察运⾏结果

dog1 和 dog2 为同⼀个对象, dog2 拿到了 dog1 设置的值.
这就是Bean的不同作⽤域了
1.2 Bean的作⽤域
在Spring中⽀持6种作⽤域,后4种在Spring MVC环境才⽣效
- singleton:单例作⽤域
- prototype:原型作⽤域(多例作⽤域)
- request:请求作⽤域
- session:会话作⽤域
- Application: 全局作⽤域
- websocket:HTTP WebSocket 作⽤域

参考⽂档: https://docs.spring.io/spring-framework/reference/core/beans/factory-scopes.html
我们来简单看下代码实现
定义⼏个不同作⽤域的Bean
java
@Configuration
public class BeanConfig {
@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;
}
}

proxyMode⽤来为spring bean设置代理. proxyMode = ScopedProxyMode.TARGET_CLASS表⽰这个Bean基于CGLIB实现动态代理. Request, session和application作⽤域的Bean 需要设置proxyMode .
观察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可以有多个. (了解即可)
2. Bean的⽣命周期
⽣命周期指的是⼀个对象从诞⽣到销毁的整个⽣命过程, 我们把这个过程就叫做⼀个对象的⽣命周期.
Bean 的⽣命周期分为以下5个部分:

实例化和属性赋值对应构造⽅法和setter⽅法的注⼊. 初始化和销毁是⽤⼾能⾃定义扩展的两个阶段,可以在实例化之后, 类加载完成之前进⾏⾃定义"事件"处理.
