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(单例)作用域

方式一:直接设置值

@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);
    }
}

image-20240127020422168

可以看到,当第一次获取 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 +
                '}';
    }
}

image-20240127020339429

此时,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)
@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();
    }
}

image-20240127034859735

  • 18
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CHJBL

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值