Bean作用域和生命周期

2023-12-15 19:45:07

前言

在之前的文章中我们知道, Spring是一个存放Bean的IoC容器, 这个容器的两大核心功能是存Bean和取Bean. 今天来详细了解一下Bean的作用域和生命周期.


Bean的作用域

什么是Bean的作用域

以前我们接触到的作用域说的是变量的可作用范围. 而今天要讲到Bean的作用域不同于之前的作用域, Bean的作用域说的是一个Bean在整个Spring框架中的行为模式. 行为模式有六种. 也就是作用域有六种. 下面将具体介绍这六种行为模式(作用域).

Bean的六种作用域

1. 单例作用域 singleton

singleton单例作用域, 顾名思义. 单例作用域就是在Spring框架中只存有该Bean的一个实例. 在整个框架中对该Bean的注入操作都是同一个对象.

这种作用域是Spring默认的Bean作用域, 适合于无状态的Bean. 所谓无状态就是该Bean的属性对象不需要更新.

当向Spring中存入一个Bean时, Spring默认这个Bean的作用域就是单例的, 因此不需要另外显式配置.

2. 原型作用域 prototype (多例作用域)

prototype多例作用域, 在每次获取Bean(ApplicationContext或通过注解进行注入)时, 都会获取到一个新的实例对象. 该实例对象遵循Spring框架对其进行的初始化操作(@Bean进行初始化).

实际上, 在每次获取实例对象时, 都是通过拷贝一份已有的原型对象实现的.

这种作用域适用于有状态的Bean. 需要注意的是, 这种作用域只适用于Spring框架, 对于Spring MVC和Spring Boot来说是不支持的.

当向Spring中存入一个Bean, 并且要将这个Bean的作用域设置为原型作用域时, 需要用到@Scope("prototype")或者@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
在这里插入图片描述

@Service
public class UserService {
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public User setUser(){
        User user = new User();
        user.setUserid(2);
        user.setUsername("张三");
        user.setPassword("123");
        return user;
    }
}

3. 请求作用域 request

在每此http请求时会生成一个新的实例. 本此请求和响应公用一个实例. 适用于需要在同一次请求处理期间共享数据的Bean, 确保每个请求都有自己的实例. 在Spring MVC和Spring Boot中使用, Spring中不能使用.

使用时需要用到@RequestScope

4. 会话作用域 session

每个Http会话会创建一个实例, 该实例在整个会话中有效. 适用于在整个会话期间内共享数据的Bean. 在Spring MVC中使用, 在Spring中不能使用.

使用时需要用到@SessionScope注解.

5. 全局作用域 application

在整个web应用程序中共享一个Bean, 和单例模式相似但不同.

不同之处在于全局作用域是在整个web应用程序中共享一个Bean, 他是Spring Web中的作用域, 作用于Servlet容器.
而单例模式是在整个Spring容器中共享一个Bean. 是Spring中的作用域, 作用于IoC容器.

6. Http WebSocket作用域 websocket

在一个http webSocket的生命周期中定义一个Bean实例. 仅适用于Spring WebSocket中使用.

Spring的执行流程和Bean的生命周期

Spring的执行流程

Bean的执行流程是从启动Spring容器 ->初始化Bean -> 将Bean注册到Spring中 -> 将Bean装配到需要的类中.


public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Config.xml");
        UserController controller1 = context.getBean("userController", UserController.class);
        controller1.setUser();
        UserController2 controller2 = context.getBean("userController2", UserController2.class);
        controller2.print();
    }
}

  1. 启动Spring容器: 当代码执行到main方法中的ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Config.xml");时, 启动Spring容器. 加载指定的配置文件.
  2. 初始化Bean: 初始化Bean, 就是根据配置文件中指定的要扫描的路径进行扫描, 查找五大类注解和@Bean方法注解. 如果扫描到有需要存到Spring中的Bean, 先实例化(分配内存空间), 然后进行初始化.
  3. 注册Bean对象到容器中. 这就是往Spring中存Bean对象.
  4. 将Bean装配到需要的类中, 这就是注入Bean对象.

Bean的生命周期

生命周期是一个对象从诞生到销毁的整个生命过程, 这个过程就叫做一个对象的生命周期.

Bean的生命周期分为以下五步:

1. 实例化Bean

为Bean分配内存空间


2. 设置属性

将当前Bean所依赖的Bean注入进来. 为当前Bean的初始化做准备.


3. Bean初始化

  1. 发送通知: 继承一些通知接口, 如BeanNameAware, BeanFactoryAware, ApplicationContextAware. 实现这些接口的方法
