Spring知識——IOC容器

IOC概述

一、理解:
(1)控制反轉。將生成對象的控制權交IOC容器,由容器生成依賴的對象。調用類只依賴接口,而不依賴具體的實現類,減小了耦合。在運行的時候,才由容器將具體的實例注入到調用類的對象中。
(2)依賴注入,就是向Ioc容器索要bean的過程。getBean是依賴注入的起點。依賴注入的過程是用戶第一次向Ioc容器索要Bean時觸發的。
(3)生成bean的兩種方式java

a、經過反射調用構造函數
b、經過CGLib

二、優勢:
(1)依賴關係的管理被反轉並交給容器,使複雜的依賴關係管理從應用中解放出來。
(2)代碼解耦
三、啓動過程(依賴注入的實現過程):node

a、Resource尋找資源(XML文件形式的beanDefinition)
b、將XML文件載入內存中,解析成org.springframework.beans.factory.config.BeanDefinition對象
c、將org.springframework.beans.factory.config.BeanDefinition對象註冊到HashMap容器中
d、客戶想Ioc容器索要bean,觸發依賴注入

基礎使用

1、首先講解依賴注入的3種方式:
一、set方式注入:
假設有一個SpringAction,類中須要實例化一個SpringDao對象,那麼就能夠定義一個private的SpringDao成員變量,而後建立SpringDao的set方法(這是ioc的注入入口):web

package com.bless.springdemo.action;  
public class SpringAction {  
        //注入對象springDao  
    private SpringDao springDao;  
        //必定要寫被注入對象的set方法  
        public void setSpringDao(SpringDao springDao) {  
        this.springDao = springDao;  
    }  
  
        public void ok(){  
        springDao.ok();  
    }  
}

隨後編寫spring的xml文件,<bean>中的name屬性是class屬性的一個別名,class屬性指類的全名,由於在SpringAction中有一個公共屬性Springdao,因此要在<bean>標籤中建立一個<property>標籤指定SpringDao。<property>標籤中的name就是SpringAction類中的SpringDao屬性名,ref指下面<bean name="springDao"...>,這樣實際上是spring將SpringDaoImpl對象實例化而且調用SpringAction的setSpringDao方法將SpringDao注入。spring

<!--配置bean,配置後該類由spring管理-->  
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">  
        <!--(1)依賴注入,配置當前類中相應的屬性-->  
        <property name="springDao" ref="springDao"></property>  
</bean>  
<bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>

二、構造器注入:
這種方式的注入是指帶有參數的構造函數注入,看下面的例子,我建立了兩個成員變量SpringDao和User,可是並未設置對象的set方法,因此就不能支持Set注入方式,這裏的注入方式是在SpringAction的構造函數中注入,也就是說在建立SpringAction對象時要將SpringDao和User兩個參數值傳進來:編程

public class SpringAction {  
    //注入對象springDao  
    private SpringDao springDao;  
    private User user;  
      
    public SpringAction(SpringDao springDao,User user){  
        this.springDao = springDao;  
        this.user = user;  
        System.out.println("構造方法調用springDao和user");  
    }  
          
        public void save(){  
        user.setName("卡卡");  
        springDao.save(user);  
    }  
}

在XML文件中一樣不用<property>的形式,而是使用<constructor-arg>標籤,ref屬性一樣指向其它<bean>標籤的name屬性:緩存

<!--配置bean,配置後該類由spring管理-->  
    <bean name="springAction" class="com.bless.springdemo.action.SpringAction">  
        <!--(2)建立構造器注入,若是主類有帶參的構造方法則需添加此配置-->  
        <constructor-arg ref="springDao"></constructor-arg>  
        <constructor-arg ref="user"></constructor-arg>  
    </bean>  
    <bean name="springDao" class="com.bless.springdemo.dao.impl.SpringDaoImpl"></bean>  
    <bean name="user" class="com.bless.springdemo.vo.User"></bean>

解決構造方法參數的不肯定性,你可能會遇到構造方法傳入的兩參數都是同類型的,爲了分清哪一個該賦對應值,則須要進行一些小處理:session

下面是設置index,就是參數位置:
<bean name="springAction" class="com.bless.springdemo.action.SpringAction">  
        <constructor-arg index="0" ref="springDao"></constructor-arg>  
        <constructor-arg index="1" ref="user"></constructor-arg>  
</bean>

另外一種是設置參數類型:less

<constructor-arg type="java.lang.String" ref=""/>

三、接口注入:
ClassA依賴於InterfaceB,在運行期, InterfaceB 實例將由容器提供。ssh

