国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Spring知識(shí)——IOC容器

yexiaobai / 1612人閱讀

摘要:生成的兩種方式通過(guò)反射調(diào)用構(gòu)造函數(shù)通過(guò)優(yōu)點(diǎn)依賴關(guān)系的管理被反轉(zhuǎn)并交給容器,使復(fù)雜的依賴關(guān)系管理從應(yīng)用中解放出來(lái)。

IOC概述

1、理解:
(1)控制反轉(zhuǎn)。將生成對(duì)象的控制權(quán)交IOC容器,由容器生成依賴的對(duì)象。調(diào)用類只依賴接口,而不依賴具體的實(shí)現(xiàn)類,減少了耦合。在運(yùn)行的時(shí)候,才由容器將具體的實(shí)例注入到調(diào)用類的對(duì)象中。
(2)依賴注入,就是向Ioc容器索要bean的過(guò)程。getBean是依賴注入的起點(diǎn)。依賴注入的過(guò)程是用戶第一次向Ioc容器索要Bean時(shí)觸發(fā)的。
(3)生成bean的兩種方式

a、通過(guò)反射調(diào)用構(gòu)造函數(shù)
b、通過(guò)CGLib

2、優(yōu)點(diǎn):
(1)依賴關(guān)系的管理被反轉(zhuǎn)并交給容器,使復(fù)雜的依賴關(guān)系管理從應(yīng)用中解放出來(lái)。
(2)代碼解耦
3、啟動(dòng)過(guò)程(依賴注入的實(shí)現(xiàn)過(guò)程):

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

基礎(chǔ)使用

一、首先講解依賴注入的3種方式:
1、set方式注入:
假設(shè)有一個(gè)SpringAction,類中需要實(shí)例化一個(gè)SpringDao對(duì)象,那么就可以定義一個(gè)private的SpringDao成員變量,然后創(chuàng)建SpringDao的set方法(這是ioc的注入入口):

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

隨后編寫spring的xml文件,中的name屬性是class屬性的一個(gè)別名,class屬性指類的全名,因?yàn)樵赟pringAction中有一個(gè)公共屬性Springdao,所以要在標(biāo)簽中創(chuàng)建一個(gè)標(biāo)簽指定SpringDao。標(biāo)簽中的name就是SpringAction類中的SpringDao屬性名,ref指下面,這樣其實(shí)是spring將SpringDaoImpl對(duì)象實(shí)例化并且調(diào)用SpringAction的setSpringDao方法將SpringDao注入。

  
  
          
          
  

2、構(gòu)造器注入:
這種方式的注入是指帶有參數(shù)的構(gòu)造函數(shù)注入,看下面的例子,我創(chuàng)建了兩個(gè)成員變量SpringDao和User,但是并未設(shè)置對(duì)象的set方法,所以就不能支持Set注入方式,這里的注入方式是在SpringAction的構(gòu)造函數(shù)中注入,也就是說(shuō)在創(chuàng)建SpringAction對(duì)象時(shí)要將SpringDao和User兩個(gè)參數(shù)值傳進(jìn)來(lái):

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

在XML文件中同樣不用的形式,而是使用標(biāo)簽,ref屬性同樣指向其它標(biāo)簽的name屬性:

  
      
          
          
          
      
      
     

解決構(gòu)造方法參數(shù)的不確定性,你可能會(huì)遇到構(gòu)造方法傳入的兩參數(shù)都是同類型的,為了分清哪個(gè)該賦對(duì)應(yīng)值,則需要進(jìn)行一些小處理:

下面是設(shè)置index,就是參數(shù)位置:
  
          
          
  

另一種是設(shè)置參數(shù)類型:

 

3、接口注入:
ClassA依賴于InterfaceB,在運(yùn)行期, InterfaceB 實(shí)例將由容器提供。

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