public class Bean implements BeanNameAware, BeanFactoryAware {
    @Override
    public void setBeanName(String s) {
        System.out.println("通知bean名为 -> " + s);
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("通知工厂bean为 -> " + beanFactory);
    }
}
  1. 执行初始化的前置方法: 通过实现 BeanPostProcessor接口, 重写 postProcessBeforeInitialization方法. 前置方法和后置方法都不用显式调用

这个方法在Bean的初始化方法调用之前被调用. 实现BeanPostProcessor接口并覆写该方法, 可以在Bean初始化之前进行一些自定义的操作. 例如, 对Bean的属性进行修改或验证等.

public class Bean implements BeanNameAware, BeanFactoryAware , BeanPostProcessor {
    @Override
    public void setBeanName(String s) {
        System.out.println("通知bean名为 -> " + s);
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("通知工厂bean为 -> " + beanFactory);
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("执行初始化前置方法");
        return bean;
    }
}
  1. 执行初始化方法: 可以在xml文件中配置, 或者也可以通过注解@PostConstruct. 两者都出现时, 通过注解的方式优先级更高.
    (1) 通过xml文件: 在这里插入图片描述
    <bean id="bean" class="com.annotation.controller.Bean" init-method="beanInit"
          destroy-method="destory"> </bean>
    public void beanInit(){
        System.out.println("通过xml初始化bean");
    }

(2) 通过注解@PostConstruct:

    @PostConstruct
    public void beanInit2(){
        System.out.println("通过注解初始化bean");
    }
  1. 执行初始化的后置方法

这个方法在Bean的初始化方法调用之后被调用. 和前置方法一样实现BeanPostProcessor接口, 重写后置方法postProcessAfterInitialization, 可以在Bean初始化之后进行一些自定义的操作. 例如, 对Bean进行额外的初始化或修改.

public class Bean implements BeanNameAware, BeanFactoryAware , BeanPostProcessor {
    @Override
    public void setBeanName(String s) {
        System.out.println("通知bean名为 -> " + s);
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("通知工厂bean为 -> " + beanFactory);
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("执行初始化前置方法");
        return bean;
    }
    public void beanInit(){
        System.out.println("通过xml初始化bean");
    }
    @PostConstruct
    public void beanInit2(){
        System.out.println("通过注解初始化bean");
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("执行初始化后置方法");
        return bean;
    }
}

4. 使用Bean

    public void print(){
        System.out.println("使用bean");
    }

5. 销毁Bean

销毁Bean的方法与初始化Bean的方法类似, 可以在xml中配置, 也可以通过注解. 与初始化bean不同的是, bean的初始化方法无需显式调用, 而bean的销毁方法需要显式调用.
(1) 通过xml配置

    <bean id="bean" class="com.annotation.controller.Bean" init-method="beanInit"
          destroy-method="destory"> </bean>
    public void destory(){
        System.out.println("通过xml销毁bean");
    }

(2) 通过注解@PreDestroy

    @PreDestroy
    public void destory2(){
        System.out.println("通过注解销毁bean");
    }

代码汇总:
xml配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
	<context:component-scan base-package="com.annotation"></context:component-scan>
    <bean id="bean" class="com.annotation.controller.Bean" init-method="beanInit"
          destroy-method="destory" scope="prototype"> </bean>
</beans>

Bean类:

public class Bean implements BeanNameAware, BeanFactoryAware, BeanPostProcessor{
    @Override
    public void setBeanName(String s) {
        System.out.println("通知bean名为 -> " + s);
    }
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("通知工厂bean为 -> " + beanFactory);
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("执行初始化前置方法");
        return bean;
    }
    public void beanInit(){
        System.out.println("通过xml初始化bean");
    }
    @PostConstruct
    public void beanInit2(){
        System.out.println("通过注解初始化bean");
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("执行初始化后置方法");
        return bean;
    }
    public void destory(){
        System.out.println("通过xml销毁bean");
    }
    @PreDestroy
    public void destory2(){
        System.out.println("通过注解销毁bean");
    }
    public void print(){
        System.out.println("使用bean");
    }
}

Main类:

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Config.xml");
//        UserController controller1 = context.getBean("userController", UserController.class);
//        controller1.setUser();
//        UserController2 controller2 = context.getBean("userController2", UserController2.class);
//        controller2.print();
        Bean bean = context.getBean("bean", Bean.class);
        bean.print();
        bean.destory();
        bean.destory2();
    }
}

文章来源:https://blog.csdn.net/qq_62414152/article/details/134884355
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。