public class ClassA {
    private InterfaceB clzB;
    public Object doSomething(InterfaceB b) {
        clzB = b;
        return clzB.doIt();
    }
}
……
}

2、Bean標籤
一、scope屬性:
(1)singleton:單例模式,即該bean對應的類只有一個實例;在spring 中是scope(做用範圍)參數的默認值 ;
(2)prototype:表示每次從容器中取出bean時,都會生成一個新實例;至關於new出來一個對象;
(3)request:基於web,表示每次接受一個HTTP請求時,都會生成一個新實例;
(4)session:表示在每個session中只有一個該對象.
(5)global session
global session做用域相似於標準的HTTP Session做用域,不過它僅僅在基於portlet的web應用中才有意義。Portlet規範定義了全局Session的概念,它被全部構成某個portlet web應用的各類不一樣的portlet所共享。在global session做用域中定義的bean被限定於全局portlet Session的生命週期範圍內。若是你在web中使用global session做用域來標識bean,那麼web會自動當成session類型來使用。
配置實例:
和request配置實例的前提同樣,配置好web啓動文件就能夠以下配置:
<bean id="role" class="spring.chapter2.maryGame.Role" scope="global session"/>
(6)自定義bean裝配做用域:
在spring2.0中做用域是能夠任意擴展的,你能夠自定義做用域,甚至你也能夠從新定義已有的做用域(可是你不能覆蓋singleton和prototype),spring的做用域由接口org.springframework.beans.factory.config.Scope來定義,自定義本身的做用域只要實現該接口便可,下面給個實例:
咱們創建一個線程的scope,該scope在表示一個線程中有效,代碼以下:ide

publicclass MyScope implements Scope { 
      privatefinal ThreadLocal threadScope = new ThreadLocal() {
          protected Object initialValue() {
             returnnew HashMap(); 
           } 
     }; 
     public Object get(String name, ObjectFactory objectFactory) { 
         Map scope = (Map) threadScope.get(); 
         Object object = scope.get(name); 
        if(object==null) { 
           object = objectFactory.getObject(); 
           scope.put(name, object); 
         } 
        return object; 
      } 
     public Object remove(String name) { 
         Map scope = (Map) threadScope.get(); 
        return scope.remove(name); 
      }
      publicvoid registerDestructionCallback(String name, Runnable callback) { 
      }
    public String getConversationId() {
       // TODO Auto-generated method stub
        returnnull;
     } 
           }

源碼解析

1、IOC容器:
一、對於Spring的使用者而言,IOC容器其實是什麼呢?咱們能夠說BeanFactory就是咱們看到的IoC容器,固然了Spring爲咱們準備了許多種IoC容器來使用,好比說ApplicationContext。這樣能夠方便咱們從不一樣的層面,不一樣的資源位置,不一樣的形式的定義信息來創建咱們須要的IoC容器。
在Spring中,最基本的IOC容器接口是BeanFactory - 這個接口爲具體的IOC容器的實現做了最基本的功能規定 - 無論怎麼着,做爲IOC容器,這些接口你必需要知足應用程序的最基本要求,查看BeanFactory的源碼:

public interface BeanFactory {  
  
    //這裏是對FactoryBean的轉義定義,由於若是使用bean的名字檢索FactoryBean獲得的對象是工廠生成的對象,  
    //若是須要獲得工廠自己,須要轉義         
    String FACTORY_BEAN_PREFIX = "&";  
  
  
    //這裏根據bean的名字,在IOC容器中獲得bean實例,這個IOC容器就是一個大的抽象工廠。  
    Object getBean(String name) throws BeansException;  
  
    //這裏根據bean的名字和Class類型來獲得bean實例,和上面的方法不一樣在於它會拋出異常:若是根據名字取得的bean實例的Class類型和須要的不一樣的話。  
    Object getBean(String name, Class requiredType) throws BeansException;  
  
    //這裏提供對bean的檢索,看看是否在IOC容器有這個名字的bean  
    boolean containsBean(String name);  
  
    //這裏根據bean名字獲得bean實例,並同時判斷這個bean是否是單件  
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;  
  
    //這裏對獲得bean實例的Class類型  
    Class getType(String name) throws NoSuchBeanDefinitionException;  
  
    //這裏獲得bean的別名,若是根據別名檢索,那麼其原名也會被檢索出來  
    String[] getAliases(String name);  
  
}

二、容器加載流程解析:
這裏咱們以ClassPathXmlApplicationContext的初始化爲例
(1)首先從容器構造函數入口:

public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
            throws BeansException {

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
//這裏是IoC容器的初始化過程,其初始化過程的大體步驟由AbstractApplicationContext來定義
            refresh();
        }
    }

