Spring Ioc源码阅读笔记(二)Spring Ioc核心源码体系

BeanFactory

概述

从接口命名,我们可以很容易看出,Spring的Ioc核心源码体系是工厂模式。

这里从类图抽象出来的接口层级关系,结合Spring源码对这些接口的注释,我们可以了解到:

BeanFactory是Spring Bean容器的顶层接口,是一个基本的容器视图,在这里只定义了容器的一些最基本的行为。而如ListableBeanFactory、ConfigurableBeanFactory等接口适用于一些比较特殊的场景。Spring的DI(依赖注入)实现是通过BeanFactory接口以及它的子接口来实现。具体的实现方式我们可以在下面了解到,这里不再赘述。

在这里插入图片描述

BeanFactory以及它的下级接口

BeanFactory只定义Ioc容器的基本行为。具体的实现由继承BeanFactory的实现类去实现,如XmlBeanFactory、ClasspathXmlApplicationContext等。这些实现类需要尽可能支持一个标准的Bean的生命周期(详细查看Bean生命周期章节)。

在这里插入图片描述

BeanFactory只是包装了Spring Ioc容器最基本的行为,但是对于不同场景下,为了能够灵活的描述Bean在实际传递和转化过程中的关系以及限制,在之下还有对应的不同的子类。
HierarchicalBeanFactory:描述Bean的继承关系。
在这里插入图片描述

ListableBeanFactory:描述Bean是可列表的。在这里插入图片描述

AutowireCapableBeanFactory:定义Bean的自动装配规则。
在这里插入图片描述
由这四个接口共同定义了Bean的集合、Bean之间的关系以及Bean行为。

Ioc容器的初始化

Ioc容器的初始化包括BeanDefinition的Resource定位、载入和注册。

下面会以一个比较简单的容器实现来说明下Ioc容器的初始化。

XmlBeanFactory
public class XmlBeanFactory extends DefaultListableBeanFactory {

private final XmlBeanDefinitionReader reader = 
		    new XmlBeanDefinitionReader(this);

  public XmlBeanFactory(Resource resource) throws BeansException   {
		    this(resource, null);
  }
 public XmlBeanFactory(Resource resource,  BeanFactory parentBeanFactory) throws BeansException {
    super(parentBeanFactory);
    this.reader.loadBeanDefinitions(resource);
  }
}

从源码可以看到,构造方法做了以下的事情:
第一:创建XmlBeanDefinitionReader读取器,用于载入BeanDefinition

private final XmlBeanDefinitionReader reader = 
		    new XmlBeanDefinitionReader(this);

第二:加载Resource资源对象,该对象包含了BeanDefinition的信息,完成Bean的载入和注册。

 this.reader.loadBeanDefinitions(resource);
FileSystemXmlApplicationContext

FileSystemXmlApplicationContext
在这里插入图片描述

源码分析
	public FileSystemXmlApplicationContext(String[] configLocations, boolean 		refresh, ApplicationContext parent)throws BeansException {
         super(parent);
         setConfigLocations(configLocations);
         if (refresh) {
             refresh();
         }
 }

在构造方法里面,可以看到:

首先,调用父类的构造方法为容器设置好资源加载器;

  super(parent);

跟到里面可以看到

public AbstractApplicationContext(ApplicationContext parent) {
     this.parent = parent;
     this.resourcePatternResolver = getResourcePatternResolver();
}

protected ResourcePatternResolver getResourcePatternResolver() {
      return new PathMatchingResourcePatternResolver(this);
}

创建完资源加载器之后,接下来setConfigLocations方法定位资源文件。

定位完资源文件后,开始调用refresh()函数载入Bean。

