`
imaginecup
  • 浏览: 87566 次
  • 性别: 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容器初始化源码解析 #### 一、Spring框架的核心——IoC容器 Spring框架是一个开源的轻量级Java开发框架,其核心功能是IoC(Inversion of Control,控制反转)容器和AOP(Aspect Oriented ...

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

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

    Spring IOC容器实现分析.pdf 下载

    1. 配置解析:Spring首先读取配置文件(XML、Java配置类或注解),解析出Bean的定义信息,包括Bean的类型、初始化方法、依赖关系等。 2. Bean的实例化:当需要使用某个Bean时,IOC容器会根据Bean的定义创建实例。...

    Spring源码分析_Spring_IOC

    ### Spring源码分析_Spring_IOC:深入理解Spring的IOC容器机制 #### 基本概念与核心作用 在探讨Spring框架的核心组件之一——IOC(Inversion of Control,控制反转)容器之前,首先需要理解它在Spring框架中的角色...

    Spring框架系列(7) - Spring IOC实现原理详解之IOC初始化流程.doc

    Spring 框架系列(7)- Spring IOC 实现原理详解之 IOC 初始化流程 本文将详细解释 Spring 框架中的 IOC...IOC 容器的初始化流程是 Spring 框架中的关键部分,用于将资源配置文件中的信息加载到 IOC 容器中。

    Spring源码解析.pdf

    ### Spring源码解析知识点 #### 一、Spring IoC 容器详解 ##### 1. BeanFactory —— 最基础的IoC容器 - **概念**:`BeanFactory` 是Spring框架中最基本的IoC容器,它负责管理Bean的生命周期,包括创建、配置和...

    Spring源码深度解析第二版

    Spring源码深度解析第二版 Spring是一款广泛应用于Java企业级应用程序的开源框架,旨在简化Java应用程序的开发和部署。Spring框架的核心主要包括了IoC容器、AOP、MVC框架等模块。 第1章 Spring整体架构和环境搭建 ...

    手写一个SpringIoc容器

    本项目"手写一个SpringIoc容器"旨在模仿Spring的IOC(Inversion of Control,控制反转)功能,帮助开发者深入理解Spring的工作原理,提升对依赖注入(Dependency Injection)模式的认识。 在实现自定义的Spring IOC...

    Spring IoC源码深度剖析开源架构源码2021.pdf

    文档可能将深入探讨Spring IoC容器初始化、Bean生命周期管理、依赖注入等关键概念,并以2021年的开源版本为背景进行分析。 从提供的部分文档内容来看,我们可以提炼出以下几个知识点: 1. **BeanFactory与...

    spring源码解析

    ### Spring源码解析知识点 #### 1. Spring IoC 容器概述 Spring 框架的核心特性之一是它的依赖注入(Dependency Injection, DI)能力,这种能力通过一个称为 Inversion of Control (IoC) 容器来实现。IoC 容器负责...

    Spring IOC源码解读

    Spring的IOC容器在初始化时会读取配置文件,解析Bean的定义,然后根据这些定义创建Bean实例。在Bean实例化的过程中,可以通过依赖注入(Dependency Injection,DI)来解决对象间的依赖关系。DI有两种主要形式:...

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

    一、Spring IoC容器的初始化 1. **实例化容器**:容器的起点通常是`AnnotationConfigApplicationContext`,它是基于注解配置的上下文。在创建`AnnotationConfigApplicationContext`时,我们通常会传入一个或多个...

    仿spring ioc 容器

    在IT行业中,Spring框架是Java开发中的一个基石,特别是其依赖注入(Dependency Injection,简称DI...同时,也可以参考Spring的源码,深入了解IoC容器的工作原理,这对于提升自身编程能力、理解和应用IoC有极大的帮助。

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

    当创建`AnnotationConfigApplicationContext`时,会初始化`DefaultListableBeanFactory`,这是Spring IoC容器的主要实现,它负责处理Bean的定义和管理。 接着,`AnnotatedBeanDefinitionReader`被实例化,它的主要...

    【框架源码篇 01】Spring源码-手写IOC

    5. **Bean管理**:最后,容器会管理Bean的生命周期,包括初始化、使用和销毁。 在实际开发中,Spring使用了更加高效和灵活的方式来实现这些功能,比如使用`ApplicationContext`接口作为IOC容器的入口,以及`...

    Java Spring 源码解析 Xmind 思维导图

    在Spring源码解析中,时序图用于描绘不同组件之间的调用关系,如AOP代理的生成过程、事件发布机制、数据访问层(DAO)与业务逻辑层(Service)的交互等。这有助于开发者理解Spring如何处理复杂的应用场景。 再者,...

    Spring3.1.3 Ioc在Web容器中的建立

    标题 "Spring3.1.3 Ioc在Web容器中的建立" 涉及...这个过程涉及到Spring容器的初始化、bean的定义与依赖注入,以及Web应用的结构配置。通过理解和熟练运用这些知识,开发者可以更好地构建可维护、可扩展的Spring应用。

    Spring 源码分析(Bean的初始化)

    在Spring框架中,Bean的初始化是一个至关重要的过程,它涉及到从XML配置文件或者注解中读取Bean的定义,解析并构建Bean实例。本篇文章主要分析了Spring如何通过`ClassPathXmlApplicationContext`来启动和初始化Bean...

Global site tag (gtag.js) - Google Analytics