二、Bean標(biāo)簽
1、scope屬性:
(1)singleton:?jiǎn)卫J剑丛揵ean對(duì)應(yīng)的類只有一個(gè)實(shí)例;在spring 中是scope(作用范圍)參數(shù)的默認(rèn)值 ;
(2)prototype:表示每次從容器中取出bean時(shí),都會(huì)生成一個(gè)新實(shí)例;相當(dāng)于new出來(lái)一個(gè)對(duì)象;
(3)request:基于web,表示每次接受一個(gè)HTTP請(qǐng)求時(shí),都會(huì)生成一個(gè)新實(shí)例;
(4)session:表示在每一個(gè)session中只有一個(gè)該對(duì)象.
(5)global session
global session作用域類似于標(biāo)準(zhǔn)的HTTP Session作用域,不過(guò)它僅僅在基于portlet的web應(yīng)用中才有意義。Portlet規(guī)范定義了全局Session的概念,它被所有構(gòu)成某個(gè)portlet web應(yīng)用的各種不同的portlet所共享。在global session作用域中定義的bean被限定于全局portlet Session的生命周期范圍內(nèi)。如果你在web中使用global session作用域來(lái)標(biāo)識(shí)bean,那么web會(huì)自動(dòng)當(dāng)成session類型來(lái)使用。
配置實(shí)例:
和request配置實(shí)例的前提一樣,配置好web啟動(dòng)文件就可以如下配置:

(6)自定義bean裝配作用域:
在spring2.0中作用域是可以任意擴(kuò)展的,你可以自定義作用域,甚至你也可以重新定義已有的作用域(但是你不能覆蓋singleton和prototype),spring的作用域由接口org.springframework.beans.factory.config.Scope來(lái)定義,自定義自己的作用域只要實(shí)現(xiàn)該接口即可,下面給個(gè)實(shí)例:
我們建立一個(gè)線程的scope,該scope在表示一個(gè)線程中有效,代碼如下:

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;
     } 
           }
源碼解析

一、IOC容器:
1、對(duì)于Spring的使用者而言,IOC容器實(shí)際上是什么呢?我們可以說(shuō)BeanFactory就是我們看到的IoC容器,當(dāng)然了Spring為我們準(zhǔn)備了許多種IoC容器來(lái)使用,比如說(shuō)ApplicationContext。這樣可以方便我們從不同的層面,不同的資源位置,不同的形式的定義信息來(lái)建立我們需要的IoC容器。
在Spring中,最基本的IOC容器接口是BeanFactory - 這個(gè)接口為具體的IOC容器的實(shí)現(xiàn)作了最基本的功能規(guī)定 - 不管怎么著,作為IOC容器,這些接口你必須要滿足應(yīng)用程序的最基本要求,查看BeanFactory的源碼:

public interface BeanFactory {  
  
    //這里是對(duì)FactoryBean的轉(zhuǎn)義定義,因?yàn)槿绻褂胋ean的名字檢索FactoryBean得到的對(duì)象是工廠生成的對(duì)象,  
    //如果需要得到工廠本身,需要轉(zhuǎn)義         
    String FACTORY_BEAN_PREFIX = "&";  
  
  
    //這里根據(jù)bean的名字,在IOC容器中得到bean實(shí)例,這個(gè)IOC容器就是一個(gè)大的抽象工廠。  
    Object getBean(String name) throws BeansException;  
  
    //這里根據(jù)bean的名字和Class類型來(lái)得到bean實(shí)例,和上面的方法不同在于它會(huì)拋出異常:如果根據(jù)名字取得的bean實(shí)例的Class類型和需要的不同的話。  
    Object getBean(String name, Class requiredType) throws BeansException;  
  
    //這里提供對(duì)bean的檢索,看看是否在IOC容器有這個(gè)名字的bean  
    boolean containsBean(String name);  
  
    //這里根據(jù)bean名字得到bean實(shí)例,并同時(shí)判斷這個(gè)bean是不是單件  
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;  
  
    //這里對(duì)得到bean實(shí)例的Class類型  
    Class getType(String name) throws NoSuchBeanDefinitionException;  
  
    //這里得到bean的別名,如果根據(jù)別名檢索,那么其原名也會(huì)被檢索出來(lái)  
    String[] getAliases(String name);  
  
}  

2、容器加載流程解析:
這里我們以ClassPathXmlApplicationContext的初始化為例
(1)首先從容器構(gòu)造函數(shù)入口:

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

        super(parent);
        setConfigLocations(configLocations);
        if (refresh) {
//這里是IoC容器的初始化過(guò)程,其初始化過(guò)程的大致步驟由AbstractApplicationContext來(lái)定義
            refresh();
        }
    }

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

