Spring 的执行流程以及 Bean 的作用域和生命周期

文章目录

Bean 的作用域

Spring 容器在初始化⼀个 Bean 的实例时,同时会指定该实例的作用域。Bean 有6种作用域

  1. singleton:单例作用域
  2. prototype:原型作用域(多例作用域)
  3. request:请求作用域 (一个http 请求共享一个 Bean)
  4. session:会话作用域 (一个会话共享一个 Bean)
  5. application:全局作用域 (一个上下文对象共享一个 Bean)
  6. websocket:HTTP WebSocket 作用域(只适用于Spring WebSocket 项目)

其中后面四种是基于 Spring MVC 生效的

更改作用域的方式

使用 @Scope 标签就可以用来声明 Bean 的作用域,不指定默认为 singleton(单例)作用域

方式一:直接设置值

java 复制代码
@Scope("prototype")
public class User {
    private Integer id = 1;
    private String name = "张三";

    @Override
    public String toString() {
        return "UserController{" +
                "id = " + id + ", " +
                "name = " + name +
                '}';
    }
}

方式二:使用枚举设置

java 复制代码
@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 默认的作用域

java 复制代码
@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 +
                '}';
    }
}
java 复制代码
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注入)都是新的对象实例。

java 复制代码
@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 执行流程

分为四个步骤

  1. 启动 Spring 容器(加载配置文件)
  2. 实例化 Bean(分配内存空间)
  3. Bean 注册到 Spring 中(存)
  4. 将 Bean 装配到需要的类(取)

Bean 的生命周期

Bean 的生命周期分为五大部分

  1. 实例化 Bean(分配内存空间)
  2. 设置属性(注入和装配)
  3. Bean 初始化
    1. 实现各种 Aware 通知的方法(例如 BeanNameAware,BeanFactoryAware的接口方法)
    2. 执行 BeanPostProcessor 初始化前置方法
    3. 执行 @PostConstruct 初始化方法,依赖注入操作之后被执行
    4. 如果有指定init-method 方法则执行
    5. 执行 BeanPostProcessor 初始化后置方法
  4. 使用 Bean
  5. 销毁 Bean(销毁方法例如:如 @PreDestroy、DisposableBean 接口方法、destroy-method)
java 复制代码
@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 文件进行配置

xml 复制代码
<bean id="user" class="spring.demo.entity.User" init-method="Init"></bean>

接着启动类启动

java 复制代码
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();
    }
}
相关推荐
孤廖12 分钟前
【算法磨剑:用 C++ 思考的艺术・Dijkstra 实战】弱化版 vs 标准版模板,洛谷 P3371/P4779 双题精讲
java·开发语言·c++·程序人生·算法·贪心算法·启发式算法
码畜也有梦想25 分钟前
Maven中optional的作用
java·jenkins·maven
云和数据.ChenGuang44 分钟前
java常见SSL bug解决方案
java·bug·ssl
songx_991 小时前
leetcode29( 有效的括号)
java·数据结构·算法·leetcode
于樱花森上飞舞1 小时前
【java】常见排序算法详解
java·算法·排序算法
维持好习惯1 小时前
复杂Excel文件导入功能(使用AI快速实现)
java·spring boot·excel
酷炫码神1 小时前
第 2 篇:Java 入门实战(JDK8 版)—— 编写第一个 Java 程序,理解基础运行逻辑
java·开发语言·策略模式
月阳羊1 小时前
【硬件-笔试面试题-93】硬件/电子工程师,笔试面试题(知识点:波特图)
java·经验分享·单片机·嵌入式硬件·面试
choice of2 小时前
SpringMVC通过注解实现全局异常处理
java·后端·spring
单线程bug2 小时前
Spring Boot中Filter与Interceptor的区别
java·spring boot·后端