美文网首页
Spring之Bean的作用域与生命周期

Spring之Bean的作用域与生命周期

作者: 小七奇奇 | 来源:发表于2018-08-24 23:16 被阅读58次

    Version:1.0 StartHTML:000000209 EndHTML:000019387 StartFragment:000001892 EndFragment:000019301 StartSelection:000001892 EndSelection:000019291 SourceURL:https://www.cnblogs.com/5ishare/p/9532057.html <title>Spring之Bean的作用域与生命周期 - 社会主义接班人 - 博客园</title><link href="/bundles/blog-common.css?v=PX31qVjOE47mNaZI9JUSFK-ajuzMnpXA9PeteRNR1Qw1" rel="stylesheet" type="text/css"><link id="MainCss" href="/skins/red_autumnal_leaves/bundle-red_autumnal_leaves.css?v=EDEp2d1uMe8iyN6qDoW8MQgYb-JCFIeiYP0oX3XiiRM1" rel="stylesheet" type="text/css"><link id="mobile-style" href="/skins/red_autumnal_leaves/bundle-red_autumnal_leaves-mobile.css?v=d9LctKHRIQp9rreugMcQ1-UJuq_j1fo0GZXTXj8Bqrk1" rel="stylesheet" type="text/css" media="only screen and (max-width: 767px)"><link title="RSS" href="http://www.cnblogs.com/5ishare/rss" rel="alternate" type="application/rss+xml"><link title="RSD" href="http://www.cnblogs.com/5ishare/rsd.xml" rel="EditURI" type="application/rsd+xml"><link href="http://www.cnblogs.com/5ishare/wlwmanifest.xml" rel="wlwmanifest" type="application/wlwmanifest+xml"> <script type="text/javascript">var currentBlogApp = '5ishare', cb_enable_mathjax=false;var isLogined=true;</script>

    在前面博客中提到容器启动获得BeanDefinition对象中有一个scope 属性。该属性控制着bean对象的作用域。本章节介绍Bean的作用域及生命周期,了解bean是怎么来的又怎么没的。

    一、Bean的作用域
    在Bean容器启动会读取bean的xml配置文件,然后将xml中每个bean元素分别转换成BeanDefinition对象。在BeanDefinition对象中有scope 属性,就是它控制着bean的作用域。
    Spring框架支持5种作用域,有三种作用域是当开发者使用基于web的ApplicationContext的时候才生效的。下面就是Spring直接支持的作用域了,当然开发者也可以自己定制作用域。

    |

    作用域

    |

    描述

    |
    |

    单例(singleton)

    |

    (默认)每一个Spring IoC容器都拥有唯一的一个实例对象

    |
    |

    原型(prototype)

    |

    一个Bean定义,任意多个对象

    |
    |

    请求(request)

    |

    一个HTTP请求会产生一个Bean对象,也就是说,每一个HTTP请求都有自己的Bean实例。只在基于web的Spring ApplicationContext中可用

    |
    |

    会话(session)

    |

    限定一个Bean的作用域为HTTPsession的生命周期。同样,只有基于web的Spring ApplicationContext才能使用

    |
    |

    全局会话(global session)

    |

    限定一个Bean的作用域为全局HTTPSession的生命周期。通常用于门户网站场景,同样,只有基于web的Spring ApplicationContext可用

    |

    我们可以以XMLInstance类为基础演示一下singleton和prototype作用域。
    这里使用通过BeanFactory的getBean方法获取两次bean对象。

    <pre> XMLInstance instance=(XMLInstance)factory.getBean("xmlinstance");
    instance.setName("123");
    instance.Breath();
    instance=(XMLInstance)factory.getBean("xmlinstance");
    instance.Breath();</pre>

    如果我们采用bean默认的作用域singleton,如下配置,则两个getbean获取的对象是一致的。

    <pre> <bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="singleton">
    <property name="air" ref="CleanAir"></property>
    <property name="name" value="abc"></property>
    </bean></pre>

    <pre>输出结果:
    Name:123;Air:CleanAir
    Name:123;Air:CleanAir</pre>

    如果我们采用bean默认的作用域singleton,如下配置,则两个getbean获取的对象是不一致的。

    <pre> <bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="prototype">
    <property name="air" ref="CleanAir"></property>
    <property name="name" value="abc"></property>
    </bean></pre>

    <pre>输出结果:
    Name:123;Air:CleanAir
    Name:abc;Air:CleanAir</pre>

    二、Bean的生命周期
    前面章节介绍了bean容器以及bean的配置与注入,本章节学习bean的生命周期,了解bean是怎么来的又是怎么没的。

    image

    ApplicationContext容器中,Bean的生命周期流程如上图所示,流程大致如下:
    1.首先容器启动后,会对scope为singleton且非懒加载的bean进行实例化,
    2.按照Bean定义信息配置信息,注入所有的属性,
    3.如果Bean实现了BeanNameAware接口,会回调该接口的setBeanName()方法,传入该Bean的id,此时该Bean就获得了自己在配置文件中的id,
    4.如果Bean实现了BeanFactoryAware接口,会回调该接口的setBeanFactory()方法,传入该Bean的BeanFactory,这样该Bean就获得了自己所在的BeanFactory,
    5.如果Bean实现了ApplicationContextAware接口,会回调该接口的setApplicationContext()方法,传入该Bean的ApplicationContext,这样该Bean就获得了自己所在的ApplicationContext,
    6.如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessBeforeInitialzation()方法,
    7.如果Bean实现了InitializingBean接口,则会回调该接口的afterPropertiesSet()方法,
    8.如果Bean配置了init-method方法,则会执行init-method配置的方法,
    9.如果有Bean实现了BeanPostProcessor接口,则会回调该接口的postProcessAfterInitialization()方法,
    10.经过流程9之后,就可以正式使用该Bean了,对于scope为singleton的Bean,Spring的ioc容器中会缓存一份该bean的实例,而对于scope为prototype的Bean,每次被调用都会new一个新的对象,期生命周期就交给调用方管理了,不再是Spring容器进行管理了
    11.容器关闭后,如果Bean实现了DisposableBean接口,则会回调该接口的destroy()方法,
    12.如果Bean配置了destroy-method方法,则会执行destroy-method配置的方法,至此,整个Bean的生命周期结束。

    这里在UserBean类基础上进行改造,增加了name属性并实现了ApplicationContextAware接口。

    image image

    <pre>package com.demo.model; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class UserBean implements BeanNameAware,BeanFactoryAware,InitializingBean,DisposableBean,ApplicationContextAware { private String name; public String getName() { return name;
    } public void setName(String name) { this.name = name;
    System.out.println("set方法被调用");
    } public UserBean() {
    System.out.println("UserBean类构造方法");
    } public void setBeanName(String name) {
    System.out.println("BeanNameAware被调用");
    } public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
    System.out.println("BeanFactoryAware被调用");
    } public void afterPropertiesSet() throws Exception {
    System.out.println("InitializingBean被调用");
    } public void destroy() throws Exception {
    System.out.println("DisposableBean被调用");
    } //自定义的初始化函数
    public void myInit() {
    System.out.println("myInit被调用");
    } //自定义的销毁方法
    public void myDestroy() {
    System.out.println("myDestroy被调用");
    } public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
    System.out.println("setApplicationContext被调用");
    }

    }</pre>

    View Code

    定义了后置处理器CusBeanPostProcessor 实现了BeanPostProcessor 接口。

    [[图片上传失败...(image-60f7f6-1535123798917)]](javascript:void(0); "复制代码")

    <pre>package com.demo.model; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; public class CusBeanPostProcessor implements BeanPostProcessor { public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessBeforeInitialization被调用"); return bean;

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

    }</pre>

    [[图片上传失败...(image-877b6a-1535123798917)]](javascript:void(0); "复制代码")

    在xml中配置bean和BeanPostProcessor。

    <pre> <bean id="user" class="com.demo.model.UserBean" destroy-method="myDestroy" init-method="myInit">
    <property name="name" value="abc"></property>
    </bean>
    <bean id="postProcessor" class="com.demo.model.CusBeanPostProcessor" /></pre>

    测试:

    <pre> ApplicationContext context=new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"});
    BeanFactory factory=context;
    UserBean user=(UserBean)context.getBean("user");
    ((ClassPathXmlApplicationContext)context).close();</pre>

    输出结果:
    UserBean类构造方法
    set方法被调用
    BeanNameAware被调用
    BeanFactoryAware被调用
    setApplicationContext被调用
    postProcessBeforeInitialization被调用
    InitializingBean被调用
    myInit被调用
    postProcessAfterInitialization被调用
    DisposableBean被调用
    myDestroy被调用

    image

    相关文章

      网友评论

          本文标题:Spring之Bean的作用域与生命周期

          本文链接:https://www.haomeiwen.com/subject/itcwiftx.html