@Override
    public void refresh() throws BeansException, IllegalStateException {
        synchronized (this.startupShutdownMonitor) {
            // 準(zhǔn)備這個(gè)上下文來(lái)刷新
            prepareRefresh();

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

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

            try {
                // 允許在上下文子類中對(duì)bean工廠進(jìn)行后處理
                postProcessBeanFactory(beanFactory);

                // 調(diào)用 factory processors注冊(cè)為上下文中的bean
                invokeBeanFactoryPostProcessors(beanFactory);

                // 注冊(cè) 攔截bean創(chuàng)建的bean處理器
                registerBeanPostProcessors(beanFactory);

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

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

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

                // 檢查監(jiān)聽(tīng)器bean,并且注冊(cè)它們
                registerListeners();

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

                // 發(fā)布相應(yīng)的事件
                finishRefresh();
            }

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

                // 銷毀已經(jīng)創(chuàng)建的單例,以避免資源泄漏
                destroyBeans();

                // 重置active標(biāo)志位
                cancelRefresh(ex);

                // 拋出異常給調(diào)用者
                throw ex;
            }

            finally {
                // 在Spring的核心中重置常見(jiàn)的自檢緩存,因?yàn)槲覀兛赡懿辉傩枰獑卫龑?duì)象的元數(shù)據(jù)了
                resetCommonCaches();
            }
        }
    }

(4)進(jìn)入obtainFreshBeanFactory()函數(shù),發(fā)現(xiàn)調(diào)用refreshBeanFactory(),而refreshBeanFactory()里面調(diào)用了loadBeanDefinitions()函數(shù),該函數(shù)描述了加載bean定義的過(guò)程,最終會(huì)調(diào)用”具體的解析和注冊(cè)過(guò)程“。

@Override
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
        // 為給定的BeanFactory創(chuàng)建一個(gè)新的XmlBeanDefinitionReader
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

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

        // 允許子類提供reader的自定義初始化,然后執(zhí)行實(shí)際加載bean定義。
        initBeanDefinitionReader(beanDefinitionReader);
        loadBeanDefinitions(beanDefinitionReader);
    }

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
        Resource[] configResources = getConfigResources();
        if (configResources != null) {
            // 調(diào)用XmlBeanDefinitionReader來(lái)載入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 currentResources = this.resourcesCurrentlyBeingLoaded.get();
        if (currentResources == null) {
            currentResources = new HashSet(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());
                }
                //這里是具體的解析和注冊(cè)過(guò)程  
                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 {
            //通過(guò)解析得到DOM,然后完成bean在IOC容器中的注冊(cè)
            Document doc = doLoadDocument(inputSource, resource);
            return registerBeanDefinitions(doc, resource);
        }
    ....

我們看到先把定義文件解析為DOM對(duì)象,然后進(jìn)行具體的注冊(cè)過(guò)程:

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 具體的注冊(cè)過(guò)程,首先得到XmlBeanDefinitionReader,來(lái)處理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;
}

// 對(duì)配置文件(xml文件)進(jìn)行解析
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)) {
                    //這里是解析過(guò)程的調(diào)用,對(duì)缺省的元素進(jìn)行分析比如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)) {
            //這里對(duì)我們最熟悉的bean元素進(jìn)行處理  
            processBeanDefinition(ele, delegate);
        }
        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
            // recurse
            doRegisterBeanDefinitions(ele);
        }
    }

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

(6)我們看到在parseBeanDefinition中對(duì)具體bean元素的解析式交給BeanDefinitionParserDelegate來(lái)完成的,下面我們看看解析完的bean是怎樣在IOC容器中注冊(cè)的:
在BeanDefinitionReaderUtils調(diào)用的是:

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

        // Register bean definition under primary name.
        String beanName = definitionHolder.getBeanName();
        //這是調(diào)用IOC來(lái)注冊(cè)的bean的過(guò)程,需要得到BeanDefinition
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

        // 別名也是可以通過(guò)IOC容器和bean聯(lián)系起來(lái)的進(jìn)行注冊(cè)
        String[] aliases = definitionHolder.getAliases();
        if (aliases != null) {
            for (String alias : aliases) {
                registry.registerAlias(beanName, alias);
            }
        }
}

(7)我們看看XmlBeanFactory中的注冊(cè)實(shí)現(xiàn):