(2)再看AbstractApplicationContext中refresh函數定義,這個方法包含了整個BeanFactory初始化的過程。這裏使用到模板模式。

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 準備這個上下文來刷新
            prepareRefresh();

            // 告訴子類刷新其beanFactory
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

            // 準備將要在上下文中使用的bean工廠
            prepareBeanFactory(beanFactory);

            try {
                // 容許在上下文子類中對bean工廠進行後處理
                postProcessBeanFactory(beanFactory);

                // 調用 factory processors註冊爲上下文中的bean
                invokeBeanFactoryPostProcessors(beanFactory);

                // 註冊 攔截bean建立的bean處理器
                registerBeanPostProcessors(beanFactory);

                // 初始化此上下文的消息源
                initMessageSource();

                // 初始化此上下文的時間多播器
                initApplicationEventMulticaster();

                // 在特殊上下文子類中初始化其特殊的bean
                onRefresh();

                // 檢查監聽器bean,而且註冊它們
                registerListeners();

                // 初始化全部剩下的(非懶加載)單例
                finishBeanFactoryInitialization(beanFactory);

                // 發佈相應的事件
                finishRefresh();
            }

            catch (BeansException ex) {
                if (logger.isWarnEnabled()) {
                    logger.warn("Exception encountered during context initialization - " +
                            "cancelling refresh attempt: " + ex);
                }

                // 銷燬已經建立的單例,以免資源泄漏
                destroyBeans();

                // 重置active標誌位
                cancelRefresh(ex);

                // 拋出異常給調用者
                throw ex;
            }

            finally {
                // 在Spring的核心中重置常見的自檢緩存,由於咱們可能再也不須要單例對象的元數據了
                resetCommonCaches();
            }
        }
    }

(4)進入obtainFreshBeanFactory()函數,發現調用refreshBeanFactory(),而refreshBeanFactory()裏面調用了loadBeanDefinitions()函數,該函數描述了加載bean定義的過程,最終會調用」具體的解析和註冊過程「。

@Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 爲給定的BeanFactory建立一個新的XmlBeanDefinitionReader
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

        // 使用此上下文的資源加載環境,去配置bean定義閱讀器。
        beanDefinitionReader.setEnvironment(this.getEnvironment());
        beanDefinitionReader.setResourceLoader(this);
        beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

        // 容許子類提供reader的自定義初始化,而後執行實際加載bean定義。
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            // 調用XmlBeanDefinitionReader來載入bean定義信息。
            reader.loadBeanDefinitions(configResources);
        }
        String[] configLocations = getConfigLocations();
        if (configLocations != null) {
            reader.loadBeanDefinitions(configLocations);
        }
}

// XmlBeanDefinitionReader.java
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
        Assert.notNull(encodedResource, "EncodedResource must not be null");
        if (logger.isInfoEnabled()) {
            logger.info("Loading XML bean definitions from " + encodedResource.getResource());
        }

        Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet<EncodedResource>(4);
            this.resourcesCurrentlyBeingLoaded.set(currentResources);
        }
        if (!currentResources.add(encodedResource)) {
            throw new BeanDefinitionStoreException(
                    "Detected cyclic loading of " + encodedResource + " - check your import definitions!");
        }
        try {
            InputStream inputStream = encodedResource.getResource().getInputStream();
            try {
                InputSource inputSource = new InputSource(inputStream);
                if (encodedResource.getEncoding() != null) {
                    inputSource.setEncoding(encodedResource.getEncoding());
                }
                //這裏是具體的解析和註冊過程  
                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
            }
            finally {
                inputStream.close();
            }
        }
        catch (IOException ex) {
            throw new BeanDefinitionStoreException(
                    "IOException parsing XML document from " + encodedResource.getResource(), ex);
        }
        finally {
            currentResources.remove(encodedResource);
            if (currentResources.isEmpty()) {
                this.resourcesCurrentlyBeingLoaded.remove();
            }
        }
    }


protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
            throws BeanDefinitionStoreException {
        try {
            //經過解析獲得DOM,而後完成bean在IOC容器中的註冊
            Document doc = doLoadDocument(inputSource, resource);
            return registerBeanDefinitions(doc, resource);
        }
    ....

咱們看到先把定義文件解析爲DOM對象,而後進行具體的註冊過程:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 具體的註冊過程,首先獲得XmlBeanDefinitionReader,來處理xml的bean定義文件
        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
        int countBefore = getRegistry().getBeanDefinitionCount();
        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
        return getRegistry().getBeanDefinitionCount() - countBefore;
    }

