1. 程式人生 > >Spring之Bean的作用域與生命周期

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

src efi lin 控制 初始化 troy [] 分享 isp

在前面博客中提到容器啟動獲得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實例。只在基於webSpring ApplicationContext中可用

會話(session

限定一個Bean的作用域為HTTPsession的生命周期。同樣,只有基於web

Spring ApplicationContext才能使用

全局會話(global session

限定一個Bean的作用域為全局HTTPSession的生命周期。通常用於門戶網站場景,同樣,只有基於webSpring ApplicationContext可用

我們可以以XMLInstance類為基礎演示一下singleton和prototype作用域。
這裏使用通過BeanFactory的getBean方法獲取兩次bean對象。

        XMLInstance instance=(XMLInstance)factory.getBean("xmlinstance");
        instance.setName(
"123"); instance.Breath(); instance=(XMLInstance)factory.getBean("xmlinstance"); instance.Breath();

如果我們采用bean默認的作用域singleton,如下配置,則兩個getbean獲取的對象是一致的。

  <bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="singleton">
      <property name="air" ref="CleanAir"></property>
      <property name="name" value="abc"></property>
  </bean>
輸出結果:
Name:123;Air:CleanAir
Name:123;Air:CleanAir

如果我們采用bean默認的作用域singleton,如下配置,則兩個getbean獲取的對象是不一致的。

  <bean id="xmlinstance" class="com.demo.model.XMLInstance" scope="prototype">
      <property name="air" ref="CleanAir"></property>
      <property name="name" value="abc"></property>
  </bean>
輸出結果:
Name:123;Air:CleanAir
Name:abc;Air:CleanAir

二、Bean的生命周期
前面章節介紹了bean容器以及bean的配置與註入,本章節學習bean的生命周期,了解bean是怎麽來的又是怎麽沒的。

技術分享圖片

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接口。 技術分享圖片
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被調用");
    }

}
View Code

定義了後置處理器CusBeanPostProcessor 實現了BeanPostProcessor 接口。

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

}

在xml中配置bean和BeanPostProcessor。

  <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" />

測試:

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

輸出結果:
UserBean類構造方法
set方法被調用
BeanNameAware被調用
BeanFactoryAware被調用
setApplicationContext被調用
postProcessBeforeInitialization被調用
InitializingBean被調用
myInit被調用
postProcessAfterInitialization被調用
DisposableBean被調用
myDestroy被調用

技術分享圖片

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