//---------------------------------------------------------------------  
// 這里是IOC容器對(duì)BeanDefinitionRegistry接口的實(shí)現(xiàn)  
//---------------------------------------------------------------------  
  
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  
        throws BeanDefinitionStoreException {  
  
    .....//這里省略了對(duì)BeanDefinition的驗(yàn)證過(guò)程  
    //先看看在容器里是不是已經(jīng)有了同名的bean,如果有拋出異常。  
    Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
    if (oldBeanDefinition != null) {  
        if (!this.allowBeanDefinitionOverriding) {  
        ...........  
    }  
    else {  
        //把bean的名字加到IOC容器中去  
        this.beanDefinitionNames.add(beanName);  
    }  
    //這里把bean的名字和Bean定義聯(lián)系起來(lái)放到一個(gè)HashMap中去,IOC容器通過(guò)這個(gè)Map來(lái)維護(hù)容器里的Bean定義信息。  
    this.beanDefinitionMap.put(beanName, beanDefinition);  
    removeSingleton(beanName);  
} 

這樣就完成了Bean定義在IOC容器中的注冊(cè),就可被IOC容器進(jìn)行管理和使用了。

總結(jié)IOC容器初始化流程:

1、初始化的入口在容器實(shí)現(xiàn)中的refresh()調(diào)用來(lái)完成
2、將bean定義信息載入IOC容器。使用的方法是loadBeanDefinition,其中的大致過(guò)程如下:
(1)通過(guò)ResourceLoader來(lái)完成資源文件位置的定位,DefaultResourceLoader是默認(rèn)的實(shí)現(xiàn),同時(shí)上下文本身就給出了ResourceLoader的實(shí)現(xiàn),可以從類路徑,文件系統(tǒng), URL等方式來(lái)定為資源位置。如果是XmlBeanFactory作為IOC容器,那么需要為它指定bean定義的資源,也就是說(shuō)bean定義文件時(shí)通過(guò)抽象成Resource來(lái)被IOC容器處理的
(2)容器通過(guò)BeanDefinitionReader來(lái)完成定義信息的解析和Bean信息的注冊(cè),往往使用的是XmlBeanDefinitionReader來(lái)解析bean的xml定義文件 - 實(shí)際的處理過(guò)程是委托給BeanDefinitionParserDelegate來(lái)完成的,從而得到bean的定義信息,這些信息在Spring中使用BeanDefinition對(duì)象來(lái)表示 - 這個(gè)名字可以讓我們想到loadBeanDefinition,RegisterBeanDefinition這些相關(guān)的方法 - 他們都是為處理BeanDefinitin服務(wù)的,IoC容器解析得到BeanDefinition以后,需要把它在IOC容器中注冊(cè),這由IOC實(shí)現(xiàn) BeanDefinitionRegistry接口來(lái)實(shí)現(xiàn)。注冊(cè)過(guò)程就是在IOC容器內(nèi)部維護(hù)的一個(gè)HashMap來(lái)保存得到的 BeanDefinition的過(guò)程。這個(gè)HashMap是IoC容器持有bean信息的場(chǎng)所,以后對(duì)bean的操作都是圍繞這個(gè)HashMap來(lái)實(shí)現(xiàn)的。
(3)然后我們就可以通過(guò)BeanFactory和ApplicationContext來(lái)享受到Spring IOC的服務(wù)了.

Beanfactory 和Factory bean

1、BeanFactory 指的是IOC容器的編程抽象,比如ApplicationContext, XmlBeanFactory等,這些都是IOC容器的具體表現(xiàn),需要使用什么樣的容器由客戶決定但Spring為我們提供了豐富的選擇。
2、Factory bean 是一個(gè)可以在IOC容器中被管理的一個(gè)bean,是對(duì)各種處理過(guò)程和資源使用的抽象,Factory bean在需要時(shí)產(chǎn)生另一個(gè)對(duì)象,而不返回FactoryBean本省,我們可以把它看成是一個(gè)抽象工廠,對(duì)它的調(diào)用返回的是工廠生產(chǎn)的產(chǎn)品。所有的 Factory bean都實(shí)現(xiàn)特殊的org.springframework.beans.factory.FactoryBean接口,當(dāng)使用容器中factory bean的時(shí)候,該容器不會(huì)返回factory bean本身,而是返回其生成的對(duì)象。Spring包括了大部分的通用資源和服務(wù)訪問(wèn)抽象的Factory bean的實(shí)現(xiàn),其中包括:
對(duì)JNDI查詢的處理,對(duì)代理對(duì)象的處理,對(duì)事務(wù)性代理的處理,對(duì)RMI代理的處理等,這些我們都可以看成是具體的工廠,看成是SPRING為我們建立好的工廠。也就是說(shuō)Spring通過(guò)使用抽象工廠模式為我們準(zhǔn)備了一系列工廠來(lái)生產(chǎn)一些特定的對(duì)象,免除我們手工重復(fù)的工作,我們要使用時(shí)只需要在IOC容器里配置好就能很方便的使用了。

IOC高級(jí)特性

一、lazy-init延遲加載
1、執(zhí)行原理:
lazy-init屬性:為true的話,在Ioc容器初始化過(guò)程中,會(huì)對(duì)BeanDefinitionMap中所有的Bean進(jìn)行依賴注入,這樣在初始化過(guò)程結(jié)束后,容器執(zhí)行g(shù)etBean得到的就是已經(jīng)準(zhǔn)備好的Bean,不需要進(jìn)行依賴注入。
2、優(yōu)點(diǎn):當(dāng)應(yīng)用第一次向容器索取所需的Bean時(shí),容器不再需要對(duì)Bean進(jìn)行初始化,直接從已經(jīng)完成實(shí)例化的Bean中取出需要的bean,這樣就提高了第一次獲取Bean的性能。

二、BeanPostProcessor后置處理器:
1、BeanPostProcessor后置處理器是Spring IoC容器經(jīng)常使用到的一個(gè)特性,這個(gè)Bean后置處理器是一個(gè)監(jiān)聽(tīng)器,可以監(jiān)聽(tīng)容器觸發(fā)的Bean聲明周期事件。后置處理器想容器注冊(cè)以后,容器中管理的Bean就具備了接收IoC容器事件回調(diào)的能力。
2、BeanPostProcessor的使用非常簡(jiǎn)單,只需要提供一個(gè)實(shí)現(xiàn)接口BeanPostProcessor的實(shí)現(xiàn)類,然后在Bean的配置文件中設(shè)置即可。
3、API解釋:

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

三、自動(dòng)裝配:
1、概念:無(wú)須在Spring配置文件中描述javaBean之間的依賴關(guān)系(如配置)。IOC容器會(huì)自動(dòng)建立java Bean之間的關(guān)聯(lián)關(guān)系(通過(guò)autowire)。
2、在Spring中,支持 5 自動(dòng)裝配模式。
(1)no – 缺省情況下,自動(dòng)配置是通過(guò)“ref”屬性手動(dòng)設(shè)定
(2)byName – 根據(jù)屬性名稱自動(dòng)裝配。如果一個(gè)bean的名稱和其他bean屬性的名稱是一樣的,將會(huì)自裝配它。
(3)byType – 按數(shù)據(jù)類型自動(dòng)裝配。如果一個(gè)bean的數(shù)據(jù)類型是用其它bean屬性的數(shù)據(jù)類型,兼容并自動(dòng)裝配它。
(4)constructor – 在構(gòu)造函數(shù)參數(shù)的byType方式。

Spring Bean生命周期


ApplicationContext容器中,Bean的生命周期流程如上圖所示,流程大致如下:

1.首先容器啟動(dòng)后,會(huì)對(duì)scope為singleton且非懶加載的bean進(jìn)行實(shí)例化,

2.按照Bean定義信息配置信息,注入所有的屬性,

3.如果Bean實(shí)現(xiàn)了BeanNameAware接口,會(huì)回調(diào)該接口的setBeanName()方法,傳入該Bean的id,此時(shí)該Bean就獲得了自己在配置文件中的id,

4.如果Bean實(shí)現(xiàn)了BeanFactoryAware接口,會(huì)回調(diào)該接口的setBeanFactory()方法,傳入該Bean的BeanFactory,這樣該Bean就獲得了自己所在的BeanFactory,

5.如果Bean實(shí)現(xiàn)了ApplicationContextAware接口,會(huì)回調(diào)該接口的setApplicationContext()方法,傳入該Bean的ApplicationContext,這樣該Bean就獲得了自己所在的ApplicationContext,

6.如果有Bean實(shí)現(xiàn)了BeanPostProcessor接口,則會(huì)回調(diào)該接口的postProcessBeforeInitialzation()方法,

7.如果Bean實(shí)現(xiàn)了InitializingBean接口,則會(huì)回調(diào)該接口的afterPropertiesSet()方法,

8.如果Bean配置了init-method方法,則會(huì)執(zhí)行init-method配置的方法,

9.如果有Bean實(shí)現(xiàn)了BeanPostProcessor接口,則會(huì)回調(diào)該接口的postProcessAfterInitialization()方法,

10.經(jīng)過(guò)流程9之后,就可以正式使用該Bean了,對(duì)于scope為singleton的Bean,Spring的ioc容器中會(huì)緩存一份該bean的實(shí)例,而對(duì)于scope為prototype的Bean,每次被調(diào)用都會(huì)new一個(gè)新的對(duì)象,期生命周期就交給調(diào)用方管理了,不再是Spring容器進(jìn)行管理了

11.容器關(guān)閉后,如果Bean實(shí)現(xiàn)了DisposableBean接口,則會(huì)回調(diào)該接口的destroy()方法,

12.如果Bean配置了destroy-method方法,則會(huì)執(zhí)行destroy-method配置的方法,至此,整個(gè)Bean的生命周期結(jié)束

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

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/69181.html

相關(guān)文章

  • Spring IOC知識(shí)點(diǎn)一網(wǎng)打盡!

    摘要:使用的好處知乎的回答不用自己組裝,拿來(lái)就用。統(tǒng)一配置,便于修改。 前言 只有光頭才能變強(qiáng) 回顧前面: 給女朋友講解什么是代理模式 包裝模式就是這么簡(jiǎn)單啦 單例模式你會(huì)幾種寫法? 工廠模式理解了沒(méi)有? 在刷Spring書籍的時(shí)候花了點(diǎn)時(shí)間去學(xué)習(xí)了單例模式和工廠模式,總的來(lái)說(shuō)還是非常值得的! 本來(lái)想的是刷完《Spring 實(shí)戰(zhàn) (第4版)》和《精通Spring4.x 企業(yè)應(yīng)用開發(fā)實(shí)戰(zhàn)》...

    djfml 評(píng)論0 收藏0
  • Spring IOC 容器源碼分析 - 余下的初始化工作

    摘要:簡(jiǎn)介本篇文章是容器源碼分析系列文章的最后一篇文章,本篇文章所分析的對(duì)象是方法,該方法用于對(duì)已完成屬性填充的做最后的初始化工作。后置處理器是拓展點(diǎn)之一,通過(guò)實(shí)現(xiàn)后置處理器接口,我們就可以插手的初始化過(guò)程。 1. 簡(jiǎn)介 本篇文章是Spring IOC 容器源碼分析系列文章的最后一篇文章,本篇文章所分析的對(duì)象是 initializeBean 方法,該方法用于對(duì)已完成屬性填充的 bean 做最...

    Alfred 評(píng)論0 收藏0
  • Spring IOC 容器源碼分析系列文章導(dǎo)讀

    摘要:本文是容器源碼分析系列文章的第一篇文章,將會(huì)著重介紹的一些使用方法和特性,為后續(xù)的源碼分析文章做鋪墊。我們可以通過(guò)這兩個(gè)別名獲取到這個(gè)實(shí)例,比如下面的測(cè)試代碼測(cè)試結(jié)果如下本小節(jié),我們來(lái)了解一下這個(gè)特性。 1. 簡(jiǎn)介 Spring 是一個(gè)輕量級(jí)的企業(yè)級(jí)應(yīng)用開發(fā)框架,于 2004 年由 Rod Johnson 發(fā)布了 1.0 版本。經(jīng)過(guò)十幾年的迭代,現(xiàn)在的 Spring 框架已經(jīng)非常成熟了...

    NSFish 評(píng)論0 收藏0
  • Spring IOC 容器源碼分析 - 循環(huán)依賴的解決辦法

    摘要:實(shí)例化時(shí),發(fā)現(xiàn)又依賴于。一些緩存的介紹在進(jìn)行源碼分析前,我們先來(lái)看一組緩存的定義。可是看完源碼后,我們似乎仍然不知道這些源碼是如何解決循環(huán)依賴問(wèn)題的。 1. 簡(jiǎn)介 本文,我們來(lái)看一下 Spring 是如何解決循環(huán)依賴問(wèn)題的。在本篇文章中,我會(huì)首先向大家介紹一下什么是循環(huán)依賴。然后,進(jìn)入源碼分析階段。為了更好的說(shuō)明 Spring 解決循環(huán)依賴的辦法,我將會(huì)從獲取 bean 的方法getB...

    aikin 評(píng)論0 收藏0
  • Spring AOP 源碼分析系列文章導(dǎo)讀

    摘要:在寫完容器源碼分析系列文章中的最后一篇后,沒(méi)敢懈怠,趁熱打鐵,花了天時(shí)間閱讀了方面的源碼。從今天開始,我將對(duì)部分的源碼分析系列文章進(jìn)行更新。全稱是,即面向切面的編程,是一種開發(fā)理念。在中,切面只是一個(gè)概念,并沒(méi)有一個(gè)具體的接口或類與此對(duì)應(yīng)。 1. 簡(jiǎn)介 前一段時(shí)間,我學(xué)習(xí)了 Spring IOC 容器方面的源碼,并寫了數(shù)篇文章對(duì)此進(jìn)行講解。在寫完 Spring IOC 容器源碼分析系列...

    張春雷 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<