(5)在BeanDefinitionDocumentReader中完成bean定義文件的解析和IOC容器bean的初始化。

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
        this.readerContext = readerContext;
        logger.debug("Loading bean definitions");
        Element root = doc.getDocumentElement();
        doRegisterBeanDefinitions(root);
}

protected void doRegisterBeanDefinitions(Element root) 
        BeanDefinitionParserDelegate parent = this.delegate;
        this.delegate = createDelegate(getReaderContext(), root, parent);

        if (this.delegate.isDefaultNamespace(root)) {
            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
            if (StringUtils.hasText(profileSpec)) {
                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
                    return;
                }
            }
        }

        preProcessXml(root);
        parseBeanDefinitions(root, this.delegate);
        postProcessXml(root);

        this.delegate = parent;
}

// 對配置文件(xml文件)進行解析
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
        if (delegate.isDefaultNamespace(root)) {
            NodeList nl = root.getChildNodes();
            for (int i = 0; i < nl.getLength(); i++) {
                Node node = nl.item(i);
                if (node instanceof Element) {
                    Element ele = (Element) node;
                    if (delegate.isDefaultNamespace(ele)) {
                    //這裏是解析過程的調用,對缺省的元素進行分析好比bean元素 
                        parseDefaultElement(ele, delegate);
                    }
                    else {
                        delegate.parseCustomElement(ele);
                    }
                }
            }
        }
        else {
            delegate.parseCustomElement(root);
        }
}

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
            importBeanDefinitionResource(ele);
        }
        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
            processAliasRegistration(ele);
        }
        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
            //這裏對咱們最熟悉的bean元素進行處理  
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
//委託給BeanDefinitionParserDelegate來完成對bean元素的處理,這個類包含了具體的bean解析的過程。  
        // 把解析bean文件獲得的信息放到BeanDefinition裏,他是bean信息的主要載體,也是IOC容器的管理對象。
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if (bdHolder != null) {
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
            try {
                // 這裏是向IOC容器註冊,其實是放到IOC容器的一個map裏
                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
            }
            catch (BeanDefinitionStoreException ex) {
                getReaderContext().error("Failed to register bean definition with name '" +
                        bdHolder.getBeanName() + "'", ele, ex);
            }
            // 這裏向IOC容器發送事件,表示解析和註冊完成
            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }
    }

(6)咱們看到在parseBeanDefinition中對具體bean元素的解析式交給BeanDefinitionParserDelegate來完成的,下面咱們看看解析完的bean是怎樣在IOC容器中註冊的:
在BeanDefinitionReaderUtils調用的是:

