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...

相关文章
相关标签/搜索