public void refresh() throws BeansException, IllegalStateException {
      synchronized (this.startupShutdownMonitor) {
      // 准备刷新容器
      prepareRefresh();

      //通过refreshBeanFactory()重刷beanFactory,如果存在,则destroy
      //它,如果不存在,则创建。
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

     // 为BeanFactory配置容器特性,例如类加载器,事件处理器等
     prepareBeanFactory(beanFactory);

     try {
         // 为容器的某些子类指定特殊的BeanPost事件处理器
         postProcessBeanFactory(beanFactory);
         
         invokeBeanFactoryPostProcessors(beanFactory);

         //注册BeanPostProcessor,此处将结合Bean的生命周期来看
         registerBeanPostProcessors(beanFactory);

         //初始化信息源
         initMessageSource();

         // 初始化容器事件传播器
         initApplicationEventMulticaster();

         // 如果子类有特殊需求,调用特殊化的初始化方法,默认为空
         onRefresh();

         // 为事件传播器注册事件监听器
         registerListeners();

         // 装载所有剩余的单态Bean
         finishBeanFactoryInitialization(beanFactory);

         // 发布容器的生命周期事件
         finishRefresh();
    }catch (BeansException ex) {
         // 销毁已创建的单态Bean
         beanFactory.destroySingletons();

         //重置active标识,该标识在prepareRefresh()设置
         cancelRefresh(ex);

         throw ex;
    }
  }
}
//obtainFreshBeanFactory
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {  
        //子类具体实现refreshBeanFactory
         refreshBeanFactory();  
        ConfigurableListableBeanFactory beanFactory = getBeanFactory();  
        if (logger.isDebugEnabled()) {  
            logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);  
        }  
        return beanFactory;  
    }

refreshBeanFactory()可以参考AbstractRefreshableApplicationContext类的实现。

//AbstractRefreshableApplicationContext
protected final void refreshBeanFactory() throws BeansException {  
       if (hasBeanFactory()) {
           destroyBeans();  
           closeBeanFactory();  
       }  
       try {  
            //创建IoC容器  
            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);  
       }  
   }

其他的都挺容易理解的,这里不在赘述,这里说下loadBeanDefinitions(beanFactory)

  @Override  
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {  
        //创建Bean读取器,容器使用该读取器读取Bean定义资源
        XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  
        //为Bean读取器设置Spring资源加载器,AbstractXmlApplicationContext的  
        //祖先父类AbstractApplicationContext继承DefaultResourceLoader,因此,容器本身也是一个资源加载器  
       beanDefinitionReader.setResourceLoader(this);  
       //为Bean读取器设置SAX xml解析器  
       beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  
       //当Bean读取器读取Bean定义的Xml资源文件时,启用Xml的校验机制  
       initBeanDefinitionReader(beanDefinitionReader);  
       //Bean读取器真正实现加载的方法  
       loadBeanDefinitions(beanDefinitionReader);  
   }  

 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  
       //获取Bean定义资源的定位  
       Resource[] configResources = getConfigResources();  
       if (configResources != null) {  
           reader.loadBeanDefinitions(configResources);  
       }  
       String[] configLocations = getConfigLocations();  
       if (configLocations != null) { 
           reader.loadBeanDefinitions(configLocations);  
       }  
   }  

AbstractBeanDefinitionReader reader.loadBeanDefinitions

public int loadBeanDefinitions(Resource... resources) throws BeanDefinitionStoreException {
       Assert.notNull(resources, "Resource array must not be null");
       int counter = 0;
       for (Resource resource : resources) {
             counter += loadBeanDefinitions(resource);
       }
       return counter;
}

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

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {  
       //获取在IoC容器初始化过程中设置的资源加载器  
       ResourceLoader resourceLoader = getResourceLoader();  
       if (resourceLoader == null) {  
           throw new BeanDefinitionStoreException(  
                   "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");  
       }  
       if (resourceLoader instanceof ResourcePatternResolver) {  
           try {  
               //加载多个指定位置的Bean定义资源文件  
               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 {  
       	    // 加载单个资源
           int loadCount = loadBeanDefinitions(resource);  
           if (actualResources != null) {  
               actualResources.add(resource);  
           }  
           if (logger.isDebugEnabled()) {  
               logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");  
           }  
           return loadCount;  
       }  
   }  

从AbstractBeanDefinitionReader的loadBeanDefinitions方法分析可以知道容器主要做了以下两件事情:
(1)调用资源加载器的获取资源方法resourceLoader.getResource(location),获取到加载的资源。
(2)加载Bean定义。这里通过委派子类的loadBeanDefinition方法来实现。
在这个过程中,有几个点,我比较想关注的:
1.Spring解析多个资源文件时,是如何做到模糊匹配资源路径加载的?
2.如何从资源文件映射程Spring容器所识别的Bean定义?

以下围绕这两点来看下。
关于第一个问题,可以透过这行代码进行分析:

   Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);  

关于ResourePatternResolver我们可以解析出他的类层次图。
在这里插入图片描述

可以看到,具体的实现是通过PathMatchingResourcePatternResolver
进到里面看它里面的源码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值