文章目录
- Bean 的作用域
- 更改作用域的方式
- singleton
- prototype
- Spring 执行流程
- Bean 的生命周期
Bean 的作用域
Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作用域。Bean 有6种作用域
- singleton:单例作用域
- prototype:原型作用域(多例作用域)
- request:请求作用域 (一个http 请求共享一个 Bean)
- session:会话作用域 (一个会话共享一个 Bean)
- application:全局作用域 (一个上下文对象共享一个 Bean)
- websocket:HTTP WebSocket 作用域(只适用于Spring WebSocket 项目)
其中后面四种是基于 Spring MVC 生效的
更改作用域的方式
使用 @Scope 标签就可以用来声明 Bean 的作用域,不指定默认为 singleton(单例)作用域
方式一:直接设置值
@Scope("prototype")
public class User {
private Integer id = 1;
private String name = "张三";
@Override
public String toString() {
return "UserController{" +
"id = " + id + ", " +
"name = " + name +
'}';
}
}
方式二:使用枚举设置
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class User {
private Integer id = 1;
private String name = "张三";
@Override
public String toString() {
return "UserController{" +
"id = " + id + ", " +
"name = " + name +
'}';
}
}
singleton
作用域下的Bean在IoC容器中只存在⼀个实例:获取Bean及装配Bean都是同⼀个对象。
通常Bean对象的属性状态不需要更新的时候使用。
该种作用域也是 Bean 默认的作用域
@Getter // Lombok
@Setter // Lombok
@Controller
public class User {
private Integer id = 1;
private String name = "张三";
@Override
public String toString() {
return "UserController{" +
"id = " + id + ", " +
"name = " + name +
'}';
}
}
public class Start {
public static void main(String[] args) {
// 获取 Spring 的上下文对象
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 获取 Bean 对象
User user1 = context.getBean("user", User.class);
System.out.println("user1 -> " + user1);
user1.setId(2);
user1.setName("王五");
User user2 = context.getBean("user", User.class);
System.out.println("user2 -> " + user2);
}
}
可以看到,当第一次获取 bean 时在没有任何修改的情况下,打印的结果是初始值。但对这个 bean 进行修改后,之后再次获取该 bean 的结果就是修改后的结果
prototype
每次对该作用域下的Bean的请求都会创建新的实例,也就是说获取Bean 和装配Bean(即通过@Autowired注入)都是新的对象实例。
@Getter // Lombok
@Setter // Lombok
@Controller
@Scope("prototype")
public class User {
private Integer id = 1;
private String name = "张三";
@Override
public String toString() {
return "UserController{" +
"id = " + id + ", " +
"name = " + name +
'}';
}
}
此时,user1 和 user2就互不干扰了
Spring 执行流程
分为四个步骤
- 启动 Spring 容器(加载配置文件)
- 实例化 Bean(分配内存空间)
- Bean 注册到 Spring 中(存)
- 将 Bean 装配到需要的类(取)
Bean 的生命周期
Bean 的生命周期分为五大部分
- 实例化 Bean(分配内存空间)
- 设置属性(注入和装配)
- Bean 初始化
- 实现各种 Aware 通知的方法(例如 BeanNameAware,BeanFactoryAware的接口方法)
- 执行 BeanPostProcessor 初始化前置方法
- 执行 @PostConstruct 初始化方法,依赖注入操作之后被执行
- 如果有指定init-method 方法则执行
- 执行 BeanPostProcessor 初始化后置方法
- 使用 Bean
- 销毁 Bean(销毁方法例如:如 @PreDestroy、DisposableBean 接口方法、destroy-method)
@Controller
public class User {
private Integer id = 1;
private String name = "张三";
// 初始化
@PostConstruct
public void PostConstruct(){
System.out.println("执行初始化");
}
// 指定 init-method 方法
public void Init(){
System.out.println("执行Init-method方法");
}
// 销毁
@PreDestroy
public void Des(){
System.out.println("执行销毁");
}
@Override
public String toString() {
return "UserController{" +
"id = " + id + ", " +
"name = " + name +
'}';
}
}
如果需要使用指定的 init-method 方法,需要在xml 文件进行配置
<bean id="user" class="spring.demo.entity.User" init-method="Init"></bean>
接着启动类启动
public class Start {
public static void main(String[] args) {
// 获取 Spring 的上下文对象
ApplicationContext context =
new ClassPathXmlApplicationContext("spring-config.xml");
// 获取 Bean 对象
User user1 = context.getBean("user", User.class);
System.out.println(user1);
user1.Des();
}
}