5、Spring之bean的作用域和生命周期

5.1、bean的作用域

5.1.1、单例(默认且常用)

5.1.1.1、配置bean

注意:当bean不配置scope属性时,默认是singleton(单例)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="org.rain.spring.pojo.Student"></bean>

</beans>

5.1.1.2、测试

由控制台日志可知,此时ioc获取到的两个bean本质上是同一个对象

    @Test
    public void testScope() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-scope.xml");
        Student student1 = applicationContext.getBean(Student.class);
        Student student2 = applicationContext.getBean(Student.class);
        System.out.println(student1 == student2);
    }

5.1.2、多例

5.1.2.1、配置bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
    scope属性:设置bean的作用域
        当属性值为singleton时,在IOC容器中这个bean的对象始终为单实例;且创建对象的时机是IOC容器初始化时
        当属性值为prototype时,在IOC容器中这个bean的对象有多个实例;且创建对象的时机是获取bean时
    -->
    <bean id="student" class="org.rain.spring.pojo.Student" scope="prototype"></bean>

</beans>

5.1.2.2、测试

由控制台日志可知,此时ioc获取到的两个bean本质上是不同的对象

5.1.3、其他作用域

如果是在WebApplicationContext环境下还会有另外两个作用域(但不常用):

  • request:在一个请求范围内有效

  • session:在一个会话范围内有效

5.2、bean的生命周期

5.2.1、创建User类

package org.rain.spring.pojo;

/**
 * @author liaojy
 * @date 2023/8/3 - 23:59
 */
public class User {

    private Integer id;
    private String username;
    private String password;
    private Integer age;

    public User() {
        System.out.println("生命周期1:创建对象");
    }

    public User(Integer id, String username, String password, Integer age) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.age = age;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        System.out.println("生命周期2:依赖注入");
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void initMethod(){
        System.out.println("生命周期3:初始化");
    }

    public void destroyMethod(){
        System.out.println("生命周期4:销毁");
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", age=" + age +
                '}';
    }
}

5.2.2、配置bean

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
        init-method属性:指定初始化方法
        destroy-method属性:指定销毁方法
    -->
    <bean id="user" class="org.rain.spring.pojo.User" init-method="initMethod" destroy-method="destroyMethod">
        <property name="id" value="1"></property>
        <property name="username" value="张三"></property>
        <property name="password" value="123"></property>
        <property name="age" value="11"></property>
    </bean>

</beans>

5.2.3、测试

    @Test
    public void testLifecycle(){
        //ConfigurableApplicationContext是ApplicationContext子接口,扩展了刷新和关闭容器的方法
        ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
        User user = ioc.getBean(User.class);
        System.out.println(user);
        ioc.close();
    }

5.3、作用域对生命周期的影响

5.3.1、作用域为单例时

5.3.1.1、配置bean

    <bean id="user" class="org.rain.spring.pojo.User" init-method="initMethod" destroy-method="destroyMethod">
        <property name="id" value="1"></property>
        <property name="username" value="张三"></property>
        <property name="password" value="123"></property>
        <property name="age" value="11"></property>
    </bean>

5.3.1.2、测试

由控制台日志可知,当bean的作用域为单例时,生命周期的前三个步骤会在获取IOC容器时执行

    @Test
    public void testLifecycle(){
        //ConfigurableApplicationContext是ApplicationContext子接口,扩展了刷新和关闭容器的方法
        ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
    }

5.3.2、作用域为多例时

5.3.2.1、配置bean

    <bean id="user" class="org.rain.spring.pojo.User" init-method="initMethod" destroy-method="destroyMethod" scope="prototype">
        <property name="id" value="1"></property>
        <property name="username" value="张三"></property>
        <property name="password" value="123"></property>
        <property name="age" value="11"></property>
    </bean>

5.3.2.2、测试

由控制台日志可知,当bean的作用域为多例时,生命周期的前三个步骤会在获取bean时执行

    @Test
    public void testLifecycle(){
        //ConfigurableApplicationContext是ApplicationContext子接口,扩展了刷新和关闭容器的方法
        ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
        User user = ioc.getBean(User.class);
    }

5.4、bean的后置处理器

5.4.1、创建bean的后置处理器

注意:自定义的bean后置处理器,需要实现BeanPostProcessor接口

package org.rain.spring.process;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * @author liaojy
 * @date 2023/8/4 - 23:52
 */
public class MyBeanProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanProcessor-->后置处理器postProcessBeforeInitialization");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanProcessor-->后置处理器postProcessAfterInitialization");
        return bean;
    }
}

5.4.2、配置bean的后置处理器

注意:bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行

    <!-- bean的后置处理器要放入IOC容器才能生效 -->
    <bean id="myBeanPostProcessor" class="org.rain.spring.process.MyBeanProcessor"></bean>

5.4.3、测试

由控制台日志可知,bean的后置处理器会在生命周期的初始化前后添加额外的操作

    @Test
    public void testLifecycle(){
        //ConfigurableApplicationContext是ApplicationContext子接口,扩展了刷新和关闭容器的方法
        ConfigurableApplicationContext ioc = new ClassPathXmlApplicationContext("spring-lifecycle.xml");
        User user = ioc.getBean(User.class);
        System.out.println(user);
        ioc.close();
    }

5.5、具体的生命周期过程

  • bean对象创建(调用无参构造器)

  • 给bean对象设置属性

  • bean对象初始化之前操作(由bean的后置处理器负责)

  • bean对象初始化(需在配置bean时指定初始化方法)

  • bean对象初始化之后操作(由bean的后置处理器负责)

  • bean对象就绪可以使用

  • bean对象销毁(需在配置bean时指定销毁方法)

  • IOC容器关闭

热门相关:倾心之恋:总裁的妻子   本法官萌萌哒   异世修真邪君   豪门情变,渣总裁滚远点!   大妆