zoukankan      html  css  js  c++  java
  • Spring 源码学习

        spring最核心的理念是IOC,包括AOP也要屈居第二,那么IOC到底是什么呢,四个字,控制反转

    一、什么是Ioc/DI?

    IoC 容器:最主要是完成了完成对象的创建和依赖的管理注入等等。

    先从我们自己设计这样一个视角来考虑:

    所谓控制反转,就是把原先我们代码里面需要实现的对象创建、依赖的代码,反转给容器来帮忙实现。那么必然的我们需要创建一个容器,同时需要一种描述来让容器知道需要创建的对象与对象的关系。这个描述最具体表现就是我们可配置的文件

    对象和对象关系怎么表示?

    可以用 xml , properties 文件等语义化配置文件表示。

    描述对象关系的文件存放在哪里?

    可能是 classpath , filesystem ,或者是 URL 网络资源, servletContext 等。

    回到正题,有了配置文件,还需要对配置文件解析。

    不同的配置文件对对象的描述不一样,如标准的,自定义声明式的,如何统一? 在内部需要有一个统一的关于对象的定义,所有外部的描述都必须转化成统一的描述定义。

    如何对不同的配置文件进行解析?需要对不同的配置文件语法,采用不同的解析器

    二、 Spring IOC体系结构?

    (1) BeanFactory

           

            Spring Bean的创建是典型的工厂模式,这一系列的Bean工厂,也即IOC容器为开发者管理对象间的依赖关系提供了很多便利和基础服务。

            首先是BeanFactory ,它会根据定义好的不同的依赖选择不同的设计模式(主要有单例和原型模式)来返回bean,他们有不同的作用域,spring 2.0以后,作用域更加复杂。

     

        

    1 public interface BeanFactory {    
    2      
    3      //对FactoryBean的转义定义,因为如果使用bean的名字是一个factoryBean那么返回就是一个factory          
    5      String FACTORY_BEAN_PREFIX = "&"; 
    6         
    7      //根据bean的名字,获取在IOC容器中得到bean实例    
    8      Object getBean(String name) throws BeansException;    
    9    
    10     //根据bean的名字和Class类型来得到bean实例,增加了类型安全验证机制。    
    11      Object getBean(String name, Class requiredType) throws BeansException;    
    12     
    13     //提供对bean的检索,看看是否在IOC容器有这个名字的bean    
    14      boolean containsBean(String name);    
    15     
    16     //根据bean名字得到bean实例,并同时判断这个bean是不是单例    
    17     boolean isSingleton(String name) throws NoSuchBeanDefinitionException;    
    18     
    19     //得到bean实例的Class类型    
    20     Class getType(String name) throws NoSuchBeanDefinitionException;    
    21     
    22     //得到bean的别名,如果根据别名检索,那么其原名也会被检索出来    
    23    String[] getAliases(String name);    
    24     
     }
    

     

            在Spring中有许多的IOC容器的实现供用户选择和使用,其相互关系如下:

     

            其中BeanFactory作为最顶层的一个接口类,它定义了IOC容器的基本功能规范,BeanFactory 有三个子类:ListableBeanFactory、HierarchicalBeanFactory 和AutowireCapableBeanFactory。但是从上图中我们可以发现最终的默认实现类是 DefaultListableBeanFactory,他实现了所有的接口。那为何要定义这么多层次的接口呢?查阅这些接口的源码和说明发现,每个接口都有他使用的场合,它主要是为了区分在 Spring 内部在操作过程中对象的传递和转化过程中,对对象的数据访问所做的限制。例如 ListableBeanFactory 接口表示这些 Bean 是可列表的,而 HierarchicalBeanFactory 表示的是这些 Bean 是有继承关系的,也就是每个Bean 有可能有父 Bean。AutowireCapableBeanFactory 接口定义 Bean 的自动装配规则。这四个接口共同定义了 Bean 的集合、Bean 之间的关系、以及 Bean 行为.

           这个类BeanFactory是spring中所有bean工厂,也就是俗称的IOC容器的祖先,各种IOC容器都只是它的实现或者为了满足特别需求的扩展实现,包括我们平时用的最多的ApplicationContext。从上面的方法就可以看出,这些工厂的实现最大的作用就是根据bean的名称亦或类型等等,来返回一个bean的实例。

          一个工厂如果想拥有这样的功能,那么它一定需要以下几个因素:

              1.需要持有各种bean的定义,否则无法正确的完成bean的实例化。

              2.需要持有bean之间的依赖关系,否则在bean实例化的过程中也会出现问题。例如上例,如果我们只是各自持有Person和Company,却不知道他们的依赖关系,那么在Company初始化以后,调用open方法时,就会报空指针。这是因为Company其实并没有真正的被正确初始化。

              3.以上两种都要依赖于我们所写的依赖关系的定义,暂且认为是XML文件(其实可以是各种各样的),那么我们需要一个工具来完成XML文件的读取。

               

    我目前想到的,只需要满足以上三种条件,便可以创建一个bean工厂,来生产各种bean。当然,spring有更高级的做法,以上只是我们直观的去想如何实现IOC。

              其实在上述过程中仍旧有一些问题,比如第一步,我们需要持有bean的定义,如何持有?这是一个问题。我们知道spring的XML配置文件中,有一个属性是lazy-init,这就说明,bean在何时实例化我们是可以控制的。这个属性默认是false,但是我们可以将这个属性设置为true,也就是说spring容器初始化以后,配置了延迟加载的各种bean都还未产生,它们只在需要的时候出现。

              所以我们无法直接的创建一个Map<String,Object>来持有这些bean的实例,在这里要注意,我们要储存的是bean的定义,而非实例。

              那么接下来,又是一个祖宗级别的接口要出现了,来看BeanDefinition。

    (2) BeanDefinition

                这个便是spring中的bean定义接口,所以其实我们工厂里持有的bean定义,就是一堆这个玩意,或者是他的实现类和子接口。这个接口并非直接的祖宗接口,他所继承的两个接口一个是core下面的AttributeAccessor,继承这个接口就以为这我们的bean定义接口同样具有处理属性的能力,而另外一个是beans下面的BeanMetadataElement,字面翻译这个接口就是bean的元数据元素,它可以获得bean的配置定义的一个元素。在XML文件中来说,就是会持有一个bean标签。

     

    package org.springframework.beans.factory.config;
    
    import org.springframework.beans.BeanMetadataElement;
    import org.springframework.beans.MutablePropertyValues;
    import org.springframework.core.AttributeAccessor;
    
    
    public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {
    
    
        String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
    
    
        String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;
    
    
        int ROLE_APPLICATION = 0;
    
    
        int ROLE_SUPPORT = 1;
    
    
        int ROLE_INFRASTRUCTURE = 2;
    
    
        String getParentName();
    
    
        void setParentName(String parentName);
    
    
        String getBeanClassName();
    
    
        void setBeanClassName(String beanClassName);
    
    
        String getFactoryBeanName();
    
        
        void setFactoryBeanName(String factoryBeanName);
    
        
        String getFactoryMethodName();
    
        
        void setFactoryMethodName(String factoryMethodName);
    
    
        String getScope();
    
        
        void setScope(String scope);
    
        
        boolean isLazyInit();
    
        
        void setLazyInit(boolean lazyInit);
    
        
        String[] getDependsOn();
    
        
        void setDependsOn(String[] dependsOn);
    
        
        boolean isAutowireCandidate();
    
        
        void setAutowireCandidate(boolean autowireCandidate);
    
        
        boolean isPrimary();
    
        
        void setPrimary(boolean primary);
    
    
        ConstructorArgumentValues getConstructorArgumentValues();
    
    
        MutablePropertyValues getPropertyValues();
    
    
        boolean isSingleton();
    
    
        boolean isPrototype();
    
        
        boolean isAbstract();
    
        
        int getRole();
    
        
        String getDescription();
    
        
        String getResourceDescription();
    
        
        BeanDefinition getOriginatingBeanDefinition();
    
    }
    复制代码

           仔细观看,能发现beanDefinition中有两个方法分别是String[] getDependsOn()和void setDependsOn(String[] dependsOn),这两个方法就是获取依赖的beanName和设置依赖的beanName,这样就好办了,只要我们有一个BeanDefinition,就可以完全的产生一个完整的bean实例。

          那么知道了上述两个接口,我相信不少人甚至不看源码都已经猜到spring是如何做的了。没错,就是让bean工厂持有一个Map<String,BeanDefinition>,这样就可以在任何时候我们想用哪个bean,取到它的bean定义,我们就可以创造出一个新鲜的实例。

           接口当然不可能持有这样一个对象,那么这个对象一定是在BeanFactory的某个实现类或者抽象实现类当中所持有的,上面我们说了BeanFactory的继承关系,我们发现最终的默认实现类是 DefaultListableBeanFactory。

    (3)DefaultListableBeanFactory

        它的源码为:

        

    package org.springframework.beans.factory.support;
    
    
    /**
     * Default implementation of the
     * based on bean definition objects.
     *
     * <p>Can be used as a standalone bean factory, or as a superclass for custom
     * bean factories. Note that readers for specific bean definition formats are
     * typically implemented separately rather than as bean factory subclasses:.
     *
     */
    @SuppressWarnings("serial")
    public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
    		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    	private static Class<?> javaxInjectProviderClass = null;
    
    	static {
    		ClassLoader cl = DefaultListableBeanFactory.class.getClassLoader();
    		try {
    			javaxInjectProviderClass = cl.loadClass("javax.inject.Provider");
    		}
    		catch (ClassNotFoundException ex) {
    			// JSR-330 API not available - Provider interface simply not supported then.
    		}
    	}
    
    
    	/** Map from serialized id to factory instance */
    	private static final Map<String, Reference<DefaultListableBeanFactory>> serializableFactories =
    			new ConcurrentHashMap<String, Reference<DefaultListableBeanFactory>>(8);
    
    
    /** Map of bean definition objects, keyed by bean name */ private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>(64); /** Map of singleton and non-singleton bean names keyed by dependency type */ private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64); /** Map of singleton-only bean names keyed by dependency type */ private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<Class<?>, String[]>(64); /** List of bean definition names, in registration order */ private final List<String> beanDefinitionNames = new ArrayList<String>(); /** * Create a new DefaultListableBeanFactory. */ public DefaultListableBeanFactory() { super(); } /** * Create a new DefaultListableBeanFactory with the given parent. * @param parentBeanFactory the parent BeanFactory */ public DefaultListableBeanFactory(BeanFactory parentBeanFactory) { super(parentBeanFactory); } //--------------------------------------------------------------------- // Implementation of ListableBeanFactory interface //--------------------------------------------------------------------- public <T> T getBean(Class<T> requiredType) throws BeansException { Assert.notNull(requiredType, "Required type must not be null"); String[] beanNames = getBeanNamesForType(requiredType); if (beanNames.length > 1) { ArrayList<String> autowireCandidates = new ArrayList<String>(); for (String beanName : beanNames) { if (getBeanDefinition(beanName).isAutowireCandidate()) { autowireCandidates.add(beanName); } } if (autowireCandidates.size() > 0) { beanNames = autowireCandidates.toArray(new String[autowireCandidates.size()]); } } if (beanNames.length == 1) { return getBean(beanNames[0], requiredType); } else if (beanNames.length > 1) { T primaryBean = null; for (String beanName : beanNames) { T beanInstance = getBean(beanName, requiredType); if (isPrimary(beanName, beanInstance)) { if (primaryBean != null) { throw new NoUniqueBeanDefinitionException(requiredType, beanNames.length, "more than one 'primary' bean found of required type: " + Arrays.asList(beanNames)); } primaryBean = beanInstance; } } if (primaryBean != null) { return primaryBean; } throw new NoUniqueBeanDefinitionException(requiredType, beanNames); } else if (getParentBeanFactory() != null) { return getParentBeanFactory().getBean(requiredType); } else { throw new NoSuchBeanDefinitionException(requiredType); } } }

             其中

    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
    

           让bean工厂持有一个Map<String,BeanDefinition>,这样就可以在任何时候我们想用哪个bean,取到它的bean定义,我们就可以创造出一个新鲜的实例。     

                  那么从现在来看,我们需要什么才能把Map填充呢?也就是初始化bean工厂呢,或者说建立IOC容器。我首先列出来以下几步。

                 1.需要一个File指向我们的XML文件(本文的配置文件都已XML为例,因为这是我们最熟悉的),专业点可以叫资源定位,简单点可以说我们需要一些工具来完成找到XML文件的所在位置。

                 2.需要一个Reader来读取我们的XML文件,专业点叫DOM解析,简单点说,就是把XML文件的各种定义都给拿出来。

                 3.需要将读出来的数据都设置到Map当中。

                 那么从现在来看,我们需要什么才能把Map填充呢?也就是初始化bean工厂呢,或者说建立IOC容器。

                 1.需要一个File指向我们的XML文件(本文的配置文件都已XML为例,因为这是我们最熟悉的),专业点可以叫资源定位,简单点可以说我们需要一些工具来完成找到XML文件的所在位置。

                 2.需要一个Reader来读取我们的XML文件,专业点叫DOM解析,简单点说,就是把XML文件的各种定义都给拿出来。

                 3.需要将读出来的数据都设置到Map当中。

                 这三步总结起来就是定位、解析、注册。

    (4)定位、解析、注册

                 spring提供了许多IOC容器的实现。比如XmlBeanFactory,ClasspathXmlApplicationContext等。其中XmlBeanFactory就是针对最基本的ioc容器的实现,这个IOC容器可以读取XML文件定义的BeanDefinition(XML文件中对bean的描述),如果说XmlBeanFactory是容器中的屌丝,ApplicationContext应该算容器中的高帅富.

            XmlBeanFactory源码如下:

    package org.springframework.beans.factory.xml;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.core.io.Resource;
    
    /**
     * Convenience extension of {@link DefaultListableBeanFactory} that reads bean definitions
     * from an XML document. Delegates to {@link XmlBeanDefinitionReader} underneath; effectively
     * equivalent to using an XmlBeanDefinitionReader with a DefaultListableBeanFactory.
     *
     * <p>The structure, element and attribute names of the required XML document
     * are hard-coded in this class. (Of course a transform could be run if necessary
     * to produce this format). "beans" doesn't need to be the root element of the XML
     * document: This class will parse all bean definition elements in the XML file.*/
    @Deprecated
    @SuppressWarnings({"serial", "all"})
    public class XmlBeanFactory extends DefaultListableBeanFactory {
    
        private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);
    
    
        /**
         * Create a new XmlBeanFactory with the given resource,
         * which must be parsable using DOM.
         * @param resource XML resource to load bean definitions from
         * @throws BeansException in case of loading or parsing errors
         */
        public XmlBeanFactory(Resource resource) throws BeansException {
            this(resource, null);
        }
    
        /**
         * Create a new XmlBeanFactory with the given input stream,
         * which must be parsable using DOM.
         * @param resource XML resource to load bean definitions from
         * @param parentBeanFactory parent bean factory
         * @throws BeansException in case of loading or parsing errors
         */
        public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
            super(parentBeanFactory);
            this.reader.loadBeanDefinitions(resource);
        }
    
    }

                直接上代码,我们还使用Person类作为一个Bean。

                

    package com.springframework.beans.test;
    
    public class Person {
    
        public void work(){
            System.out.println("I am working");
        }
    }

            

              我们还需要写一个简单的XML文件,beans.xml。

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
     <bean id="person" class="com.springframework.beans.test.Person"></bean>
    </beans>

               下面是我们根据上述的思路写一段程序。

      

    package com.springframework.beans.test;
    
    import org.springframework.beans.factory.support.DefaultListableBeanFactory;
    import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
    import org.springframework.core.io.ClassPathResource;
    
    
    public class TestDefaultListableBeanFactory {
    
        public static void main(String[] args) {
            ClassPathResource classPathResource = new ClassPathResource("beans.xml");
            DefaultListableBeanFactory defaultListableBeanFactory = new DefaultListableBeanFactory();
            XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(defaultListableBeanFactory);
            xmlBeanDefinitionReader.loadBeanDefinitions(classPathResource);
            System.out.println("numbers: " + defaultListableBeanFactory.getBeanDefinitionCount());
            ((Person)defaultListableBeanFactory.getBean("person")).work();
        }
    }

                对于xmlbeanfactory,代码为:

    //根据Xml配置文件创建Resource资源对象,该对象中包含了BeanDefinition的信息
     ClassPathResource resource =new ClassPathResource("application-context.xml");
    //创建DefaultListableBeanFactory
     DefaultListableBeanFactory factory =new DefaultListableBeanFactory();
    //创建XmlBeanDefinitionReader读取器,用于载入BeanDefinition。之所以需要BeanFactory作为参数,是因为会将读取的信息回调配置给factory
     XmlBeanDefinitionReader reader =new XmlBeanDefinitionReader(factory);
    //XmlBeanDefinitionReader执行载入BeanDefinition的方法,最后会完成Bean的载入和注册。完成后Bean就成功的放置到IOC容器当中,以后我们就可以从中取得Bean来使用
     reader.loadBeanDefinitions(resource);

             

               第一行完成了我们的第一步,即资源定位,采用classpath定位,因为我的beans.xml文件是放在src下面的。

               第二行创建了一个默认的bean工厂。

               第三行创建了一个reader,从名字就不难看出,这个reader是用来读取XML文件的。这一步要多说一句,其中将我们创建的defaultListableBeanFactory作为参数传给了reader的构造函数,这里是为了第四步读取XML文件做准备。

               第四行使用reader解析XML文件,并将读取的bean定义回调设置到defaultListableBeanFactory当中。其实回调这一步就相当于我们上述的注册这一步。

               

              (1)Bean 的解析

              Bean 的解析 过程非常复杂,功能被分的很细,因为这里需要被扩展的地方很多,必须保证有足够的灵活性,以应对可能的变化。Bean 的解析主要就是对 Spring 配置文件的解析。这个解析过程主要通过下图中的类完成:

               这个时候defaultListableBeanFactory已经被正确初始化了,我们已经可以使用它的一些方法了,比如上面所使用的获取bean个数,以及获得一个bean实例的方法。

                1.1

               对于ApplicationContext ,代码为

    package com.springframework.beans.test;
    
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;
    
    public class TestApplicationContext {
    
        public static void main(String[] args) {
            ApplicationContext applicationContext = new FileSystemXmlApplicationContext("classpath:beans.xml");
            System.out.println("numbers: " + applicationContext.getBeanDefinitionCount());
            ((Person)applicationContext.getBean("person")).work();
        }
    }
    

           1.2

          具体我们在new一个FileSystemXmlApplicationContext对象的时候,spring到底做了哪些事情呢,

          先看其构造函数:

     调用构造函数:

    复制代码
    /**
    * Create a new FileSystemXmlApplicationContext, loading the definitions
    * from the given XML files and automatically refreshing the context.
    * @param configLocations array of file paths
    * @throws BeansException if context creation failed
     */public FileSystemXmlApplicationContext(String... configLocations) throws BeansException {
            this(configLocations, true, null);
        }
    复制代码

    实际调用

    复制代码
    public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)  
                throws BeansException {    
            super(parent);  
            setConfigLocations(configLocations);  
            if (refresh) {  
                refresh();  
            }  
        } 

      

            通过分析FileSystemXmlApplicationContext的源代码可以知道,在创建FileSystemXmlApplicationContext容器时,构造方法做以下两项重要工作:

           1 首先,调用父类容器的构造方法(super(parent)方法)为容器设置好Bean资源加载器。(其继承体系如下)

    public abstract class AbstractApplicationContext extends DefaultResourceLoader  
            implements ConfigurableApplicationContext, DisposableBean {  
        //静态初始化块,在整个容器创建过程中只执行一次  
        static {  
            //为了避免应用程序在Weblogic8.1关闭时出现类加载异常加载问题,加载IoC容  
           //器关闭事件(ContextClosedEvent)类  
            ContextClosedEvent.class.getName();  
        }  
        //FileSystemXmlApplicationContext调用父类构造方法调用的就是该方法  
        public AbstractApplicationContext(ApplicationContext parent) {  
            this.parent = parent;  
            this.resourcePatternResolver = getResourcePatternResolver();  
        }  
        //获取一个Spring Source的加载器用于读入Spring Bean定义资源文件  
        protected ResourcePatternResolver getResourcePatternResolver() {  
            // AbstractApplicationContext继承DefaultResourceLoader,也是一个S  
            //Spring资源加载器,其getResource(String location)方法用于载入资源  
            return new PathMatchingResourcePatternResolver(this);  
        }   
    ……  
    } 

    AbstractApplicationContext构造方法中调用PathMatchingResourcePatternResolver的构造方法创建Spring资源加载器:

    public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {  
            Assert.notNull(resourceLoader, "ResourceLoader must not be null");  
            //设置Spring的资源加载器  
            this.resourceLoader = resourceLoader;  
    } 
      

              在设置容器的资源加载器之后,接下来FileSystemXmlApplicationContet执行setConfigLocations方法通过调用其父类AbstractRefreshableConfigApplicationContext的方法进行对Bean定义资源文件的定位,该方法的源码如下:

        //处理单个资源文件路径为一个字符串的情况  
        public void setConfigLocation(String location) {  
           //String CONFIG_LOCATION_DELIMITERS = ",; /t/n";  
           //即多个资源文件路径之间用” ,; /t/n”分隔,解析成数组形式  
            setConfigLocations(StringUtils.tokenizeToStringArray(location, CONFIG_LOCATION_DELIMITERS));  
        }  
    //解析Bean定义资源文件的路径,处理多个资源文件字符串数组 public void setConfigLocations(String[] locations) { if (locations != null) { Assert.noNullElements(locations, "Config locations must not be null"); this.configLocations = new String[locations.length]; for (int i = 0; i < locations.length; i++) { // resolvePath为同一个类中将字符串解析为路径的方法 this.configLocations[i] = resolvePath(locations[i]).trim(); } } else { this.configLocations = null; } }
    复制代码

             

                  通过这两个方法的源码我们可以看出,我们既可以使用一个字符串来配置多个Spring Bean定义资源文件,也可以使用字符串数组,即下面两种方式都是可以的:

                 a.    ClasspathResource res = new ClasspathResource(“a.xml,b.xml,……”);

                  多个资源文件路径之间可以是用” ,; /t/n”等分隔。

                  b.    ClasspathResource res = new ClasspathResource(newString[]{“a.xml”,”b.xml”,……});

                    至此,Spring IoC容器在初始化时将配置的Bean定义资源文件定位为Spring封装的Resource。

            1.3

              refresh方法,便是IOC容器初始化的入口。

              Spring IoC容器对Bean定义资源的载入是从refresh()函数开始的,refresh()是一个模板方法,refresh()方法的作用是:在创建IoC容器前,如果已经有容器存在,则需要把已有的容器销毁和关闭,以保证在refresh之后使用的是新建立起来的IoC容器。refresh的作用类似于对IoC容器的重启,在新建立好的容器中对容器进行初始化,对Bean定义资源进行载入

               FileSystemXmlApplicationContext通过调用其父类AbstractApplicationContext的refresh()函数启动整个IoC容器对Bean定义的载入过程:

           

    public void refresh() throws BeansException, IllegalStateException {  
    2        synchronized (this.startupShutdownMonitor) {  
    3            //调用容器准备刷新的方法,获取容器的当时时间,同时给容器设置同步标识  
    4            prepareRefresh();  
    5            //告诉子类启动refreshBeanFactory()方法,Bean定义资源文件的载入从  
    6           //子类的refreshBeanFactory()方法启动  
    7            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();  
    8            //为BeanFactory配置容器特性,例如类加载器、事件处理器等  
    9            prepareBeanFactory(beanFactory);  
    10            try {  
    11                //为容器的某些子类指定特殊的BeanPost事件处理器  
    12                postProcessBeanFactory(beanFactory);  
    13                //调用所有注册的BeanFactoryPostProcessor的Bean  
    14                invokeBeanFactoryPostProcessors(beanFactory);  
    15                //为BeanFactory注册BeanPost事件处理器.  
    16                //BeanPostProcessor是Bean后置处理器,用于监听容器触发的事件  
    17                registerBeanPostProcessors(beanFactory);  
    18                //初始化信息源,和国际化相关.  
    19                initMessageSource();  
    20                //初始化容器事件传播器.  
    21                initApplicationEventMulticaster();  
    22                //调用子类的某些特殊Bean初始化方法  
    23                onRefresh();  
    24                //为事件传播器注册事件监听器.  
    25                registerListeners();  
    26                //初始化所有剩余的单态Bean.  
    27                finishBeanFactoryInitialization(beanFactory);  
    28                //初始化容器的生命周期事件处理器,并发布容器的生命周期事件  
    29                finishRefresh();  
    30            }  
    31            catch (BeansException ex) {  
    32                //销毁以创建的单态Bean  
    33                destroyBeans();  
    34                //取消refresh操作,重置容器的同步标识.  
    35                cancelRefresh(ex);  
    36                throw ex;  
    37            }  
    38        }  
    39    }
    

            refresh()方法主要为IoC容器Bean的生命周期管理提供条件,Spring IoC容器载入Bean定义资源文件从其子类容器的refreshBeanFactory()方法启动,所以整个refresh()中“ConfigurableListableBeanFactory beanFactory =obtainFreshBeanFactory();”这句以后代码的都是注册容器的信息源和生命周期事件,载入过程就是从这句代码启动

        protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
            //这里使用了委派设计模式,父类定义了抽象的refreshBeanFactory()方法,具体实现调用子类容器的refreshBeanFactory()方法
             refreshBeanFactory();  
            ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
            if (logger.isDebugEnabled()) {  
                logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
            }  
            return beanFactory;  
        } 
    
    

         该方法中第一句便调用了另外一个refreshBeanFactory方法,这个方法是AbstractApplicationContext中的抽象方法,具体的实现并没有在这个抽象类中实现,而是留给了子类,我们追踪到这个子类当中去看一下。该方法又子类AbstractRefreshableApplicationContext实现,我们来看

             

    protected final void refreshBeanFactory() throws BeansException {
            if (hasBeanFactory()) {
                destroyBeans();
                closeBeanFactory();
            }
            try {
                DefaultListableBeanFactory beanFactory = createBeanFactory();
                beanFactory.setSerializationId(getId());
                customizeBeanFactory(beanFactory);
                loadBeanDefinitions(beanFactory);
                synchronized (this.beanFactoryMonitor) {
                    this.beanFactory = beanFactory;
                }
            }
            catch (IOException ex) {
                throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
            }
        }
    

           方法加上了final关键字,也就是说此方法不可被重写,可以很清楚的看到,IOC容器的初始化就是在这个方法里发生的,第一步先是判断有无现有的工厂,有的话便会将其摧毁,否则,就会创建一个默认的bean工厂,也就是前面提到的DefaultListableBeanFactory,注意看loadBeanDefinitions(beanFactory);这里,当我们创建了一个默认的bean工厂以后,便是载入bean的定义。这与我们上一章所使用的原始的创建bean工厂的方式极为相似。

              AbstractRefreshableApplicationContext中只定义了抽象的loadBeanDefinitions方法,容器真正调用的是其子类AbstractXmlApplicationContext对该方法的实现,AbstractXmlApplicationContext的主要源码如下:

                1.4

         loadBeanDefinitions方法是由AbstractXmlApplicationContext抽象类实现的。

    复制代码
        protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
            // Create a new XmlBeanDefinitionReader for the given BeanFactory.
            XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
    
            // Configure the bean definition reader with this context's
            // resource loading environment.
            beanDefinitionReader.setResourceLoader(this);
            beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    
            // Allow a subclass to provide custom initialization of the reader,
            // then proceed with actually loading the bean definitions.
            initBeanDefinitionReader(beanDefinitionReader);
            loadBeanDefinitions(beanDefinitionReader);
        }
    复制代码

              1.5

              第一行首先定义了一个reader,很明显,这个就是spring为读取XML配置文件而定制的读取工具,这里AbstractXmlApplicationContext间接实现了ResourceLoader接口,所以该方法的第二行才得以成立,最后一行便是真正载入bean定义的过程。我们追踪其根源,可以发现最终的读取过程正是由reader完成的,代码如下。

    复制代码
    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();
                }
            }
        }
    复制代码

            1.6 

               这个方法中不难发现,try块中的代码才是载入bean定义的真正过程,我们一步一步的扒开bean定义的载入,spring将资源返回的输入流包装以后传给了doLoadBeanDefinitions方法,我们进去看看发生了什么。

               

    protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
                throws BeanDefinitionStoreException {
            try {
                int validationMode = getValidationModeForResource(resource);
                Document doc = this.documentLoader.loadDocument(
                        inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
                return registerBeanDefinitions(doc, resource);
            }
            catch (BeanDefinitionStoreException ex) {
                throw ex;
            }
            catch (SAXParseException ex) {
                throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                        "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
            }
            catch (SAXException ex) {
                throw new XmlBeanDefinitionStoreException(resource.getDescription(),
                        "XML document from " + resource + " is invalid", ex);
            }
            catch (ParserConfigurationException ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "Parser configuration exception parsing XML from " + resource, ex);
            }
            catch (IOException ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "IOException parsing XML document from " + resource, ex);
            }
            catch (Throwable ex) {
                throw new BeanDefinitionStoreException(resource.getDescription(),
                        "Unexpected exception parsing XML document from " + resource, ex);
            }
        }
    

      可以看到,spring采用documentLoader将资源转换成了Document接口,这正是我们熟知的SAX对XML解析的重要接口之一,这下不难理解了,可以想象出spring一定是根据XSD文件规定的XML格式,解析了XML文件中的各个节点以及属性。尽管如此,我们还是跟着registerBeanDefinitions方法进去看看。

         XmlBeanDefinitionReader类中的doLoadBeanDefinitions方法是从特定XML文件中实际载入Bean定义资源的方法,该方法在载入Bean定义资源之后将其转换为Document对象,接下来调用registerBeanDefinitions启动Spring IoC容器对Bean定义的解析过程,registerBeanDefinitions方法源码如下:


    1 //按照Spring的Bean语义要求将Bean定义资源解析并转换为容器内部数据结构 2 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException { 3 //得到BeanDefinitionDocumentReader来对xml格式的BeanDefinition解析 4 BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader(); 5 //获得容器中注册的Bean数量 6 int countBefore = getRegistry().getBeanDefinitionCount(); 7 //解析过程入口,这里使用了委派模式,BeanDefinitionDocumentReader只是个接口,//具体的解析实现过程有实现类DefaultBeanDefinitionDocumentReader完成 8 documentReader.registerBeanDefinitions(doc, createReaderContext(resource)); 9 //统计解析的Bean数量 10 return getRegistry().getBeanDefinitionCount() - countBefore; 11 } 12 //创建BeanDefinitionDocumentReader对象,解析Document对象 13 protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() { 14 return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass)); }

         1.7解析文件与注册的具体实现

             1解析与注册的分界点

            按照Spring的Bean规则对Document对象解析的过程是在接口BeanDefinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReader中实现的。BeanDefinitionDocumentReader接口通过registerBeanDefinitions方法调用其实现类DefaultBeanDefinitionDocumentReader对Document对象进行解析,解析的代码如下:

         

     //根据Spring DTD对Bean的定义规则解析Bean定义Document对象  
    2     public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {  
    3         //获得XML描述符  
    4         this.readerContext = readerContext;  
    5         logger.debug("Loading bean definitions");  
    6         //获得Document的根元素  
    7         Element root = doc.getDocumentElement();  
    8         //具体的解析过程由BeanDefinitionParserDelegate实现,  
    9         //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素  
    10        BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);  
    11        //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性  
    12        preProcessXml(root);  
    13        //从Document的根元素开始进行Bean定义的Document对象  
    14        parseBeanDefinitions(root, delegate);  
    15        //在解析Bean定义之后,进行自定义的解析,增加解析过程的可扩展性  
    16        postProcessXml(root);  
    17    }  
    18    //创建BeanDefinitionParserDelegate,用于完成真正的解析过程  
    19    protected BeanDefinitionParserDelegate createHelper(XmlReaderContext readerContext, Element root) {  
    20        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);  
    21        //BeanDefinitionParserDelegate初始化Document根元素  
    22        delegate.initDefaults(root);  
    23        return delegate;  
    24    }  
    25    //使用Spring的Bean规则从Document的根元素开始进行Bean定义的Document对象  
    26    protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {  
    27        //Bean定义的Document对象使用了Spring默认的XML命名空间  
    28        if (delegate.isDefaultNamespace(root)) {  
    29            //获取Bean定义的Document对象根元素的所有子节点  
    30            NodeList nl = root.getChildNodes();  
    31            for (int i = 0; i < nl.getLength(); i++) {  
    32                Node node = nl.item(i);  
    33                //获得Document节点是XML元素节点  
    34                if (node instanceof Element) {  
    35                    Element ele = (Element) node;  
    36                //Bean定义的Document的元素节点使用的是Spring默认的XML命名空间  
    37                    if (delegate.isDefaultNamespace(ele)) {  
    38                        //使用Spring的Bean规则解析元素节点  
    39                        parseDefaultElement(ele, delegate);  
    40                    }  
    41                    else {  
    42                        //没有使用Spring默认的XML命名空间,则使用用户自定义的解//析规则解析元素节点  
    43                        delegate.parseCustomElement(ele);  
    44                    }  
    45                }  
    46            }  
    47        }  
    48        else {  
    49            //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的  
    50            //解析规则解析Document根节点  
    51            delegate.parseCustomElement(root);  
    52        }  
    53    }  
    54    //使用Spring的Bean规则解析Document元素节点  
    55    private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {  
    56        //如果元素节点是<Import>导入元素,进行导入解析  
    57        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {  
    58            importBeanDefinitionResource(ele);  
    59        }  
    60        //如果元素节点是<Alias>别名元素,进行别名解析  
    61        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {  
    62            processAliasRegistration(ele);  
    63        }  
    64        //元素节点既不是导入元素,也不是别名元素,即普通的<Bean>元素,  
    65        //按照Spring的Bean规则解析元素  
    66        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {  
    67            processBeanDefinition(ele, delegate);  
    68        }  
    69    }  
    70    //解析<Import>导入元素,从给定的导入路径加载Bean定义资源到Spring IoC容器中  
    71    protected void importBeanDefinitionResource(Element ele) {  
    72        //获取给定的导入元素的location属性  
    73        String location = ele.getAttribute(RESOURCE_ATTRIBUTE);  
    74        //如果导入元素的location属性值为空,则没有导入任何资源,直接返回  
    75        if (!StringUtils.hasText(location)) {  
    76            getReaderContext().error("Resource location must not be empty", ele);  
    77            return;  
    78        }  
    79        //使用系统变量值解析location属性值  
    80        location = SystemPropertyUtils.resolvePlaceholders(location);  
    81        Set<Resource> actualResources = new LinkedHashSet<Resource>(4);  
    82        //标识给定的导入元素的location是否是绝对路径  
    83        boolean absoluteLocation = false;  
    84        try {  
    85            absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();  
    86        }  
    87        catch (URISyntaxException ex) {  
    88            //给定的导入元素的location不是绝对路径  
    89        }  
    90        //给定的导入元素的location是绝对路径  
    91        if (absoluteLocation) {  
    92            try {  
    93                //使用资源读入器加载给定路径的Bean定义资源  
    94                int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);  
    95                if (logger.isDebugEnabled()) {  
    96                    logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");  
    97                }  
    98            }  
    99            catch (BeanDefinitionStoreException ex) {  
    100                getReaderContext().error(  
    101                        "Failed to import bean definitions from URL location [" + location + "]", ele, ex);  
    102            }  
    103        }  
    104        else {  
    105            //给定的导入元素的location是相对路径  
    106            try {  
    107                int importCount;  
    108                //将给定导入元素的location封装为相对路径资源  
    109                Resource relativeResource = getReaderContext().getResource().createRelative(location);  
    110                //封装的相对路径资源存在  
    111                if (relativeResource.exists()) {  
    112                    //使用资源读入器加载Bean定义资源  
    113                    importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);  
    114                    actualResources.add(relativeResource);  
    115                }  
    116                //封装的相对路径资源不存在  
    117                else {  
    118                    //获取Spring IoC容器资源读入器的基本路径  
    119                    String baseLocation = getReaderContext().getResource().getURL().toString();  
    120                    //根据Spring IoC容器资源读入器的基本路径加载给定导入  
    121                    //路径的资源  
    122                    importCount = getReaderContext().getReader().loadBeanDefinitions(  
    123                            StringUtils.applyRelativePath(baseLocation, location), actualResources);  
    124                }  
    125                if (logger.isDebugEnabled()) {  
    126                    logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");  
    127                }  
    128            }  
    129            catch (IOException ex) {  
    130                getReaderContext().error("Failed to resolve current resource location", ele, ex);  
    131            }  
    132            catch (BeanDefinitionStoreException ex) {  
    133                getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",  
    134                        ele, ex);  
    135            }  
    136        }  
    137        Resource[] actResArray = actualResources.toArray(new Resource[actualResources.size()]);  
    138        //在解析完<Import>元素之后,发送容器导入其他资源处理完成事件  
    139        getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));  
    140    }  
    141    //解析<Alias>别名元素,为Bean向Spring IoC容器注册别名  
    142    protected void processAliasRegistration(Element ele) {  
    143        //获取<Alias>别名元素中name的属性值  
    144        String name = ele.getAttribute(NAME_ATTRIBUTE);  
    145        //获取<Alias>别名元素中alias的属性值  
    146        String alias = ele.getAttribute(ALIAS_ATTRIBUTE);  
    147        boolean valid = true;  
    148        //<alias>别名元素的name属性值为空  
    149        if (!StringUtils.hasText(name)) {  
    150            getReaderContext().error("Name must not be empty", ele);  
    151            valid = false;  
    152        }  
    153        //<alias>别名元素的alias属性值为空  
    154        if (!StringUtils.hasText(alias)) {  
    155            getReaderContext().error("Alias must not be empty", ele);  
    156            valid = false;  
    157        }  
    158        if (valid) {  
    159            try {  
    160                //向容器的资源读入器注册别名  
    161                getReaderContext().getRegistry().registerAlias(name, alias);  
    162            }  
    163            catch (Exception ex) {  
    164                getReaderContext().error("Failed to register alias '" + alias +  
    165                        "' for bean with name '" + name + "'", ele, ex);  
    166            }  
    167            //在解析完<Alias>元素之后,发送容器别名处理完成事件  
    168            getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));  
    169        }  
    170    }  
    171    //解析Bean定义资源Document对象的普通元素  
    172    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {  
    173        // BeanDefinitionHolder是对BeanDefinition的封装,即Bean定义的封装类  
    174        //对Document对象中<Bean>元素的解析由BeanDefinitionParserDelegate实现
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele); 175 if (bdHolder != null) { 176 bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder); 177 try { 178 //向Spring IoC容器注册解析得到的Bean定义,这是Bean定义向IoC容器注册的入口 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry()); 179 } 180 catch (BeanDefinitionStoreException ex) { 181 getReaderContext().error("Failed to register bean definition with name '" + 182 bdHolder.getBeanName() + "'", ele, ex); 183 } 184 //在完成向Spring IoC容器注册解析得到的Bean定义之后,发送注册事件 185 getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder)); 186 } 187 }

         2 具体解析过程 

           对Bean定义资源文件中使用最多的<Bean>元素交由BeanDefinitionParserDelegate中parseBeanDefinitionElement来解析,其解析实现的源码如下:

      //解析<Bean>元素的入口  
    2    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {  
    3        return parseBeanDefinitionElement(ele, null);  
    4    }  
    5    //解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name  
    6    //和别名属性  
    7    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {  
    8        //获取<Bean>元素中的id属性值  
    9        String id = ele.getAttribute(ID_ATTRIBUTE);  
    10        //获取<Bean>元素中的name属性值  
    11        String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);  
    12        ////获取<Bean>元素中的alias属性值  
    13        List<String> aliases = new ArrayList<String>();  
    14        //将<Bean>元素中的所有name属性值存放到别名中  
    15        if (StringUtils.hasLength(nameAttr)) {  
    16            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, BEAN_NAME_DELIMITERS);  
    17            aliases.addAll(Arrays.asList(nameArr));  
    18        }  
    19        String beanName = id;  
    20        //如果<Bean>元素中没有配置id属性时,将别名中的第一个值赋值给beanName  
    21        if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {  
    22            beanName = aliases.remove(0);  
    23            if (logger.isDebugEnabled()) {  
    24                logger.debug("No XML 'id' specified - using '" + beanName +  
    25                        "' as bean name and " + aliases + " as aliases");  
    26            }  
    27        }  
    28        //检查<Bean>元素所配置的id或者name的唯一性,containingBean标识<Bean>  
    29        //元素中是否包含子<Bean>元素  
    30        if (containingBean == null) {  
    31            //检查<Bean>元素所配置的id、name或者别名是否重复  
    32            checkNameUniqueness(beanName, aliases, ele);  
    33        }  
    34        //详细对<Bean>元素中配置的Bean定义进行解析的地方  
    35        AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);  
    36        if (beanDefinition != null) {  
    37            if (!StringUtils.hasText(beanName)) {  
    38                try {  
    39                    if (containingBean != null) {  
    40                        //如果<Bean>元素中没有配置id、别名或者name,且没有包含子//<Bean>元素,为解析的Bean生成一个唯一beanName并注册  
    41                        beanName = BeanDefinitionReaderUtils.generateBeanName(  
    42                                beanDefinition, this.readerContext.getRegistry(), true);  
    43                    }  
    44                    else {  
    45                        //如果<Bean>元素中没有配置id、别名或者name,且包含了子//<Bean>元素,为解析的Bean使用别名向IoC容器注册  
    46                        beanName = this.readerContext.generateBeanName(beanDefinition);  
    47                        //为解析的Bean使用别名注册时,为了向后兼容                                    //Spring1.2/2.0,给别名添加类名后缀  
    48                        String beanClassName = beanDefinition.getBeanClassName();  
    49                        if (beanClassName != null &&  
    50                                beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&  
    51                                !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {  
    52                            aliases.add(beanClassName);  
    53                        }  
    54                    }  
    55                    if (logger.isDebugEnabled()) {  
    56                        logger.debug("Neither XML 'id' nor 'name' specified - " +  
    57                                "using generated bean name [" + beanName + "]");  
    58                    }  
    59                }  
    60                catch (Exception ex) {  
    61                    error(ex.getMessage(), ele);  
    62                    return null;  
    63                }  
    64            }  
    65            String[] aliasesArray = StringUtils.toStringArray(aliases);  
    66            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);  
    67        }  
    68        //当解析出错时,返回null  
    69        return null;  
    70    }  
    71    //详细对<Bean>元素中配置的Bean定义其他属性进行解析,由于上面的方法中已经对//Bean的id、name和别名等属性进行了处理,该方法中主要处理除这三个以外的其他属性数据  
    72    public AbstractBeanDefinition parseBeanDefinitionElement(  
    73            Element ele, String beanName, BeanDefinition containingBean) {  
    74        //记录解析的<Bean>  
    75        this.parseState.push(new BeanEntry(beanName));  
    76        //这里只读取<Bean>元素中配置的class名字,然后载入到BeanDefinition中去  
    77        //只是记录配置的class名字,不做实例化,对象的实例化在依赖注入时完成  
    78        String className = null;  
    79        if (ele.hasAttribute(CLASS_ATTRIBUTE)) {  
    80            className = ele.getAttribute(CLASS_ATTRIBUTE).trim();  
    81        }  
    82        try {  
    83            String parent = null;  
    84            //如果<Bean>元素中配置了parent属性,则获取parent属性的值  
    85            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {  
    86                parent = ele.getAttribute(PARENT_ATTRIBUTE);  
    87            }  
    88            //根据<Bean>元素配置的class名称和parent属性值创建BeanDefinition  
    89            //为载入Bean定义信息做准备  
    90            AbstractBeanDefinition bd = createBeanDefinition(className, parent);  
    91            //对当前的<Bean>元素中配置的一些属性进行解析和设置,如配置的单态(singleton)属性等  
    92            parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);  
    93            //为<Bean>元素解析的Bean设置description信息 bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));  
    94            //对<Bean>元素的meta(元信息)属性解析  
    95            parseMetaElements(ele, bd);  
    96            //对<Bean>元素的lookup-method属性解析  
    97            parseLookupOverrideSubElements(ele, bd.getMethodOverrides());  
    98            //对<Bean>元素的replaced-method属性解析  
    99            parseReplacedMethodSubElements(ele, bd.getMethodOverrides());  
    100            //解析<Bean>元素的构造方法设置  
    101            parseConstructorArgElements(ele, bd);  
    102            //解析<Bean>元素的<property>设置  
    103            parsePropertyElements(ele, bd);  
    104            //解析<Bean>元素的qualifier属性  
    105            parseQualifierElements(ele, bd);  
    106            //为当前解析的Bean设置所需的资源和依赖对象  
    107            bd.setResource(this.readerContext.getResource());  
    108            bd.setSource(extractSource(ele));  
    109            return bd;  
    110        }  
    111        catch (ClassNotFoundException ex) {  
    112            error("Bean class [" + className + "] not found", ele, ex);  
    113        }  
    114        catch (NoClassDefFoundError err) {  
    115            error("Class that bean class [" + className + "] depends on not found", ele, err);  
    116        }  
    117        catch (Throwable ex) {  
    118            error("Unexpected failure during bean definition parsing", ele, ex);  
    119        }  
    120        finally {  
    121            this.parseState.pop();  
    122        }  
    123        //解析<Bean>元素出错时,返回null  
    124        return null;  
    125    } 
    

            注意:在解析<Bean>元素过程中没有创建和实例化Bean对象,只是创建了Bean对象的定义类BeanDefinition,将<Bean>元素中的配置信息设置到BeanDefinition中作为记录,当依赖注入时才使用这些记录信息创建和实例化具体的Bean对象。

                 上面方法中一些对一些配置如元信息(meta)、qualifier等的解析,我们在Spring中配置时使用的也不多,我们在使用Spring的<Bean>元素时,配置最多的是<property>属性,因此我们下面继续分析源码,了解Bean的属性在解析时是如何设置的。

       

    复制代码
    1    //解析<Bean>元素中的<property>子元素  
    2    public void parsePropertyElements(Element beanEle, BeanDefinition bd) {  
    3        //获取<Bean>元素中所有的子元素  
    4        NodeList nl = beanEle.getChildNodes();  
    5        for (int i = 0; i < nl.getLength(); i++) {  
    6            Node node = nl.item(i);  
    7            //如果子元素是<property>子元素,则调用解析<property>子元素方法解析  
    8            if (isCandidateElement(node) && nodeNameEquals(node, PROPERTY_ELEMENT)) {  
    9                parsePropertyElement((Element) node, bd);  
    10            }  
    11        }  
    12    }  
    13    //解析<property>元素  
    14    public void parsePropertyElement(Element ele, BeanDefinition bd) {  
    15        //获取<property>元素的名字   
    16        String propertyName = ele.getAttribute(NAME_ATTRIBUTE);  
    17        if (!StringUtils.hasLength(propertyName)) {  
    18            error("Tag 'property' must have a 'name' attribute", ele);  
    19            return;  
    20        }  
    21        this.parseState.push(new PropertyEntry(propertyName));  
    22        try {  
    23            //如果一个Bean中已经有同名的property存在,则不进行解析,直接返回。  
    24            //即如果在同一个Bean中配置同名的property,则只有第一个起作用  
    25            if (bd.getPropertyValues().contains(propertyName)) {  
    26                error("Multiple 'property' definitions for property '" + propertyName + "'", ele);  
    27                return;  
    28            }  
    29            //解析获取property的值  
    30            Object val = parsePropertyValue(ele, bd, propertyName);  
    31            //根据property的名字和值创建property实例  
    32            PropertyValue pv = new PropertyValue(propertyName, val);  
    33            //解析<property>元素中的属性  
    34            parseMetaElements(ele, pv);  
    35            pv.setSource(extractSource(ele));  
    36            bd.getPropertyValues().addPropertyValue(pv);  
    37        }  
    38        finally {  
    39            this.parseState.pop();  
    40        }  
    41    }  
    42    //解析获取property值  
    43    public Object parsePropertyValue(Element ele, BeanDefinition bd, String propertyName) {  
    44        String elementName = (propertyName != null) ?  
    45                        "<property> element for property '" + propertyName + "'" :  
    46                        "<constructor-arg> element";  
    47        //获取<property>的所有子元素,只能是其中一种类型:ref,value,list等  
    48        NodeList nl = ele.getChildNodes();  
    49        Element subElement = null;  
    50        for (int i = 0; i < nl.getLength(); i++) {  
    51            Node node = nl.item(i);  
    52            //子元素不是description和meta属性  
    53            if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT) &&  
    54                    !nodeNameEquals(node, META_ELEMENT)) {  
    55                if (subElement != null) {  
    56                    error(elementName + " must not contain more than one sub-element", ele);  
    57                }  
    58                else {//当前<property>元素包含有子元素  
    59                    subElement = (Element) node;  
    60                }  
    61            }  
    62        }  
    63        //判断property的属性值是ref还是value,不允许既是ref又是value  
    64        boolean hasRefAttribute = ele.hasAttribute(REF_ATTRIBUTE);  
    65        boolean hasValueAttribute = ele.hasAttribute(VALUE_ATTRIBUTE);  
    66        if ((hasRefAttribute && hasValueAttribute) ||  
    67                ((hasRefAttribute || hasValueAttribute) && subElement != null)) {  
    68            error(elementName +  
    69                    " is only allowed to contain either 'ref' attribute OR 'value' attribute OR sub-element", ele);  
    70        }  
    71        //如果属性是ref,创建一个ref的数据对象RuntimeBeanReference,这个对象  
    72        //封装了ref信息  
    73        if (hasRefAttribute) {  
    74            String refName = ele.getAttribute(REF_ATTRIBUTE);  
    75            if (!StringUtils.hasText(refName)) {  
    76                error(elementName + " contains empty 'ref' attribute", ele);  
    77            }  
    78            //一个指向运行时所依赖对象的引用  
    79            RuntimeBeanReference ref = new RuntimeBeanReference(refName);  
    80            //设置这个ref的数据对象是被当前的property对象所引用  
    81            ref.setSource(extractSource(ele));  
    82            return ref;  
    83        }  
    84         //如果属性是value,创建一个value的数据对象TypedStringValue,这个对象  
    85        //封装了value信息  
    86        else if (hasValueAttribute) {  
    87            //一个持有String类型值的对象  
    88            TypedStringValue valueHolder = new TypedStringValue(ele.getAttribute(VALUE_ATTRIBUTE));  
    89            //设置这个value数据对象是被当前的property对象所引用  
    90            valueHolder.setSource(extractSource(ele));  
    91            return valueHolder;  
    92        }  
    93        //如果当前<property>元素还有子元素  
    94        else if (subElement != null) {  
    95            //解析<property>的子元素  
    96            return parsePropertySubElement(subElement, bd);  
    97        }  
    98        else {  
    99            //propery属性中既不是ref,也不是value属性,解析出错返回null        error(elementName + " must specify a ref or value", ele);  
    100            return null;  
    101        }  
        } 
    

         通过上述源码分析,我们明白了在Spring配置文件中,对<property>元素中配置的Array、List、Set、Map、Prop等各种集合子元素的都通过上述方法解析,生成对应的数据对象,比如ManagedList、ManagedArray、ManagedSet等,这些Managed类是Spring对象BeanDefiniton的数据封装,对集合数据类型的具体解析有各自的解析方法实现,解析方法的命名非常规范,一目了然,我们对<list>集合元素的解析方法进行源码分析,了解其实现过程。在BeanDefinitionParserDelegate类中的parseListElement方法就是具体实现解析<property>元素中的<list>集合子元素,源码如下:

          

    //解析<list>集合子元素  
    2    public List parseListElement(Element collectionEle, BeanDefinition bd) {  
    3        //获取<list>元素中的value-type属性,即获取集合元素的数据类型  
    4        String defaultElementType = collectionEle.getAttribute(VALUE_TYPE_ATTRIBUTE);  
    5        //获取<list>集合元素中的所有子节点  
    6        NodeList nl = collectionEle.getChildNodes();  
    7        //Spring中将List封装为ManagedList  
    8        ManagedList<Object> target = new ManagedList<Object>(nl.getLength());  
    9        target.setSource(extractSource(collectionEle));  
    10        //设置集合目标数据类型  
    11        target.setElementTypeName(defaultElementType);  
    12        target.setMergeEnabled(parseMergeAttribute(collectionEle));  
    13        //具体的<list>元素解析  
    14        parseCollectionElements(nl, target, bd, defaultElementType);  
    15        return target;  
    16    }   
    17    //具体解析<list>集合元素,<array>、<list>和<set>都使用该方法解析  
    18    protected void parseCollectionElements(  
    19            NodeList elementNodes, Collection<Object> target, BeanDefinition bd, String defaultElementType) {  
    20        //遍历集合所有节点  
    21        for (int i = 0; i < elementNodes.getLength(); i++) {  
    22            Node node = elementNodes.item(i);  
    23            //节点不是description节点  
    24            if (node instanceof Element && !nodeNameEquals(node, DESCRIPTION_ELEMENT)) {  
    25                //将解析的元素加入集合中,递归调用下一个子元素  
    26                target.add(parsePropertySubElement((Element) node, bd, defaultElementType));  
    27            }  
    28        }  
        } 
    

      

             经过对Spring Bean定义资源文件转换的Document对象中的元素层层解析,Spring IoC现在已经将XML形式定义的Bean定义资源文件转换为Spring IoC所识别的数据结构——BeanDefinition,它是Bean定义资源文件中配置的POJO对象在Spring IoC容器中的映射,我们可以通过AbstractBeanDefinition为入口,荣IoC容器进行索引、查询和操作。

    通过Spring IoC容器对Bean定义资源的解析后,IoC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是最为重要的依赖注入还没有发生,现在在IoC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器注册Bean定义信息才能全部完成IoC容器的初始化过程

     

              3接下来是注册过程

               DefaultBeanDefinitionDocumentReader对Bean定义转换的Document对象解析的流程中,在其parseDefaultElement方法中完成对Document对象的解析后得到封装BeanDefinition的BeanDefinitionHold对象,然后调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean,BeanDefinitionReaderUtils的注册的源码如下:

               

    //将解析的BeanDefinitionHold注册到容器中 
    public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)  
        throws BeanDefinitionStoreException {  
            //获取解析的BeanDefinition的名称
             String beanName = definitionHolder.getBeanName();  
            //向IoC容器注册BeanDefinition 
            registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());  
            //如果解析的BeanDefinition有别名,向容器为其注册别名  
             String[] aliases = definitionHolder.getAliases();  
            if (aliases != null) {  
                for (String aliase : aliases) {  
                    registry.registerAlias(beanName, aliase);  
                }  
            }  
    }

           

              registerBeanDefinition方法在DefaultListableBeanFactory,它中使用一个HashMap的集合对象存放IoC容器中注册解析的BeanDefinition,向IoC容器注册的主要代码为:
    //存储注册的俄BeanDefinition  
    2    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();  
    3    //向IoC容器注册解析的BeanDefiniton  
    4    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)  
    5            throws BeanDefinitionStoreException {  
    6        Assert.hasText(beanName, "Bean name must not be empty");  
    7        Assert.notNull(beanDefinition, "BeanDefinition must not be null");  
    8        //校验解析的BeanDefiniton  
    9        if (beanDefinition instanceof AbstractBeanDefinition) {  
    10            try {  
    11                ((AbstractBeanDefinition) beanDefinition).validate();  
    12            }  
    13            catch (BeanDefinitionValidationException ex) {  
    14                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
    15                        "Validation of bean definition failed", ex);  
    16            }  
    17        }  
    18        //注册的过程中需要线程同步,以保证数据的一致性  
    19        synchronized (this.beanDefinitionMap) {  
    20            Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);  
    21            //检查是否有同名的BeanDefinition已经在IoC容器中注册,如果已经注册,  
    22            //并且不允许覆盖已注册的Bean,则抛出注册失败异常  
    23            if (oldBeanDefinition != null) {  
    24                if (!this.allowBeanDefinitionOverriding) {  
    25                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,  
    26                            "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +  
    27                            "': There is already [" + oldBeanDefinition + "] bound.");  
    28                }  
    29                else {//如果允许覆盖,则同名的Bean,后注册的覆盖先注册的  
    30                    if (this.logger.isInfoEnabled()) {  
    31                        this.logger.info("Overriding bean definition for bean '" + beanName +  
    32                                "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");  
    33                    }  
    34                }  
    35            }  
    36            //IoC容器中没有已经注册同名的Bean,按正常注册流程注册  
    37            else {  
    38                this.beanDefinitionNames.add(beanName);  
    39                this.frozenBeanDefinitionNames = null;  
    40            }  
    41            this.beanDefinitionMap.put(beanName, beanDefinition);  
    42            //重置所有已经注册过的BeanDefinition的缓存  
    43            resetBeanDefinition(beanName);  
    44        }  
        } 
    复制代码
    

       至此,Bean定义资源文件中配置的Bean被解析过后,已经注册到IoC容器中,被容器管理起来,真正完成了IoC容器初始化所做的全部工作。现  在IoC容器中已经建立了整个Bean的配置信息,这些BeanDefinition信息已经可以使用,并且可以被检索,IoC容器的作用就是对这些注册的Bean定义信息进行处理和维护。这些的注册的Bean定义信息是IoC容器控制反转的基础,正是有了这些注册的数据,容器才可以进行依赖注入。

          

         (4)依赖注入

           1

           当Spring IoC容器完成了Bean定义资源的定位、载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入,依赖注入在以下两种情况发生:

    (1).用户第一次通过getBean方法向IoC容索要Bean时,IoC容器触发依赖注入。

    (2).当用户在Bean定义资源中为<Bean>元素配置了lazy-init属性,即让容器在解析注册Bean定义时进行预实例化,触发依赖注入。

    BeanFactory接口定义了Spring IoC容器的基本功能规范,是Spring IoC容器所应遵守的最底层和最基本的编程规范。BeanFactory接口中定义了几个getBean方法,就是用户向IoC容器索取管理的Bean的方法,我们通过分析其子类的具体实现,理解Spring IoC容器在用户索取Bean时如何完成依赖注入。

      在BeanFactory中我们看到getBeanString…)函数,它的具体实现在AbstractBeanFactory

           

       

         具体代码为

    package org.springframework.beans.factory.support;

    import org.springframework.beans.factory.BeanFactory;



    1 //获取IoC容器中指定名称的Bean 2 public Object getBean(String name) throws BeansException { 3 //doGetBean才是真正向IoC容器获取被管理Bean的过程 4 return doGetBean(name, null, null, false); 5 } 6 //获取IoC容器中指定名称和类型的Bean 7 public <T> T getBean(String name, Class<T> requiredType) throws BeansException { 8 //doGetBean才是真正向IoC容器获取被管理Bean的过程 9 return doGetBean(name, requiredType, null, false); 10 } 11 //获取IoC容器中指定名称和参数的Bean 12 public Object getBean(String name, Object... args) throws BeansException { 13 //doGetBean才是真正向IoC容器获取被管理Bean的过程 14 return doGetBean(name, null, args, false); 15 } 16 //获取IoC容器中指定名称、类型和参数的Bean 17 public <T> T getBean(String name, Class<T> requiredType, Object... args) throws BeansException { 18 //doGetBean才是真正向IoC容器获取被管理Bean的过程 19 return doGetBean(name, requiredType, args, false); 20 } 21 //真正实现向IoC容器获取Bean的功能,也是触发依赖注入功能的地方 22 @SuppressWarnings("unchecked") 23 protected <T> T doGetBean( 24 final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly) 25 throws BeansException { 26 //根据指定的名称获取被管理Bean的名称,剥离指定名称中对容器的相关依赖 27 //如果指定的是别名,将别名转换为规范的Bean名称 28 final String beanName = transformedBeanName(name); 29 Object bean; 30 //先从缓存中取是否已经有被创建过的单态类型的Bean,对于单态模式的Bean整 31 //个IoC容器中只创建一次,不需要重复创建 32 Object sharedInstance = getSingleton(beanName); 33 //IoC容器创建单态模式Bean实例对象 34 if (sharedInstance != null && args == null) { 35 if (logger.isDebugEnabled()) { 36 //如果指定名称的Bean在容器中已有单态模式的Bean被创建,直接返回 37 //已经创建的Bean 38 if (isSingletonCurrentlyInCreation(beanName)) { 39 logger.debug("Returning eagerly cached instance of singleton bean '" + beanName + 40 "' that is not fully initialized yet - a consequence of a circular reference"); 41 } 42 else { 43 logger.debug("Returning cached instance of singleton bean '" + beanName + "'"); 44 } 45 } 46 //获取给定Bean的实例对象,主要是完成FactoryBean的相关处理 47 //注意:BeanFactory是管理容器中Bean的工厂,而FactoryBean是 48 //创建创建对象的工厂Bean,两者之间有区别 49 bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); 50 } 51 else {//缓存没有正在创建的单态模式Bean 52 //缓存中已经有已经创建的原型模式Bean,但是由于循环引用的问题导致实 53 //例化对象失败 54 if (isPrototypeCurrentlyInCreation(beanName)) { 55 throw new BeanCurrentlyInCreationException(beanName); 56 } 57 //对IoC容器中是否存在指定名称的BeanDefinition进行检查,首先检查是否 58 //能在当前的BeanFactory中获取的所需要的Bean,如果不能则委托当前容器 59 //的父级容器去查找,如果还是找不到则沿着容器的继承体系向父级容器查找 60 BeanFactory parentBeanFactory = getParentBeanFactory(); 61 //当前容器的父级容器存在,且当前容器中不存在指定名称的Bean 62 if (parentBeanFactory != null && !containsBeanDefinition(beanName)) { 63 //解析指定Bean名称的原始名称 64 String nameToLookup = originalBeanName(name); 65 if (args != null) { 66 //委派父级容器根据指定名称和显式的参数查找 67 return (T) parentBeanFactory.getBean(nameToLookup, args); 68 } 69 else { 70 //委派父级容器根据指定名称和类型查找 71 return parentBeanFactory.getBean(nameToLookup, requiredType); 72 } 73 } 74 //创建的Bean是否需要进行类型验证,一般不需要 75 if (!typeCheckOnly) { 76 //向容器标记指定的Bean已经被创建 77 markBeanAsCreated(beanName); 78 } 79 //根据指定Bean名称获取其父级的Bean定义,主要解决Bean继承时子类 80 //合并父类公共属性问题 81 final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); 82 checkMergedBeanDefinition(mbd, beanName, args); 83 //获取当前Bean所有依赖Bean的名称 84 String[] dependsOn = mbd.getDependsOn(); 85 //如果当前Bean有依赖Bean 86 if (dependsOn != null) { 87 for (String dependsOnBean : dependsOn) { 88 //递归调用getBean方法,获取当前Bean的依赖Bean 89 getBean(dependsOnBean); 90 //把被依赖Bean注册给当前依赖的Bean 91 registerDependentBean(dependsOnBean, beanName); 92 } 93 } 94 //创建单态模式Bean的实例对象 95 if (mbd.isSingleton()) { 96 //这里使用了一个匿名内部类,创建Bean实例对象,并且注册给所依赖的对象 97 sharedInstance = getSingleton(beanName, new ObjectFactory() { 98 public Object getObject() throws BeansException { 99 try { 100 //创建一个指定Bean实例对象,如果有父级继承,则合并子//类和父类的定义 101 return createBean(beanName, mbd, args); 102 } 103 catch (BeansException ex) { 104 //显式地从容器单态模式Bean缓存中清除实例对象 105 destroySingleton(beanName); 106 throw ex; 107 } 108 } 109 }); 110 //获取给定Bean的实例对象 111 bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); 112 } 113 //IoC容器创建原型模式Bean实例对象 114 else if (mbd.isPrototype()) { 115 //原型模式(Prototype)是每次都会创建一个新的对象 116 Object prototypeInstance = null; 117 try { 118 //回调beforePrototypeCreation方法,默认的功能是注册当前创//建的原型对象 119 beforePrototypeCreation(beanName); 120 //创建指定Bean对象实例 121 prototypeInstance = createBean(beanName, mbd, args); 122 } 123 finally { 124 //回调afterPrototypeCreation方法,默认的功能告诉IoC容器指//定Bean的原型对象不再创建了 125 afterPrototypeCreation(beanName); 126 } 127 //获取给定Bean的实例对象 128 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); 129 } 130 //要创建的Bean既不是单态模式,也不是原型模式,则根据Bean定义资源中 131 //配置的生命周期范围,选择实例化Bean的合适方法,这种在Web应用程序中 132 //比较常用,如:request、session、application等生命周期 133 else { 134 String scopeName = mbd.getScope(); 135 final Scope scope = this.scopes.get(scopeName); 136 //Bean定义资源中没有配置生命周期范围,则Bean定义不合法 137 if (scope == null) { 138 throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'"); 139 } 140 try { 141 //这里又使用了一个匿名内部类,获取一个指定生命周期范围的实例 142 Object scopedInstance = scope.get(beanName, new ObjectFactory() { 143 public Object getObject() throws BeansException { 144 beforePrototypeCreation(beanName); 145 try { 146 return createBean(beanName, mbd, args); 147 } 148 finally { 149 afterPrototypeCreation(beanName); 150 } 151 } 152 }); 153 //获取给定Bean的实例对象 154 bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd); 155 } 156 catch (IllegalStateException ex) { 157 throw new BeanCreationException(beanName, 158 "Scope '" + scopeName + "' is not active for the current thread; " + 159 "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton", 160 ex); 161 } 162 } 163 } 164 //对创建的Bean实例对象进行类型检查 165 if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) { 166 throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass()); 167 } 168 return (T) bean; 169 }

      

              通过上面对向IoC容器获取Bean方法的分析,我们可以看到在Spring中,如果Bean定义的单态模式(Singleton),则容器在创建之前先从缓存中查找,以确保整个容器中只存在一个实例对象。如果Bean定义的是原型模式(Prototype),则容器每次都会创建一个新的实例对象。除此之外,Bean定义还可以扩展为指定其生命周期范围。

             2

             上面的源码只是定义了根据Bean定义的模式,采取的不同创建Bean实例对象的策略,具体的Bean实例对象的创建过程由实现了ObejctFactory接口的匿名内部类的createBean方法完成,ObejctFactory使用委派模式,具体的Bean实例创建过程交由其实现类AbstractAutowireCapableBeanFactory完成,我们继续分析AbstractAutowireCapableBeanFactory的createBean方法的源码,理解其创建Bean实例的具体实现过程。

            AbstractAutowireCapableBeanFactory类实现了ObejctFactory接口,创建容器指定的Bean实例对象,同时还对创建的Bean实例对象进行初始化处理。其创建Bean实例对象的方法源码如下:

             

    1    //创建Bean实例对象  
    2    protected Object createBean(final String beanName, final RootBeanDefinition mbd, final Object[] args)  
    3            throws BeanCreationException {  
    4        if (logger.isDebugEnabled()) {  
    5            logger.debug("Creating instance of bean '" + beanName + "'");  
    6        }  
    7        //判断需要创建的Bean是否可以实例化,即是否可以通过当前的类加载器加载  
    8        resolveBeanClass(mbd, beanName);  
    9        //校验和准备Bean中的方法覆盖  
    10        try {  
    11            mbd.prepareMethodOverrides();  
    12        }  
    13        catch (BeanDefinitionValidationException ex) {  
    14            throw new BeanDefinitionStoreException(mbd.getResourceDescription(),  
    15                    beanName, "Validation of method overrides failed", ex);  
    16        }  
    17        try {  
    18            //如果Bean配置了初始化前和初始化后的处理器,则试图返回一个需要创建//Bean的代理对象  
    19            Object bean = resolveBeforeInstantiation(beanName, mbd);  
    20            if (bean != null) {  
    21                return bean;  
    22            }  
    23        }  
    24        catch (Throwable ex) {  
    25            throw new BeanCreationException(mbd.getResourceDescription(), beanName,  
    26                    "BeanPostProcessor before instantiation of bean failed", ex);  
    27        }  
    28        //创建Bean的入口  
    29        Object beanInstance = doCreateBean(beanName, mbd, args);  
    30        if (logger.isDebugEnabled()) {  
    31            logger.debug("Finished creating instance of bean '" + beanName + "'");  
    32        }  
    33        return beanInstance;  
    34    }  
    35    //真正创建Bean的方法  
    36    protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {  
    37        //封装被创建的Bean对象  
    38        BeanWrapper instanceWrapper = null;  
    39        if (mbd.isSingleton()){//单态模式的Bean,先从容器中缓存中获取同名Bean  
    40            instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);  
    41        }  
    42        if (instanceWrapper == null) {  
    43            //创建实例对象  
    44            instanceWrapper = createBeanInstance(beanName, mbd, args);  
    45        }  
    46        final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);  
    47        //获取实例化对象的类型  
    48        Class beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);  
    49        //调用PostProcessor后置处理器  
    50        synchronized (mbd.postProcessingLock) {  
    51            if (!mbd.postProcessed) {  
    52                applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);  
    53                mbd.postProcessed = true;  
    54            }  
    55        }  
    56        // Eagerly cache singletons to be able to resolve circular references  
    57        //向容器中缓存单态模式的Bean对象,以防循环引用  
    58        boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&  
    59                isSingletonCurrentlyInCreation(beanName));  
    60        if (earlySingletonExposure) {  
    61            if (logger.isDebugEnabled()) {  
    62                logger.debug("Eagerly caching bean '" + beanName +  
    63                        "' to allow for resolving potential circular references");  
    64            }  
    65            //这里是一个匿名内部类,为了防止循环引用,尽早持有对象的引用  
    66            addSingletonFactory(beanName, new ObjectFactory() {  
    67                public Object getObject() throws BeansException {  
    68                    return getEarlyBeanReference(beanName, mbd, bean);  
    69                }  
    70            });  
    71        }  
    72        //Bean对象的初始化,依赖注入在此触发  
    73        //这个exposedObject在初始化完成之后返回作为依赖注入完成后的Bean  
    74        Object exposedObject = bean;  
    75        try {  
    76            //将Bean实例对象封装,并且Bean定义中配置的属性值赋值给实例对象  
    77            populateBean(beanName, mbd, instanceWrapper);  
    78            if (exposedObject != null) {  
    79                //初始化Bean对象  
    80                exposedObject = initializeBean(beanName, exposedObject, mbd);  
    81            }  
    82        }  
    83        catch (Throwable ex) {  
    84            if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {  
    85                throw (BeanCreationException) ex;  
    86            }  
    87            else {  
    88                throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);  
    89            }  
    90        }  
    91        if (earlySingletonExposure) {  
    92            //获取指定名称的已注册的单态模式Bean对象  
    93            Object earlySingletonReference = getSingleton(beanName, false);  
    94            if (earlySingletonReference != null) {  
    95                //根据名称获取的以注册的Bean和正在实例化的Bean是同一个  
    96                if (exposedObject == bean) {  
    97                    //当前实例化的Bean初始化完成  
    98                    exposedObject = earlySingletonReference;  
    99                }  
    100                //当前Bean依赖其他Bean,并且当发生循环引用时不允许新创建实例对象  
    101                else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {  
    102                    String[] dependentBeans = getDependentBeans(beanName);  
    103                    Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);  
    104                    //获取当前Bean所依赖的其他Bean  
    105                    for (String dependentBean : dependentBeans) {  
    106                        //对依赖Bean进行类型检查  
    107                        if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {  
    108                            actualDependentBeans.add(dependentBean);  
    109                        }  
    110                    }  
    111                    if (!actualDependentBeans.isEmpty()) {  
    112                        throw new BeanCurrentlyInCreationException(beanName,  
    113                                "Bean with name '" + beanName + "' has been injected into other beans [" +  
    114                                StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +  
    115                                "] in its raw version as part of a circular reference, but has eventually been " +  
    116                                "wrapped. This means that said other beans do not use the final version of the " +  
    117                                "bean. This is often the result of over-eager type matching - consider using " +  
    118                                "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");  
    119                    }  
    120                }  
    121            }  
    122        }  
    123        //注册完成依赖注入的Bean  
    124        try {  
    125            registerDisposableBeanIfNecessary(beanName, bean, mbd);  
    126        }  
    127        catch (BeanDefinitionValidationException ex) {  
    128            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);  
    129        }  
    130        return exposedObject;  
        } 
    

      

    下面继续分析这两个方法的代码实现。

          3

                createBeanInstance方法创建Bean的java实例对象:

                     在createBeanInstance方法中,根据指定的初始化策略,使用静态工厂、工厂方法或者容器的自动装配特性生成java实例对象,创建对象的源码如下:

      通过对方法源码的分析,我们看到具体的依赖注入实现在以下两个方法中:

             (1).createBeanInstance:生成Bean所包含的java对象实例。

             (2).populateBean :对Bean属性的依赖注入进行处理。

                   

    1    //创建Bean的实例对象  
    2    protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, Object[] args) {  
    3        //检查确认Bean是可实例化的  
    4        Class beanClass = resolveBeanClass(mbd, beanName);  
    5        //使用工厂方法对Bean进行实例化  
    6        if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {  
    7            throw new BeanCreationException(mbd.getResourceDescription(), beanName,  
    8                    "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());  
    9        }  
    10        if (mbd.getFactoryMethodName() != null)  {  
    11            //调用工厂方法实例化  
    12            return instantiateUsingFactoryMethod(beanName, mbd, args);  
    13        }  
    14        //使用容器的自动装配方法进行实例化  
    15        boolean resolved = false;  
    16        boolean autowireNecessary = false;  
    17        if (args == null) {  
    18            synchronized (mbd.constructorArgumentLock) {  
    19                if (mbd.resolvedConstructorOrFactoryMethod != null) {  
    20                    resolved = true;  
    21                    autowireNecessary = mbd.constructorArgumentsResolved;  
    22                }  
    23            }  
    24        }  
    25        if (resolved) {  
    26            if (autowireNecessary) {  
    27                //配置了自动装配属性,使用容器的自动装配实例化  
    28                //容器的自动装配是根据参数类型匹配Bean的构造方法  
    29                return autowireConstructor(beanName, mbd, null, null);  
    30            }  
    31            else {  
    32                //使用默认的无参构造方法实例化  
    33                return instantiateBean(beanName, mbd);  
    34            }  
    35        }  
    36        //使用Bean的构造方法进行实例化  
    37        Constructor[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);  
    38        if (ctors != null ||  
    39                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||  
    40                mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {  
    41            //使用容器的自动装配特性,调用匹配的构造方法实例化  
    42            return autowireConstructor(beanName, mbd, ctors, args);  
    43        }  
    44        //使用默认的无参构造方法实例化  
    45        return instantiateBean(beanName, mbd);  
    46    }   
    47    //使用默认的无参构造方法实例化Bean对象  
    48    protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {  
    49        try {  
    50            Object beanInstance;  
    51            final BeanFactory parent = this;  
    52            //获取系统的安全管理接口,JDK标准的安全管理API  
    53            if (System.getSecurityManager() != null) {  
    54                //这里是一个匿名内置类,根据实例化策略创建实例对象  
    55                beanInstance = AccessController.doPrivileged(new PrivilegedAction<Object>() {  
    56                    public Object run() {  
    57                        return getInstantiationStrategy().instantiate(mbd, beanName, parent);  
    58                    }  
    59                }, getAccessControlContext());  
    60            }  
    61            else {  
    62                //将实例化的对象封装起来  
    63                beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);  
    64            }  
    65            BeanWrapper bw = new BeanWrapperImpl(beanInstance);  
    66            initBeanWrapper(bw);  
    67            return bw;  
    68        }  
    69        catch (Throwable ex) {  
    70            throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);  
    71        }  
    72    }
    

          我们最常使用的默认无参构造方法就需要使用相应的初始化策略(JDK的反射机制或者CGLIB)来进行初始化了,在方法getInstantiationStrategy().instantiate中就具体实现类使用初始策略实例化对象。   

            方法getInstantiationStrategy().instantiate调用了SimpleInstantiationStrategy类中的实例化Bean的方法,其源码如下:

    1    //使用初始化策略实例化Bean对象  
    2    public Object instantiate(RootBeanDefinition beanDefinition, String beanName, BeanFactory owner) {  
    3        //如果Bean定义中没有方法覆盖,则就不需要CGLIB父类类的方法  
    4        if (beanDefinition.getMethodOverrides().isEmpty()) {  
    5            Constructor<?> constructorToUse;  
    6            synchronized (beanDefinition.constructorArgumentLock) {  
    7                //获取对象的构造方法或工厂方法  
    8                constructorToUse = (Constructor<?>) beanDefinition.resolvedConstructorOrFactoryMethod;  
    9                //如果没有构造方法且没有工厂方法  
    10                if (constructorToUse == null) {  
    11                    //使用JDK的反射机制,判断要实例化的Bean是否是接口  
    12                    final Class clazz = beanDefinition.getBeanClass();  
    13                    if (clazz.isInterface()) {  
    14                        throw new BeanInstantiationException(clazz, "Specified class is an interface");  
    15                    }  
    16                    try {  
    17                        if (System.getSecurityManager() != null) {  
    18                        //这里是一个匿名内置类,使用反射机制获取Bean的构造方法  
    19                            constructorToUse = AccessController.doPrivileged(new PrivilegedExceptionAction<Constructor>() {  
    20                                public Constructor run() throws Exception {  
    21                                    return clazz.getDeclaredConstructor((Class[]) null);  
    22                                }  
    23                            });  
    24                        }  
    25                        else {  
    26                            constructorToUse =  clazz.getDeclaredConstructor((Class[]) null);  
    27                        }  
    28                        beanDefinition.resolvedConstructorOrFactoryMethod = constructorToUse;  
    29                    }  
    30                    catch (Exception ex) {  
    31                        throw new BeanInstantiationException(clazz, "No default constructor found", ex);  
    32                    }  
    33                }  
    34            }  
    35            //使用BeanUtils实例化,通过反射机制调用”构造方法.newInstance(arg)”来进行实例化  
    36            return BeanUtils.instantiateClass(constructorToUse);  
    37        }  
    38        else {  
    39            //使用CGLIB来实例化对象  
    40            return instantiateWithMethodInjection(beanDefinition, beanName, owner);  
    41        }  
        } 
    

      

             通过上面的代码分析,我们看到了如果Bean有方法被覆盖了,则使用JDK的反射机制进行实例化,否则,使用CGLIB进行实例化。

    instantiateWithMethodInjection方法调用SimpleInstantiationStrategy的子类CglibSubclassingInstantiationStrategy使用CGLIB来进行初始化,其源码如下:

    1    //使用CGLIB进行Bean对象实例化  
    2    public Object instantiate(Constructor ctor, Object[] args) {  
    3            //CGLIB中的类  
    4            Enhancer enhancer = new Enhancer();  
    5            //将Bean本身作为其基类  
    6            enhancer.setSuperclass(this.beanDefinition.getBeanClass());  
    7            enhancer.setCallbackFilter(new CallbackFilterImpl());  
    8            enhancer.setCallbacks(new Callback[] {  
    9                    NoOp.INSTANCE,  
    10                    new LookupOverrideMethodInterceptor(),  
    11                    new ReplaceOverrideMethodInterceptor()  
    12            });  
    13            //使用CGLIB的create方法生成实例对象  
    14            return (ctor == null) ?   
    15                    enhancer.create() :   
    16                    enhancer.create(ctor.getParameterTypes(), args);  
    17        } 
    复制代码
    

         CGLIB是一个常用的字节码生成器的类库,它提供了一系列API实现java字节码的生成和转换功能。我们在学习JDK的动态代理时都知道,JDK的动态代理只能针对接口,如果一个类没有实现任何接口,要对其进行动态代理只能使用CGLIB。

             我们已经分析了容器初始化生成Bean所包含的Java实例对象的过程,现在我们继续分析生成对象后,Spring IoC容器是如何将Bean的属性依赖关系注入Bean实例对象中并设置好的,属性依赖注入的代码如下:

              

    1    //将Bean属性设置到生成的实例对象上  
    2    protected void populateBean(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw) {  
    3        //获取容器在解析Bean定义资源时为BeanDefiniton中设置的属性值  
    4        PropertyValues pvs = mbd.getPropertyValues();  
    5        //实例对象为null  
    6        if (bw == null) {  
    7            //属性值不为空  
    8            if (!pvs.isEmpty()) {  
    9                throw new BeanCreationException(  
    10                        mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");  
    11            }  
    12            else {  
    13                //实例对象为null,属性值也为空,不需要设置属性值,直接返回  
    14                return;  
    15            }  
    16        }  
    17        //在设置属性之前调用Bean的PostProcessor后置处理器  
    18        boolean continueWithPropertyPopulation = true;  
    19        if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {  
    20            for (BeanPostProcessor bp : getBeanPostProcessors()) {  
    21                if (bp instanceof InstantiationAwareBeanPostProcessor) {  
    22                    InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;  
    23                    if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {  
    24                        continueWithPropertyPopulation = false;  
    25                        break;  
    26                    }  
    27                }  
    28            }  
    29        }  
    30        if (!continueWithPropertyPopulation) {  
    31            return;  
    32        }  
    33        //依赖注入开始,首先处理autowire自动装配的注入  
    34        if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||  
    35                mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
    36            MutablePropertyValues newPvs = new MutablePropertyValues(pvs);  
    37            //对autowire自动装配的处理,根据Bean名称自动装配注入  
    38            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {  
    39                autowireByName(beanName, mbd, bw, newPvs);  
    40            }  
    41            //根据Bean类型自动装配注入  
    42            if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {  
    43                autowireByType(beanName, mbd, bw, newPvs);  
    44            }  
    45            pvs = newPvs;  
    46        }  
    47        //检查容器是否持有用于处理单态模式Bean关闭时的后置处理器  
    48        boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();  
    49        //Bean实例对象没有依赖,即没有继承基类  
    50        boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);  
    51        if (hasInstAwareBpps || needsDepCheck) {  
    52            //从实例对象中提取属性描述符  
    53            PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw);  
    54            if (hasInstAwareBpps) {  
    55                for (BeanPostProcessor bp : getBeanPostProcessors()) {  
    56                    if (bp instanceof InstantiationAwareBeanPostProcessor) {  
    57                        InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;  
    58                        //使用BeanPostProcessor处理器处理属性值  
    59                        pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);  
    60                        if (pvs == null) {  
    61                            return;  
    62                        }  
    63                    }  
    64                }  
    65            }  
    66            if (needsDepCheck) {  
    67                //为要设置的属性进行依赖检查  
    68                checkDependencies(beanName, mbd, filteredPds, pvs);  
    69            }  
    70        }  
    71        //对属性进行注入  
    72        applyPropertyValues(beanName, mbd, bw, pvs);  
    73    }  
    74    //解析并注入依赖属性的过程  
    75    protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {  
    76        if (pvs == null || pvs.isEmpty()) {  
    77            return;  
    78        }  
    79        //封装属性值  
    80        MutablePropertyValues mpvs = null;  
    81        List<PropertyValue> original;  
    82        if (System.getSecurityManager()!= null) {  
    83            if (bw instanceof BeanWrapperImpl) {  
    84                //设置安全上下文,JDK安全机制  
    85                ((BeanWrapperImpl) bw).setSecurityContext(getAccessControlContext());  
    86            }  
    87        }  
    88        if (pvs instanceof MutablePropertyValues) {  
    89            mpvs = (MutablePropertyValues) pvs;  
    90            //属性值已经转换  
    91            if (mpvs.isConverted()) {  
    92                try {  
    93                    //为实例化对象设置属性值  
    94                    bw.setPropertyValues(mpvs);  
    95                    return;  
    96                }  
    97                catch (BeansException ex) {  
    98                    throw new BeanCreationException(  
    99                            mbd.getResourceDescription(), beanName, "Error setting property values", ex);  
    100                }  
    101            }  
    102            //获取属性值对象的原始类型值  
    103            original = mpvs.getPropertyValueList();  
    104        }  
    105        else {  
    106            original = Arrays.asList(pvs.getPropertyValues());  
    107        }  
    108        //获取用户自定义的类型转换  
    109        TypeConverter converter = getCustomTypeConverter();  
    110        if (converter == null) {  
    111            converter = bw;  
    112        }  
    113        //创建一个Bean定义属性值解析器,将Bean定义中的属性值解析为Bean实例对象  
    114        //的实际值  
    115        BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);  
    116        //为属性的解析值创建一个拷贝,将拷贝的数据注入到实例对象中  
    117        List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());  
    118        boolean resolveNecessary = false;  
    119        for (PropertyValue pv : original) {  
    120            //属性值不需要转换  
    121            if (pv.isConverted()) {  
    122                deepCopy.add(pv);  
    123            }  
    124            //属性值需要转换  
    125            else {  
    126                String propertyName = pv.getName();  
    127                //原始的属性值,即转换之前的属性值  
    128                Object originalValue = pv.getValue();  
    129                //转换属性值,例如将引用转换为IoC容器中实例化对象引用  
    130                Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);  
    131                //转换之后的属性值  
    132                Object convertedValue = resolvedValue;  
    133                //属性值是否可以转换  
    134                boolean convertible = bw.isWritableProperty(propertyName) &&  
    135                        !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);  
    136                if (convertible) {  
    137                    //使用用户自定义的类型转换器转换属性值  
    138                    convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);  
    139                }  
    140                //存储转换后的属性值,避免每次属性注入时的转换工作  
    141                if (resolvedValue == originalValue) {  
    142                    if (convertible) {  
    143                        //设置属性转换之后的值  
    144                        pv.setConvertedValue(convertedValue);  
    145                    }  
    146                    deepCopy.add(pv);  
    147                }  
    148                //属性是可转换的,且属性原始值是字符串类型,且属性的原始类型值不是  
    149                //动态生成的字符串,且属性的原始值不是集合或者数组类型  
    150                else if (convertible && originalValue instanceof TypedStringValue &&  
    151                        !((TypedStringValue) originalValue).isDynamic() &&  
    152                        !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {  
    153                    pv.setConvertedValue(convertedValue);  
    154                    deepCopy.add(pv);  
    155                }  
    156                else {  
    157                    resolveNecessary = true;  
    158                    //重新封装属性的值  
    159                    deepCopy.add(new PropertyValue(pv, convertedValue));  
    160                }  
    161            }  
    162        }  
    163        if (mpvs != null && !resolveNecessary) {  
    164            //标记属性值已经转换过  
    165            mpvs.setConverted();  
    166        }  
    167        //进行属性依赖注入  
    168        try {  
    169            bw.setPropertyValues(new MutablePropertyValues(deepCopy));  
    170        }  
    171        catch (BeansException ex) {  
    172            throw new BeanCreationException(  
    173                    mbd.getResourceDescription(), beanName, "Error setting property values", ex);  
    174        }  
        }  
    

      

             对属性的注入过程分以下两种情况:

           (1).属性值类型不需要转换时,不需要解析属性值,直接准备进行依赖注入。

           (2).属性值需要进行类型转换时,如对其他对象的引用等,首先需要解析属性值,然后对解析后的属性值进行依赖注入。

            对属性值的解析是在BeanDefinitionValueResolver类中的resolveValueIfNecessary方法中进行的,对属性值的依赖注入是通过bw.setPropertyValues方法实现的,在分析属性值的依赖注入之前,我们先分析一下对属性值的解析过程。

            

    1    //解析属性值,对注入类型进行转换  
    2    public Object resolveValueIfNecessary(Object argName, Object value) {  
    3        //对引用类型的属性进行解析  
    4        if (value instanceof RuntimeBeanReference) {  
    5            RuntimeBeanReference ref = (RuntimeBeanReference) value;  
    6            //调用引用类型属性的解析方法  
    7            return resolveReference(argName, ref);  
    8        }  
    9        //对属性值是引用容器中另一个Bean名称的解析  
    10        else if (value instanceof RuntimeBeanNameReference) {  
    11            String refName = ((RuntimeBeanNameReference) value).getBeanName();  
    12            refName = String.valueOf(evaluate(refName));  
    13            //从容器中获取指定名称的Bean  
    14            if (!this.beanFactory.containsBean(refName)) {  
    15                throw new BeanDefinitionStoreException(  
    16                        "Invalid bean name '" + refName + "' in bean reference for " + argName);  
    17            }  
    18            return refName;  
    19        }  
    20        //对Bean类型属性的解析,主要是Bean中的内部类  
    21        else if (value instanceof BeanDefinitionHolder) {  
    22            BeanDefinitionHolder bdHolder = (BeanDefinitionHolder) value;  
    23            return resolveInnerBean(argName, bdHolder.getBeanName(), bdHolder.getBeanDefinition());  
    24        }  
    25        else if (value instanceof BeanDefinition) {  
    26            BeanDefinition bd = (BeanDefinition) value;  
    27            return resolveInnerBean(argName, "(inner bean)", bd);  
    28        }  
    29        //对集合数组类型的属性解析  
    30        else if (value instanceof ManagedArray) {  
    31            ManagedArray array = (ManagedArray) value;  
    32            //获取数组的类型  
    33            Class elementType = array.resolvedElementType;  
    34            if (elementType == null) {  
    35                //获取数组元素的类型  
    36                String elementTypeName = array.getElementTypeName();  
    37                if (StringUtils.hasText(elementTypeName)) {  
    38                    try {  
    39                        //使用反射机制创建指定类型的对象  
    40                        elementType = ClassUtils.forName(elementTypeName, this.beanFactory.getBeanClassLoader());  
    41                        array.resolvedElementType = elementType;  
    42                    }  
    43                    catch (Throwable ex) {  
    44                        throw new BeanCreationException(  
    45                                this.beanDefinition.getResourceDescription(), this.beanName,  
    46                                "Error resolving array type for " + argName, ex);  
    47                    }  
    48                }  
    49                //没有获取到数组的类型,也没有获取到数组元素的类型,则直接设置数  
    50                //组的类型为Object  
    51                else {  
    52                    elementType = Object.class;  
    53                }  
    54            }  
    55            //创建指定类型的数组  
    56            return resolveManagedArray(argName, (List<?>) value, elementType);  
    57        }  
    58        //解析list类型的属性值  
    59        else if (value instanceof ManagedList) {  
    60            return resolveManagedList(argName, (List<?>) value);  
    61        }  
    62        //解析set类型的属性值  
    63        else if (value instanceof ManagedSet) {  
    64            return resolveManagedSet(argName, (Set<?>) value);  
    65        }  
    66        //解析map类型的属性值  
    67        else if (value instanceof ManagedMap) {  
    68            return resolveManagedMap(argName, (Map<?, ?>) value);  
    69        }  
    70        //解析props类型的属性值,props其实就是key和value均为字符串的map  
    71        else if (value instanceof ManagedProperties) {  
    72            Properties original = (Properties) value;  
    73            //创建一个拷贝,用于作为解析后的返回值  
    74            Properties copy = new Properties();  
    75            for (Map.Entry propEntry : original.entrySet()) {  
    76                Object propKey = propEntry.getKey();  
    77                Object propValue = propEntry.getValue();  
    78                if (propKey instanceof TypedStringValue) {  
    79                    propKey = evaluate((TypedStringValue) propKey);  
    80                }  
    81                if (propValue instanceof TypedStringValue) {  
    82                    propValue = evaluate((TypedStringValue) propValue);  
    83                }  
    84                copy.put(propKey, propValue);  
    85            }  
    86            return copy;  
    87        }  
    88        //解析字符串类型的属性值  
    89        else if (value instanceof TypedStringValue) {  
    90            TypedStringValue typedStringValue = (TypedStringValue) value;  
    91            Object valueObject = evaluate(typedStringValue);  
    92            try {  
    93                //获取属性的目标类型  
    94                Class<?> resolvedTargetType = resolveTargetType(typedStringValue);  
    95                if (resolvedTargetType != null) {  
    96                    //对目标类型的属性进行解析,递归调用  
    97                    return this.typeConverter.convertIfNecessary(valueObject, resolvedTargetType);  
    98                }  
    99                //没有获取到属性的目标对象,则按Object类型返回  
    100                else {  
    101                    return valueObject;  
    102                }  
    103            }  
    104            catch (Throwable ex) {  
    105                throw new BeanCreationException(  
    106                        this.beanDefinition.getResourceDescription(), this.beanName,  
    107                        "Error converting typed String value for " + argName, ex);  
    108            }  
    109        }  
    110        else {  
    111            return evaluate(value);  
    112        }  
    113    }  
    114    //解析引用类型的属性值  
    115    private Object resolveReference(Object argName, RuntimeBeanReference ref) {  
    116        try {  
    117            //获取引用的Bean名称  
    118            String refName = ref.getBeanName();  
    119            refName = String.valueOf(evaluate(refName));  
    120            //如果引用的对象在父类容器中,则从父类容器中获取指定的引用对象  
    121            if (ref.isToParent()) {  
    122                if (this.beanFactory.getParentBeanFactory() == null) {  
    123                    throw new BeanCreationException(  
    124                            this.beanDefinition.getResourceDescription(), this.beanName,  
    125                            "Can't resolve reference to bean '" + refName +  
    126                            "' in parent factory: no parent factory available");  
    127                }  
    128                return this.beanFactory.getParentBeanFactory().getBean(refName);  
    129            }  
    130            //从当前的容器中获取指定的引用Bean对象,如果指定的Bean没有被实例化  
    131            //则会递归触发引用Bean的初始化和依赖注入  
    132            else {  
    133                Object bean = this.beanFactory.getBean(refName);  
    134                //将当前实例化对象的依赖引用对象  
    135                this.beanFactory.registerDependentBean(refName, this.beanName);  
    136                return bean;  
    137            }  
    138        }  
    139        catch (BeansException ex) {  
    140            throw new BeanCreationException(  
    141                    this.beanDefinition.getResourceDescription(), this.beanName,  
    142                    "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);  
    143        }  
    144    }   
    145    //解析array类型的属性  
    146    private Object resolveManagedArray(Object argName, List<?> ml, Class elementType) {  
    147        //创建一个指定类型的数组,用于存放和返回解析后的数组  
    148        Object resolved = Array.newInstance(elementType, ml.size());  
    149        for (int i = 0; i < ml.size(); i++) {  
    150        //递归解析array的每一个元素,并将解析后的值设置到resolved数组中,索引为i  
    151            Array.set(resolved, i,  
    152                resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));  
    153        }  
    154        return resolved;  
    155    }  
    156    //解析list类型的属性  
    157    private List resolveManagedList(Object argName, List<?> ml) {  
    158        List<Object> resolved = new ArrayList<Object>(ml.size());  
    159        for (int i = 0; i < ml.size(); i++) {  
    160            //递归解析list的每一个元素  
    161            resolved.add(  
    162                resolveValueIfNecessary(new KeyedArgName(argName, i), ml.get(i)));  
    163        }  
    164        return resolved;  
    165    }  
    166    //解析set类型的属性  
    167    private Set resolveManagedSet(Object argName, Set<?> ms) {  
    168        Set<Object> resolved = new LinkedHashSet<Object>(ms.size());  
    169        int i = 0;  
    170        //递归解析set的每一个元素  
    171        for (Object m : ms) {  
    172            resolved.add(resolveValueIfNecessary(new KeyedArgName(argName, i), m));  
    173            i++;  
    174        }  
    175        return resolved;  
    176    }  
    177    //解析map类型的属性  
    178    private Map resolveManagedMap(Object argName, Map<?, ?> mm) {  
    179        Map<Object, Object> resolved = new LinkedHashMap<Object, Object>(mm.size());  
    180        //递归解析map中每一个元素的key和value  
    181        for (Map.Entry entry : mm.entrySet()) {  
    182            Object resolvedKey = resolveValueIfNecessary(argName, entry.getKey());  
    183            Object resolvedValue = resolveValueIfNecessary(  
    184                    new KeyedArgName(argName, entry.getKey()), entry.getValue());  
    185            resolved.put(resolvedKey, resolvedValue);  
    186        }  
    187        return resolved;  
    188    } 
    

       通过上面的代码分析,我们明白了Spring是如何将引用类型,内部类以及集合类型等属性进行解析的,属性值解析完成后就可以进行依赖注入了,依赖注入的过程就是Bean对象实例设置到它所依赖的Bean对象属性上去,在第7步中我们已经说过,依赖注入是通过bw.setPropertyValues方法实现的,该方法也使用了委托模式,在BeanWrapper接口中至少定义了方法声明,依赖注入的具体实现交由其实现类BeanWrapperImpl来完成,下面我们就分析依BeanWrapperImpl中赖注入相关的源码。BeanWrapperImpl类主要是对容器中完成初始化的Bean实例对象进行属性的依赖注入,即把Bean对象设置到它所依赖的另一个Bean的属性中去,依赖注入的相关源码如下:

           

    1    //实现属性依赖注入功能  
    2    private void setPropertyValue(PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {  
    3        //PropertyTokenHolder主要保存属性的名称、路径,以及集合的size等信息  
    4        String propertyName = tokens.canonicalName;  
    5        String actualName = tokens.actualName;  
    6        //keys是用来保存集合类型属性的size  
    7        if (tokens.keys != null) {  
    8            //将属性信息拷贝  
    9            PropertyTokenHolder getterTokens = new PropertyTokenHolder();  
    10            getterTokens.canonicalName = tokens.canonicalName;  
    11            getterTokens.actualName = tokens.actualName;  
    12            getterTokens.keys = new String[tokens.keys.length - 1];  
    13            System.arraycopy(tokens.keys, 0, getterTokens.keys, 0, tokens.keys.length - 1);  
    14            Object propValue;  
    15            try {  
    16                //获取属性值,该方法内部使用JDK的内省( Introspector)机制,调用属性//的getter(readerMethod)方法,获取属性的值  
    17                propValue = getPropertyValue(getterTokens);  
    18            }  
    19            catch (NotReadablePropertyException ex) {  
    20                throw new NotWritablePropertyException(getRootClass(), this.nestedPath + propertyName,  
    21                        "Cannot access indexed value in property referenced " +  
    22                        "in indexed property path '" + propertyName + "'", ex);  
    23            }  
    24            //获取集合类型属性的长度  
    25            String key = tokens.keys[tokens.keys.length - 1];  
    26            if (propValue == null) {  
    27                throw new NullValueInNestedPathException(getRootClass(), this.nestedPath + propertyName,  
    28                        "Cannot access indexed value in property referenced " +  
    29                        "in indexed property path '" + propertyName + "': returned null");  
    30            }  
    31            //注入array类型的属性值  
    32            else if (propValue.getClass().isArray()) {  
    33                //获取属性的描述符  
    34                PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);  
    35                //获取数组的类型  
    36                Class requiredType = propValue.getClass().getComponentType();  
    37                //获取数组的长度  
    38                int arrayIndex = Integer.parseInt(key);  
    39                Object oldValue = null;  
    40                try {  
    41                    //获取数组以前初始化的值  
    42                    if (isExtractOldValueForEditor()) {  
    43                        oldValue = Array.get(propValue, arrayIndex);  
    44                    }  
    45                    //将属性的值赋值给数组中的元素  
    46                    Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,  
    47                            new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType));  
    48                    Array.set(propValue, arrayIndex, convertedValue);  
    49                }  
    50                catch (IndexOutOfBoundsException ex) {  
    51                    throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,  
    52                            "Invalid array index in property path '" + propertyName + "'", ex);  
    53                }  
    54            }  
    55            //注入list类型的属性值  
    56            else if (propValue instanceof List) {  
    57                PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);  
    58                //获取list集合的类型  
    59                Class requiredType = GenericCollectionTypeResolver.getCollectionReturnType(  
    60                        pd.getReadMethod(), tokens.keys.length);  
    61                List list = (List) propValue;  
    62                //获取list集合的size  
    63                int index = Integer.parseInt(key);  
    64                Object oldValue = null;  
    65                if (isExtractOldValueForEditor() && index < list.size()) {  
    66                    oldValue = list.get(index);  
    67                }  
    68                //获取list解析后的属性值  
    69                Object convertedValue = convertIfNecessary(propertyName, oldValue, pv.getValue(), requiredType,  
    70                        new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), requiredType));  
    71                if (index < list.size()) {  
    72                    //为list属性赋值  
    73                    list.set(index, convertedValue);  
    74                }  
    75                //如果list的长度大于属性值的长度,则多余的元素赋值为null  
    76                else if (index >= list.size()) {  
    77                    for (int i = list.size(); i < index; i++) {  
    78                        try {  
    79                            list.add(null);  
    80                        }  
    81                        catch (NullPointerException ex) {  
    82                            throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,  
    83                                    "Cannot set element with index " + index + " in List of size " +  
    84                                    list.size() + ", accessed using property path '" + propertyName +  
    85                                    "': List does not support filling up gaps with null elements");  
    86                        }  
    87                    }  
    88                    list.add(convertedValue);  
    89                }  
    90            }  
    91            //注入map类型的属性值  
    92            else if (propValue instanceof Map) {  
    93                PropertyDescriptor pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);  
    94                //获取map集合key的类型  
    95                Class mapKeyType = GenericCollectionTypeResolver.getMapKeyReturnType(  
    96                        pd.getReadMethod(), tokens.keys.length);  
    97                //获取map集合value的类型  
    98                Class mapValueType = GenericCollectionTypeResolver.getMapValueReturnType(  
    99                        pd.getReadMethod(), tokens.keys.length);  
    100                Map map = (Map) propValue;  
    101                //解析map类型属性key值  
    102                Object convertedMapKey = convertIfNecessary(null, null, key, mapKeyType,  
    103                        new PropertyTypeDescriptor(pd, new MethodParameter(pd.getReadMethod(), -1), mapKeyType));  
    104                Object oldValue = null;  
    105                if (isExtractOldValueForEditor()) {  
    106                    oldValue = map.get(convertedMapKey);  
    107                }  
    108                //解析map类型属性value值  
    109                Object convertedMapValue = convertIfNecessary(  
    110                        propertyName, oldValue, pv.getValue(), mapValueType,  
    111                        new TypeDescriptor(new MethodParameter(pd.getReadMethod(), -1, tokens.keys.length + 1)));  
    112                //将解析后的key和value值赋值给map集合属性  
    113                map.put(convertedMapKey, convertedMapValue);  
    114            }  
    115            else {  
    116                throw new InvalidPropertyException(getRootClass(), this.nestedPath + propertyName,  
    117                        "Property referenced in indexed property path '" + propertyName +  
    118                        "' is neither an array nor a List nor a Map; returned value was [" + pv.getValue() + "]");  
    119            }  
    120        }  
    121        //对非集合类型的属性注入  
    122        else {  
    123            PropertyDescriptor pd = pv.resolvedDescriptor;  
    124            if (pd == null || !pd.getWriteMethod().getDeclaringClass().isInstance(this.object)) {  
    125                pd = getCachedIntrospectionResults().getPropertyDescriptor(actualName);  
    126                //无法获取到属性名或者属性没有提供setter(写方法)方法  
    127                if (pd == null || pd.getWriteMethod() == null) {  
    128                    //如果属性值是可选的,即不是必须的,则忽略该属性值  
    129                    if (pv.isOptional()) {  
    130                        logger.debug("Ignoring optional value for property '" + actualName +  
    131                                "' - property not found on bean class [" + getRootClass().getName() + "]");  
    132                        return;  
    133                    }  
    134                    //如果属性值是必须的,则抛出无法给属性赋值,因为每天提供setter方法异常  
    135                    else {  
    136                        PropertyMatches matches = PropertyMatches.forProperty(propertyName, getRootClass());  
    137                        throw new NotWritablePropertyException(  
    138                                getRootClass(), this.nestedPath + propertyName,  
    139                                matches.buildErrorMessage(), matches.getPossibleMatches());  
    140                    }  
    141                }  
    142                pv.getOriginalPropertyValue().resolvedDescriptor = pd;  
    143            }  
    144            Object oldValue = null;  
    145            try {  
    146                Object originalValue = pv.getValue();  
    147                Object valueToApply = originalValue;  
    148                if (!Boolean.FALSE.equals(pv.conversionNecessary)) {  
    149                    if (pv.isConverted()) {  
    150                        valueToApply = pv.getConvertedValue();  
    151                    }  
    152                    else {  
    153                        if (isExtractOldValueForEditor() && pd.getReadMethod() != null) {  
    154                            //获取属性的getter方法(读方法),JDK内省机制  
    155                            final Method readMethod = pd.getReadMethod();  
    156                            //如果属性的getter方法不是public访问控制权限的,即访问控制权限比较严格,  
    157                            //则使用JDK的反射机制强行访问非public的方法(暴力读取属性值)  
    158                            if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers()) &&  
    159                                    !readMethod.isAccessible()) {  
    160                                if (System.getSecurityManager()!= null) {  
    161                                    //匿名内部类,根据权限修改属性的读取控制限制  
    162                                    AccessController.doPrivileged(new PrivilegedAction<Object>() {  
    163                                        public Object run() {  
    164                                            readMethod.setAccessible(true);  
    165                                            return null;  
    166                                        }  
    167                                    });  
    168                                }  
    169                                else {  
    170                                    readMethod.setAccessible(true);  
    171                                }  
    172                            }  
    173                            try {  
    174                                //属性没有提供getter方法时,调用潜在的读取属性值//的方法,获取属性值  
    175                                if (System.getSecurityManager() != null) {  
    176                                    oldValue = AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {  
    177                                        public Object run() throws Exception {  
    178                                            return readMethod.invoke(object);  
    179                                        }  
    180                                    }, acc);  
    181                                }  
    182                                else {  
    183                                    oldValue = readMethod.invoke(object);  
    184                                }  
    185                            }  
    186                            catch (Exception ex) {  
    187                                if (ex instanceof PrivilegedActionException) {  
    188                                    ex = ((PrivilegedActionException) ex).getException();  
    189                                }  
    190                                if (logger.isDebugEnabled()) {  
    191                                    logger.debug("Could not read previous value of property '" +  
    192                                            this.nestedPath + propertyName + "'", ex);  
    193                                }  
    194                            }  
    195                        }  
    196                        //设置属性的注入值  
    197                        valueToApply = convertForProperty(propertyName, oldValue, originalValue, pd);  
    198                    }  
    199                    pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);  
    200                }  
    201                //根据JDK的内省机制,获取属性的setter(写方法)方法  
    202                final Method writeMethod = (pd instanceof GenericTypeAwarePropertyDescriptor ?  
    203                        ((GenericTypeAwarePropertyDescriptor) pd).getWriteMethodForActualAccess() :  
    204                        pd.getWriteMethod());  
    205                //如果属性的setter方法是非public,即访问控制权限比较严格,则使用JDK的反射机制,  
    206                //强行设置setter方法可访问(暴力为属性赋值)  
    207                if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {  
    208                    //如果使用了JDK的安全机制,则需要权限验证  
    209                    if (System.getSecurityManager()!= null) {  
    210                        AccessController.doPrivileged(new PrivilegedAction<Object>() {  
    211                            public Object run() {  
    212                                writeMethod.setAccessible(true);  
    213                                return null;  
    214                            }  
    215                        });  
    216                    }  
    217                    else {  
    218                        writeMethod.setAccessible(true);  
    219                    }  
    220                }  
    221                final Object value = valueToApply;  
    222                if (System.getSecurityManager() != null) {  
    223                    try {  
    224                        //将属性值设置到属性上去  
    225                        AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {  
    226                            public Object run() throws Exception {  
    227                                writeMethod.invoke(object, value);  
    228                                return null;  
    229                            }  
    230                        }, acc);  
    231                    }  
    232                    catch (PrivilegedActionException ex) {  
    233                        throw ex.getException();  
    234                    }  
    235                }  
    236                else {  
    237                    writeMethod.invoke(this.object, value);  
    238                }  
    239            }  
    240            catch (TypeMismatchException ex) {  
    241                throw ex;  
    242            }  
    243            catch (InvocationTargetException ex) {  
    244                PropertyChangeEvent propertyChangeEvent =  
    245                        new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());  
    246                if (ex.getTargetException() instanceof ClassCastException) {  
    247                    throw new TypeMismatchException(propertyChangeEvent, pd.getPropertyType(), ex.getTargetException());  
    248                }  
    249                else {  
    250                    throw new MethodInvocationException(propertyChangeEvent, ex.getTargetException());  
    251                }  
    252            }  
    253            catch (Exception ex) {  
    254                PropertyChangeEvent pce =  
    255                        new PropertyChangeEvent(this.rootObject, this.nestedPath + propertyName, oldValue, pv.getValue());  
    256                throw new MethodInvocationException(pce, ex);  
    257            }  
    258        }  
        }  
    

      

              通过对上面注入依赖代码的分析,我们已经明白了Spring IoC容器是如何将属性的值注入到Bean实例对象中去的:

              (1).对于集合类型的属性,将其属性值解析为目标类型的集合后直接赋值给属性。

              (2).对于非集合类型的属性,大量使用了JDK的反射和内省机制,通过属性的getter方法(reader method)获取指定属性注入以前的值,同时调用属性的setter方法(writer method)为属性设置注入后的值。看到这里相信很多人都明白了Spring的setter注入原理

              

         三总结

     

     注入过程

  • 相关阅读:
    HDU 1022 Train Problem I
    HDU 1702 ACboy needs your help again!
    HDU 1294 Rooted Trees Problem
    HDU 1027 Ignatius and the Princess II
    HDU 3398 String
    HDU 1709 The Balance
    HDU 2152 Fruit
    HDU 1398 Square Coins
    HDU 3571 N-dimensional Sphere
    HDU 2451 Simple Addition Expression
  • 原文地址:https://www.cnblogs.com/yuanfuqiang/p/5834496.html
Copyright © 2011-2022 走看看