`
imaginecup
  • 浏览: 85182 次
  • 性别: Icon_minigender_1
  • 来自: 西安
社区版块
存档分类
最新评论

Spring源码解析1 IOC容器的初始化

阅读更多

参考《Spring技术内幕》一书:  

 IoC容器的基本接口是由BeanFactory来定义的,也就是说BeanFactory定义了IoC容器的最基本的形式,并且提供了  IoC容器所应该遵守的最基本的服务契约。BeanFactory只是一个接口类,并没有给出容器的具体实现。DefaultListableBeanFactory,XmlBeanFactory,ApplicationContext,FileSystemXmlBeanFactory,ClassPathXmlBeanFactory都实现了BeanFactory接口并且扩展了IoC容器的功能。

首先介绍BeanFactory:

 

public interface BeanFactory {      
     
    //这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,      
    //如果需要得到工厂本身,需要转义             
    String FACTORY_BEAN_PREFIX = "&";      
     
     
    //这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。      
    Object getBean(String name) throws BeansException;      
     
    //这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。      
    Object getBean(String name, Class requiredType) throws BeansException;      
     
    //这里提供对bean的检索,看看是否在IOC容器有这个名字的bean      
    boolean containsBean(String name);      
     
    //这里根据bean名字得到bean实例,并同时判断这个bean是不是单件      
    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;      
     
    //这里对得到bean实例的Class类型      
    Class getType(String name) throws NoSuchBeanDefinitionException;      
     
    //这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来      
    String[] getAliases(String name);      
     
}    

 

 

用户使用容器时,可以使用转义字符'&'来得到FactoryBean本身,用来区分通过容器来获取FactoryBean产生的对象还是获取FactoryBean本身。在Spring中所有的Bean都是由BeanFactory来管理的,而对于FactoryBean,它是一个能产生或者修饰对象生成的工厂Bean

BeanFactory和FactoryBean:BeanFactory它指的是IoC容器的编程抽象,而FactoryBean指的是一个抽象工厂,对它的调用返回的是工厂产生的对象,而不是它本身。

 

 

 

 

 

我们先通过编程实现IoC容器:

 

public class UserBeanFatory {   
    public static void main(String[] args) {   
        //创建一个BeanFactory,这里使用DefaultListableBeanFactory,包含IoC容器的重要功能   
        DefaultListableBeanFactory factory=new DefaultListableBeanFactory();   
        /*  
         * 创建一个载入BeanDefinition的读取器,这里使用XmlBeanDefinitionReader来载入XML文件形式的  
         * BeanDefinition,使用一个回调配置给BeanFactory  
         */  
        XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory);   
        /*  
         * 创建Ioc配置文件的抽象资源,这个抽象资源中包含了BeanDefinition的定义信息  
         */  
        ClassPathResource res=new ClassPathResource("applicationContext-beans.xml");   
        /*  
         * 从定义好的资源位置读入配置信息,具体的解析过程是由XmlBeanDefinitionReader  
         * 来完成的。完成整个的载入与注册Bean定义之后,需要的IoC容器就建立起来了  
         */  
        reader.loadBeanDefinitions(res);   
  
        User user=(User)factory.getBean("user");   
        System.out.println(user.getUsername()+":"+user.getPassword());   
        //等价于   
        XmlBeanFactory xmlfactory=new XmlBeanFactory(new ClassPathResource("applicationContext-beans.xml"));   
        User xmluser=(User)factory.getBean("user");   
        System.out.println(xmluser.getUsername()+":"+xmluser.getPassword());   
        ApplicationContext ac=new FileSystemXmlApplicationContext("D:/java/kcsj/SourceXmpBeanFactory/src/applicationContext-beans.xml");   
        ac.getBean("user");   
    }   
  
}  

 

 

 

 由上面我们可以想到IoC 容器初始化分为三个步骤:

1 BeanDefinition的Resource定位

2 BeanDefinition的载入和解析

3 BeanDefinition的注册

 

我们先看BeanDefinition的Resource定位:

下面以FileSystemXmlApplicationContext为例,通过分析这个ApplicationContext的实现来看看它是怎样完成Resource的定位的。

ApplicationContext ac=new FileSystemXmlApplicationContext("D:/java/kcsj/SourceXmpBeanFactory/src/applicationContext-beans.xml");

 

 


 

我们首先看看FileSystemXmlApplicationContext的源码:

 

public class FileSystemXmlApplicationContext extends AbstractXmlApplicationContext {   
      .....   
      public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)   
            throws BeansException {   
  
        super(parent);   
        setConfigLocations(configLocations);   
        if (refresh) {   
            refresh();   
        }   
     }  

 


}

 

在FileSystemXmlApplicationContext 的构造函数中完成了两部分功能:1是设置BeanDefinition的配置文件的路径,是的所有在配置文件中的BeanDefinition都能得到有效地处理;2 就是通过refresh()方法启动了IoC容器的初始化。

AbstractApplicationContext的refresh()方法源码解析:

public void refresh() throws BeansException, IllegalStateException {   
        synchronized (this.startupShutdownMonitor) {   
            // Prepare this context for refreshing.   
            prepareRefresh();   
  
            // Tell the subclass to refresh the internal bean factory.   
            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();   
  
            // Prepare the bean factory for use in this context.   
            prepareBeanFactory(beanFactory);   
  
            try {   
                // Allows post-processing of the bean factory in context subclasses.   
                postProcessBeanFactory(beanFactory);   
  
                // Invoke factory processors registered as beans in the context.   
                invokeBeanFactoryPostProcessors(beanFactory);   
  
                // Register bean processors that intercept bean creation.   
                registerBeanPostProcessors(beanFactory);   
  
                // Initialize message source for this context.   
                initMessageSource();   
  
                // Initialize event multicaster for this context.   
                initApplicationEventMulticaster();   
  
                // Initialize other special beans in specific context subclasses.   
                onRefresh();   
  
                // Check for listener beans and register them.   
                registerListeners();   
  
                // Instantiate all remaining (non-lazy-init) singletons.   
                finishBeanFactoryInitialization(beanFactory);   
  
                // Last step: publish corresponding event.   
                finishRefresh();   
            }   
  
            catch (BeansException ex) {   
                // Destroy already created singletons to avoid dangling resources.   
                destroyBeans();   
  
                // Reset 'active' flag.   
                cancelRefresh(ex);   
  
                // Propagate exception to caller.   
                throw ex;   
            }   
        }   
    }  

 

 它包含了IoC容器的整个初始化的过程,包括:BeanFactory 的更新,初始化messagesource,配置和注册后置处理器,注册监听器和事件触发器,还有进行预实例化(non-lazy-init)的处理等等。它把资源的定位交给了obtainFreshBeanFactory方法:

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {   
    refreshBeanFactory();   
    ConfigurableListableBeanFactory beanFactory = getBeanFactory();   
    if (logger.isDebugEnabled()) {   
        logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);   
    }   
    return beanFactory;   
}  

 

 然后又通过调用抽象方法refreshBeanFactory,它的实现在AbstractRefreshableApplicaitonContext中:

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

 

 

这里先判断是否已经建立了BeanFactory,如果建立则销毁并关闭BeanFactory,然后创建BeanFactory,这里创建的是DefaultListableBeanFactory,然后调用loadBeanDefinitions载入BeanDefinition的配置信息。接着我们去看loadBeanDefinitions方法的具体执行过程:

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

 

 

这里它先创建一个BeanDefinition的Xml读取器,并且回调配置给BeanFactory,如同我们前面通过编程实现IoC容器的初始化,然后再转到loadBeanDefinitions(beanDefintionReader)中:

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {   
        Resource[] configResources = getConfigResources();   
        if (configResources != null) {   
            reader.loadBeanDefinitions(configResources);   
        }   
        String[] configLocations = getConfigLocations();   
        if (configLocations != null) {   
            reader.loadBeanDefinitions(configLocations);   
        }   
    }  

 

 它首先获得BeanDefinition的配置文件的资源,判断是否存在,如果存在在加载,然后获取配置文件的路径,判断是否存在,如果存在则加载。一种是从资源中加载,另一种是从给定的路径中加载。由于我们在没有显式的定义资源,我们只是给定了一个配置文件的路径,所以它会从路径加载。也就是调用reader.loadBeanDefinitions(configLocations)方法。

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {   
    Assert.notNull(locations, "Location array must not be null");   
    int counter = 0;   
    for (String location : locations) {   
        counter += loadBeanDefinitions(location);   
    }   
    return counter;   
}  

 

 

然后继续调用loadBeanDefinitions(location)方法:

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {   
        return loadBeanDefinitions(location, null);   
    }  

 

 再转到:loadBeanDefinitions(String location, Set<Resource> actualResources)方法中

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {   
        ResourceLoader resourceLoader = getResourceLoader();   
        if (resourceLoader == null) {   
            throw new BeanDefinitionStoreException(   
                    "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");   
        }   
  
        if (resourceLoader instanceof ResourcePatternResolver) {   
            // Resource pattern matching available.   
            try {   
                Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);   
                int loadCount = loadBeanDefinitions(resources);   
                if (actualResources != null) {   
                    for (Resource resource : resources) {   
                        actualResources.add(resource);   
                    }   
                }   
                if (logger.isDebugEnabled()) {   
                    logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");   
                }   
                return loadCount;   
            }   
            catch (IOException ex) {   
                throw new BeanDefinitionStoreException(   
                        "Could not resolve bean definition resource pattern [" + location + "]", ex);   
            }   
        }   
        else {   
            // Can only load single resources by absolute URL.   
            Resource resource = resourceLoader.getResource(location);   
            int loadCount = loadBeanDefinitions(resource);   
            if (actualResources != null) {   
                actualResources.add(resource);   
            }   
            if (logger.isDebugEnabled()) {   
                logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");   
            }   
            return loadCount;   
        }   
    }  

 

 Resource resource = resourceLoader.getResource(location);就是用来定位BeanDefinition的资源的,它会交给DefaultResourceLoader的getResource()方法处理:

public Resource getResource(String location) {   
    Assert.notNull(location, "Location must not be null");   
    if (location.startsWith(CLASSPATH_URL_PREFIX)) {   
        return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());   
    }   
    else {   
        try {   
            // Try to parse the location as a URL...   
            URL url = new URL(location);   
            return new UrlResource(url);   
        }   
        catch (MalformedURLException ex) {   
            // No URL -> resolve as resource path.   
            return getResourceByPath(location);   
        }   
    }   
}  

 

 最后它又调用getResourceByPath(location),它被FileSystemXmlApplicationContext中getResourceByPath()覆盖了,具体源码如下:

protected Resource getResourceByPath(String path) {   
    if (path != null && path.startsWith("/")) {   
        path = path.substring(1);   
    }   
    return new FileSystemResource(path);   
} 

 

 到这里为止,IoC容器的初始化的第一步骤已经完成了,总结可得BeanDefinition的Resource的定位是通过DefaultResourceLoader来getResource()方法来定位的,在getResource()中又调用getResourceByPath(),它被不同的BeanFactory覆盖。
 

 

 

 

 

 

分享到:
评论
1 楼 zhudaokun 2010-12-28  
呵呵……好帖,收藏一下

相关推荐

    Spring的IoC容器初始化源码解析

    Spring的IoC容器初始化源码解析,包括资源定位、加载、注册3个过程

    Spring源码解析4章150页+Spring3.2.4中文注释源码

    3、源码分析-IOC容器的初始化 4、源码分析-IOC容器的依赖注入 5、源码分析-IOC容器的高级特性 三阶段 Spring AOP的涉及原理及具体实践 SpringJDBC的涉及原理及二次开发 SpringMVC框架设计原理及手写实现 四阶段 ...

    深入解析Spring IoC源码:核心机制与实践应用

    本文深入探讨了Spring框架中IoC容器的源码机制,涵盖了容器的初始化、Bean工厂的实例化、Bean定义的读取及Spring Bean的生命周期管理。通过精细的分析,本文揭示了AnnotationConfigApplicationContext的实例化过程,...

    深入解析Spring IoC:源码与实践指南

    本文深入探讨了Spring IoC容器的加载过程及其源码实现,揭示了Spring中最为根本的概念之一。这包括从AnnotationConfigApplicationContext的实例化开始,到DefaultListableBeanFactory工厂的建立,再到...

    spring源代码解析

    简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理...

    Spring原理篇.xmind

    包括内容:Spring体系结构、Spring重要接口讲解(BeanFactory继承体系、BeanDefinition继承体系、ApplicationContext继承体系)、IOC/DI(容器初始化流源码分析)、AOP原理(解析流程,代理流程,执行流程)、事务...

    Spring攻略(第二版 中文高清版).part1

    1.1 实例化Spring IoC容器 1 1.1.1 问题 1 1.1.2 解决方案 1 1.1.3 工作原理 3 1.2 配置Spring IoC容器中的Bean 4 1.2.1 问题 4 1.2.2 解决方案 4 1.2.3 工作原理 4 1.3 调用构造程序创建Bean 14 ...

    Spring-Reference_zh_CN(Spring中文参考手册)

    3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.6.1. 设置Bean使自动装配失效 3.3.7. 依赖检查 3.3.8. 方法注入 3.3.8.1. Lookup方法注入 3.3.8.2. 自定义方法的替代方案 3.4. bean的作用域 3.4.1. ...

    Spring 2.0 开发参考手册

    3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.4. 自定义作用域 ...

    Spring中文帮助文档

    3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton beans和prototype-bean的...

    Spring API

    3.3.4. 延迟初始化bean 3.3.5. 自动装配(autowire)协作者 3.3.6. 依赖检查 3.3.7. 方法注入 3.4. Bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. Singleton beans和prototype-bean的...

    spring chm文档

    3.3.5. 延迟初始化bean 3.3.6. 自动装配(autowire)协作者 3.3.7. 依赖检查 3.3.8. 方法注入 3.4. bean的作用域 3.4.1. Singleton作用域 3.4.2. Prototype作用域 3.4.3. 其他作用域 3.4.4. 自定义作用域 ...

    Spring攻略(第二版 中文高清版).part2

    1.1 实例化Spring IoC容器 1 1.1.1 问题 1 1.1.2 解决方案 1 1.1.3 工作原理 3 1.2 配置Spring IoC容器中的Bean 4 1.2.1 问题 4 1.2.2 解决方案 4 1.2.3 工作原理 4 1.3 调用构造程序创建Bean 14 ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (1)

    8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (3)

    8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...

    搞定J2EE:STRUTS+SPRING+HIBERNATE整合详解与典型案例 (2)

    8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...

    《程序天下:J2EE整合详解与典型案例》光盘源码

    8.4.3 改变初始化和销毁方式 8.4.4 改变异常处理的方式 8.5 小结 第九章 CVS使用指南 9.1 CVS介绍 9.1.1 CVS简介 9.1.2 为什么要使用CVS 9.2 建立CVS的开发环境 9.2.1 下载CVS 9.2.2 配置CVS 9.3 CVS的使用方法 ...

Global site tag (gtag.js) - Google Analytics