Spring Bean的作用域和生命周期

  1. Spring中5种作用域
  2. 基本作用域的使用
  3. 基本作用域Bean的生命周期
  4. 验证基本作用域生命周期

Spring中5种作用域

在Spring配置Bean时, 可以通过设置scope属性来定义Bean的作用域, 按照scope的值来分, Bean的作用域分为以下几种:

  1. [基本作用域]singeton: 单例模式(默认方式), 每次返回同一个对象实例. 通过设置其 lazy-init参数可以设置是否延迟生成对象, 并将该对象存储在内部的ConcurrentHashMap中.
  2. [基本作用域]prototype: 原型模式, 每次都返回一个新的对象实例. 每次获取时才回去创建该对象.
  3. [Spring的Web作用域]request: 同一次请求返回同一个对象实例.
  4. [Spring的Web作用域]session: 同一次会话返回同一个对象实例.
  5. [Spring的Web作用域]global-session: 所有会话返回同一个对象实例.

基本作用域的使用

需要引入spring-core, spring-bean

public class ScopeDemo {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Scope.xml");
        System.out.println("singleton: " + (context.getBean(SingetonBean.class) == context.getBean(SingetonBean.class)));
        System.out.println("prototype: " + (context.getBean(PrototypeBean.class) == context.getBean(PrototypeBean.class)));
        System.out.println("default: " + (context.getBean(DefaultBean.class) == context.getBean(DefaultBean.class)));
        // 输出 : 
        // singleton: true
        // prototype: false
        // default: true
    }
}

class DefaultBean {
}

class SingetonBean {
}

class PrototypeBean {
}

//Spring-Scope.xml 文件放入resources文件夹中
<?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 class="fun.zhaoxi.scope.SingetonBean" scope="singleton"/>
    <bean class="fun.zhaoxi.scope.PrototypeBean" scope="prototype"/>
    <bean class="fun.zhaoxi.scope.DefaultBean"/>
</beans>

基本作用域Bean的生命周期

从源码(版本 5.0.4)解读, Bean的生命周期的入口是getBean()方法, 大概分为以下的步骤:

  1. 当容器启动时, 会扫描所有的Bean信息, 并存储起来, 如果有Singleton的bean且没有设置延迟加载, 那么直接执行下面的初始化过程并缓存.
  2. 如果传入参数是类型为Class ,那么首先解析该Bean的名字, 默认BeanName = 类的全名; 如果传入名字是BeanName那么直接使用.
  3. 首先从步骤1的缓存中根据Key=BeanName读取Bean对象, 如果有直接返回.
  4. 如果没有的话, 就检测其父工厂是否包含该Bean, 如果有, 直接返回.
  5. 检测当前Bean是否有依赖Bean, 如果有依赖Bean, 首先构造依赖的Bean.
  6. 检测当前Bean的作用域, 如果是Singleton, 那么直接开始构造Bean; 如果是Prototype, 则现将当前BeanName写入到循环依赖检测的ThreadLocal中(构造完成后从ThreadLocal中移除), 再开始构造Bean.
  7. 开始真正的创建Bean:
    7-1: 构造Bean调用其构造函数(工厂方法)构造对象并设置其属性值(如果属性值, 构造函数参数是复杂对象, 先构造这些复杂参数)
    7-2: 如果BeanClass实现了BeanNameAware, 那么执行其setBeanName()方法
    7-3: 如果BeanClass实现了BeanClassLoaderAware, 那么执行其setBeanClassLoader()方法
    7-4: 如果BeanClass实现了BeanFactoryAware, 那么执行其setBeanFactory()方法
    7-5: 执行BeanPostProcessors的postProcessBeforeInitialization方法, 返回后置处理器包装后的Bean, 如果没有直接返回当前Bean
    7-6: 执行bean的init-method方法
    7-7: 执行BeanPostProcessors的postProcessAfterInitialization方法, 返回处理器包装后的Bean, 没有直接返回当前Bean
    7-8: 真正返回Bean
  8. 当容器关闭的时候, 执行Bean的destroy-method方法.

验证基本作用域生命周期

class DemoBean implements BeanNameAware, BeanClassLoaderAware, BeanFactoryAware {

    private String name;

    public DemoBean() {
        System.out.println("ctor");
    }

    public void setName(String name) {
        this.name = name;
        System.out.println("set name " + name);
    }

    public void init() {
        System.out.println("bean init");
    }

    public void destroy() {
        System.out.println("bean destroy");
    }

    public void setBeanName(String name) {
        System.out.println("set bean name " + name);
    }

    public void setBeanClassLoader(ClassLoader classLoader) {
        System.out.println("set bean ClassLoader ");
    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("set bean Factory ");
    }
}

class DemoBeanPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + " postProcessBeforeInitialization ");
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName + " postProcessAfterInitialization ");
        return bean;
    }
}

//Spring-Scope.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd"> 
    <bean id="demoBean" class="fun.zhaoxi.scope.DemoBean" init-method="init" 
    destroy-method="destroy" scope="prototype">
        <property name="name" value="demoBean-name"/>
    </bean> 
    <bean class="fun.zhaoxi.scope.DemoBeanPostProcessor"/>
</beans>


public class ScopeDemo {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Spring-Scope.xml");
        context.getBean("demoBean"); 
        ((ClassPathXmlApplicationContext) context).close();
    }
}
// 输出:
// ctor
// set name demoBean-name
// set bean name demoBean
// set bean ClassLoader 
// set bean Factory 
// demoBean postProcessBeforeInitialization 
// bean init
// demoBean postProcessAfterInitialization

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 zhao4xi@126.com

文章标题:Spring Bean的作用域和生命周期

文章字数:1.2k

本文作者:Zhaoxi

发布时间:2018-12-26, 15:09:21

最后更新:2019-09-21, 15:19:24

原始链接:http://zhao4xi.github.io/2018/12/26/Spring-Bean的作用域和生命周期/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录