public static void registerBeanDefinition(
            BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
            throws BeanDefinitionStoreException {

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        //這是調用IOC來註冊的bean的過程,須要獲得BeanDefinition
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // 別名也是能夠經過IOC容器和bean聯繫起來的進行註冊
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
}

(7)咱們看看XmlBeanFactory中的註冊實現:

//---------------------------------------------------------------------  
// 這裏是IOC容器對BeanDefinitionRegistry接口的實現  
//---------------------------------------------------------------------  
  
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  
        throws BeanDefinitionStoreException {  
  
    .....//這裏省略了對BeanDefinition的驗證過程  
    //先看看在容器裏是否是已經有了同名的bean,若是有拋出異常。  
    Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
    if (oldBeanDefinition != null) {  
        if (!this.allowBeanDefinitionOverriding) {  
        ...........  
    }  
    else {  
        //把bean的名字加到IOC容器中去  
        this.beanDefinitionNames.add(beanName);  
    }  
    //這裏把bean的名字和Bean定義聯繫起來放到一個HashMap中去,IOC容器經過這個Map來維護容器裏的Bean定義信息。  
    this.beanDefinitionMap.put(beanName, beanDefinition);  
    removeSingleton(beanName);  
}

這樣就完成了Bean定義在IOC容器中的註冊,就可被IOC容器進行管理和使用了。

總結IOC容器初始化流程:

一、初始化的入口在容器實現中的refresh()調用來完成
二、將bean定義信息載入IOC容器。使用的方法是loadBeanDefinition,其中的大體過程以下:
(1)經過ResourceLoader來完成資源文件位置的定位,DefaultResourceLoader是默認的實現,同時上下文自己就給出了ResourceLoader的實現,能夠從類路徑,文件系統, URL等方式來定爲資源位置。若是是XmlBeanFactory做爲IOC容器,那麼須要爲它指定bean定義的資源,也就是說bean定義文件時經過抽象成Resource來被IOC容器處理的
(2)容器經過BeanDefinitionReader來完成定義信息的解析和Bean信息的註冊,每每使用的是XmlBeanDefinitionReader來解析bean的xml定義文件 - 實際的處理過程是委託給BeanDefinitionParserDelegate來完成的,從而獲得bean的定義信息,這些信息在Spring中使用BeanDefinition對象來表示 - 這個名字可讓咱們想到loadBeanDefinition,RegisterBeanDefinition這些相關的方法 - 他們都是爲處理BeanDefinitin服務的,IoC容器解析獲得BeanDefinition之後,須要把它在IOC容器中註冊,這由IOC實現 BeanDefinitionRegistry接口來實現。註冊過程就是在IOC容器內部維護的一個HashMap來保存獲得的 BeanDefinition的過程。這個HashMap是IoC容器持有bean信息的場所,之後對bean的操做都是圍繞這個HashMap來實現的。
(3)而後咱們就能夠經過BeanFactory和ApplicationContext來享受到Spring IOC的服務了.

Beanfactory 和Factory bean

一、BeanFactory 指的是IOC容器的編程抽象,好比ApplicationContext, XmlBeanFactory等,這些都是IOC容器的具體表現,須要使用什麼樣的容器由客戶決定但Spring爲咱們提供了豐富的選擇。
二、Factory bean 是一個能夠在IOC容器中被管理的一個bean,是對各類處理過程和資源使用的抽象,Factory bean在須要時產生另外一個對象,而不返回FactoryBean本省,咱們能夠把它當作是一個抽象工廠,對它的調用返回的是工廠生產的產品。全部的 Factory bean都實現特殊的org.springframework.beans.factory.FactoryBean接口,當使用容器中factory bean的時候,該容器不會返回factory bean自己,而是返回其生成的對象。Spring包括了大部分的通用資源和服務訪問抽象的Factory bean的實現,其中包括:
對JNDI查詢的處理,對代理對象的處理,對事務性代理的處理,對RMI代理的處理等,這些咱們均可以當作是具體的工廠,當作是SPRING爲咱們創建好的工廠。也就是說Spring經過使用抽象工廠模式爲咱們準備了一系列工廠來生產一些特定的對象,免除咱們手工重複的工做,咱們要使用時只須要在IOC容器裏配置好就能很方便的使用了。

IOC高級特性

1、lazy-init延遲加載
一、執行原理:
lazy-init屬性:爲true的話,在Ioc容器初始化過程當中,會對BeanDefinitionMap中全部的Bean進行依賴注入,這樣在初始化過程結束後,容器執行getBean獲得的就是已經準備好的Bean,不須要進行依賴注入。
二、優勢:當應用第一次向容器索取所需的Bean時,容器再也不須要對Bean進行初始化,直接從已經完成實例化的Bean中取出須要的bean,這樣就提升了第一次獲取Bean的性能。

2、BeanPostProcessor後置處理器:
一、BeanPostProcessor後置處理器是Spring IoC容器常用到的一個特性,這個Bean後置處理器是一個監聽器,能夠監聽容器觸發的Bean聲明週期事件。後置處理器想容器註冊之後,容器中管理的Bean就具有了接收IoC容器事件回調的能力。
二、BeanPostProcessor的使用很是簡單,只須要提供一個實現接口BeanPostProcessor的實現類,而後在Bean的配置文件中設置便可。
三、API解釋:

public interface BeanPostProcessor {  
  
    /** 
     * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean 
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet} 
     * or a custom init-method). The bean will already be populated with property values.    
     */  
    //實例化、依賴注入完畢,在調用顯示的初始化以前完成一些定製的初始化任務  
    Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;  
  
      
    /** 
     * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean 
     * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}   
     * or a custom init-method). The bean will already be populated with property values.       
     */  
    //實例化、依賴注入、初始化完畢時執行  
    Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;  
  
}

3、自動裝配:
一、概念:無須在Spring配置文件中描述javaBean之間的依賴關係(如配置<property>、<constructor-arg>)。IOC容器會自動創建java Bean之間的關聯關係(經過autowire)。
二、在Spring中,支持 5 自動裝配模式。
(1)no – 缺省狀況下,自動配置是經過「ref」屬性手動設定
(2)byName – 根據屬性名稱自動裝配。若是一個bean的名稱和其餘bean屬性的名稱是同樣的,將會自裝配它。
(3)byType – 按數據類型自動裝配。若是一個bean的數據類型是用其它bean屬性的數據類型,兼容並自動裝配它。
(4)constructor – 在構造函數參數的byType方式。

Spring Bean生命週期

clipboard.png
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的生命週期結束

參考:
http://www.iteye.com/topic/86339
http://blessht.iteye.com/blog...
https://blog.csdn.net/masterm...
https://blog.csdn.net/sugar_r...

相關文章
相關標籤/搜索