zoukankan      html  css  js  c++  java
  • Spring IOC(二)容器初始化

    本系列目录:

    Spring IOC(一)概览

    Spring IOC(二)容器初始化

    Spring IOC(三)依赖注入

    Spring IOC(四)总结

    目录

    一、ApplicationContext接口设计

    二、深入源码,看IOC容器初始化

    ===========正文分割线===========

    前面一篇概览了IOC容器的接口设计。

    本文从ApplicationContext接口的一个实现类ClassPathXmlApplicationContext入手,分析容器初始化过程。先看一下ApplicationContext接口设计:

    一、ApplicationContext接口设计

    ApplicationContext是spring中较高级的容器。和BeanFactory类似,它可以加载配置文件中定义的bean,当有请求的时候分配bean。 另外,它增加了企业所需要的功能,比如,从属性文件解析文本信息和将事件传递给所指定的监听器。接口设计图如下:

    ApplicationContext继承5个接口:

    1.2个核心接口:

    ListableBeanFactory:支持获取bean 工厂的所有bean实例

    HierarchicalBeanFactory:支持继承关系

    2.3个拓展接口:

    MessageSource:提供国际化支持

    ApplicationEventPublisher:支持事件驱动模型中的事件发布器,这些事件和Bean的生命周期的结合为Bean的管理提供了便利。

    ResourcePatternResolver:资源解析器

    常见实现类:

    1.FileSystemXmlApplicationContext:从指定文件地址的加载xml定义的bean

    2.ClassPathXmlApplicationContext:从类路径下载入xml定义的bean

    3.XmlWebApplicationContext:web 应用程序的范围内载入xml定义的bean

    二、深入源码,看IOC容器初始化

    为了方便理解和追踪代码,使用常用实现类ClassPathXmlApplicationContext写了一个小例子,步骤如下:

    1).在类路径下新建xml,定义一个bean,其中daoImpl就是bean的名字,spring.aop.xml.dao.impl.DaoImpl对应具体的一个pojo.

     1 <bean id="daoImpl" class="spring.aop.xml.dao.impl.DaoImpl" /> 

    2).main方法中直接载入xml,然后获取bean,最后执行bean实例的方法。

    1     public static void main(String[] args) {
    2         //源码入口,从类路径下读取xml
    3         ApplicationContext ac1 = new ClassPathXmlApplicationContext("aop.xml");
    4         Dao dao = (Dao)ac1.getBean("daoImpl");//根据名称获取Bean
    5         dao.select();//执行Bean实例方法    
    }

    下面我们就分析ClassPathXmlApplicationContext源码,来看看都做了什么。

    2.1ClassPathXmlApplicationContext类图

    DefaultResourceLoader,该类设置classLoader,并且将配置文件 封装为Resource文件。

    AbstractApplicationContext,该类完成了大部分的IOC容器初始化工作,同时也提供了扩展接口留给子类去重载。该类的refresh()函数是核心初始化操作。

    AbstractRefreshableApplicationContext,该类支持刷新BeanFactory。

    AbstractRefreshableConfigApplicationContext,该类保存了配置文件路径

    AbstractXmlApplicationContext:该类支持解析bean定义文件

    最后ClassPathXmlApplicationContext:只提供了一个简单的构造函数

    Spring 将类职责分开,形成职责链,每一层次的扩展 都只是添加了某个功能

    然后父类定义大量的模板,让子类实现,父类层层传递到子类 直到某个子类重载了抽象方法。这里应用到了职责链设计模式和模板设计模式,IOC是个容器工厂设计模式。

    2.2 回顾上面的小例子,new ClassPathXmlApplicationContext("aop.xml");这行代码做了什么?

    1 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
    2         throws BeansException {
    3 
    4     super(parent);//把ApplicationContext作为父容器,上述测试类中由于直接载入的xml,没有父容器所以实际传了null
    5 setConfigLocations(configLocations);//替换${}后设置配置路径 6 if (refresh) { 7 refresh();//核心方法 8 } 9 }

    ClassPathXmlApplicationContext的refresh()实际上就是调用了AbstractApplicationContextrefresh()方法。全方法被synchronized同步块锁住,源码如下:

     1 public void refresh() throws BeansException, IllegalStateException {
     2         synchronized (this.startupShutdownMonitor) {
     3             //准备刷新的上下文环境,例如对系统属性或者环境变量进行准备及验证。
     4             prepareRefresh();
     5 
     6             //启动子类的refreshBeanFactory方法.解析xml
     7             ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
     8 
     9             //为BeanFactory配置容器特性,例如类加载器、事件处理器等.
    10             prepareBeanFactory(beanFactory);
    11 
    12             try {
    13                 //设置BeanFactory的后置处理. 空方法,留给子类拓展用。 
    14                 postProcessBeanFactory(beanFactory);
    15 
    16                 //调用BeanFactory的后处理器, 这些后处理器是在Bean定义中向容器注册的.  
    17                 invokeBeanFactoryPostProcessors(beanFactory);
    18 
    19                 //注册Bean的后处理器, 在Bean创建过程中调用.  
    20                 registerBeanPostProcessors(beanFactory);
    21 
    22                 //初始化上下文中的消息源,即不同语言的消息体进行国际化处理  
    23                 initMessageSource();
    24 
    25                 //初始化ApplicationEventMulticaster bean,应用事件广播器
    26                 initApplicationEventMulticaster();
    27 
    28                 //初始化其它特殊的Bean, 空方法,留给子类拓展用。 
    29                 onRefresh();
    30 
    31                 //检查并向容器注册监听器Bean
    32                 registerListeners();
    33 
    34                 //实例化所有剩余的(non-lazy-init) 单例Bean.
    35                 finishBeanFactoryInitialization(beanFactory);
    36 
    37                 //发布容器事件, 结束refresh过程. 
    38                 finishRefresh();
    39             }
    40 
    41             catch (BeansException ex) {
    42                 if (logger.isWarnEnabled()) {
    43                     logger.warn("Exception encountered during context initialization - " +
    44                             "cancelling refresh attempt: " + ex);
    45                 }
    46 
    47                 //销毁已经创建的单例Bean, 以避免资源占用.
    48                 destroyBeans();
    49 
    50                 //取消refresh操作, 重置active标志. 
    51                 cancelRefresh(ex);
    52 
    53                 // Propagate exception to caller.
    54                 throw ex;
    55             }
    56 
    57             finally {
    58                 //重置Spring的核心缓存
    60                 resetCommonCaches();
    61             }
    62         }
    63     }

    2.3 Resources定位

    refresh方法obtainFreshBeanFactory方法调用了refreshBeanFactory,该方法使用DefaultListableBeanFactory去定位resources资源

     1 protected final void refreshBeanFactory() throws BeansException {
     2         if (hasBeanFactory()) {
     3             destroyBeans();
     4             closeBeanFactory();
     5         }
     6         try {//创建并设置DefaultListableBeanFactory同时调用loadBeanDefinitions载入loadBeanDefinition
     7             DefaultListableBeanFactory beanFactory = createBeanFactory();
     8             beanFactory.setSerializationId(getId());
     9             customizeBeanFactory(beanFactory);
    10             loadBeanDefinitions(beanFactory);//核心方法
    11             synchronized (this.beanFactoryMonitor) {
    12                 this.beanFactory = beanFactory;
    13             }
    14         }
    15         catch (IOException ex) {
    16             throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    17         }
    18     }

    loadBeanDefinitions其具体实现在AbstractXmlApplicationContext中,定义了一个Reader作为入参执行载入过程:

     1 protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
     2         // 为给定的bean工厂创建一个reader
     3         XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
     4 
     5         // Configure the bean definition reader with this context's
     6         // resource loading environment.
     7         beanDefinitionReader.setEnvironment(this.getEnvironment());
     8         beanDefinitionReader.setResourceLoader(this);
     9         beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
    10 
    11         // Allow a subclass to provide custom initialization of the reader,
    12         // then proceed with actually loading the bean definitions.
    13         initBeanDefinitionReader(beanDefinitionReader);
    14         loadBeanDefinitions(beanDefinitionReader);//核心方法
    15     }
    loadBeanDefinitions方法如下:
     1 protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
     2         Resource[] configResources = getConfigResources();
     3         if (configResources != null) {
     4             reader.loadBeanDefinitions(configResources);
     5         }
     6         String[] configLocations = getConfigLocations();
     7         if (configLocations != null) {
     8             reader.loadBeanDefinitions(configLocations);
     9         }
    10     }

    getConfigResources采用模板方法设计模式,具体的实现由子类完成,实际上这里getConfigResources调用的就是子类ClassPathXmlApplicationContext的getConfigResources方法。ClassPathXmlApplicationContext继承了DefaultResourceLoader,具备了Resource加载资源的功能。至此完成了Resource定位!

    2.4 BeanDefinition载入

    这里支持2种模式:1.模板匹配多资源,生成Resource[]。2.载入单个资源url绝对地址,生成一个Resource

     1 public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
     2         ResourceLoader resourceLoader = getResourceLoader();//获取ResourceLoader资源加载器
     3         if (resourceLoader == null) {
     4             throw new BeanDefinitionStoreException(
     5                     "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
     6         }
     7         // 1.匹配模板解析 ClassPathXmlApplicationContext是ResourcePatternResolver接口的实例
     8         if (resourceLoader instanceof ResourcePatternResolver) {
     9            
    10             try {//接口ResourcePatternResolver
    11                 Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
    12                 int loadCount = loadBeanDefinitions(resources);
    13                 if (actualResources != null) {
    14                     for (Resource resource : resources) {
    15                         actualResources.add(resource);
    16                     }
    17                 }
    18                 if (logger.isDebugEnabled()) {
    19                     logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
    20                 }
    21                 return loadCount;
    22             }
    23             catch (IOException ex) {
    24                 throw new BeanDefinitionStoreException(
    25                         "Could not resolve bean definition resource pattern [" + location + "]", ex);
    26             }
    27         }
    28         else {
    29             // 2.载入单个资源url绝对地址
    30             Resource resource = resourceLoader.getResource(location);
    31             int loadCount = loadBeanDefinitions(resource);
    32             if (actualResources != null) {
    33                 actualResources.add(resource);
    34             }
    35             if (logger.isDebugEnabled()) {
    36                 logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
    37             }
    38             return loadCount;
    39         }
    40     }

    loadBeanDefinitions最终调用XmlBeanDefinitionReader.doLoadBeanDefinitions(),如下:

     1 protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
     2             throws BeanDefinitionStoreException {
     3         try {// 取得xml文件的Document,解析过程是由DocumentLoader完成,默认为DefaultDocumentLoader
     4             Document doc = doLoadDocument(inputSource, resource);
     5             return registerBeanDefinitions(doc, resource);// 启动对BeanDefinition的详细解析过程,这个解析会使用到spring的BEAN配置规则
     6         }
     7         catch (BeanDefinitionStoreException ex) {
     8             throw ex;
     9         }
    10         catch (SAXParseException ex) {
    11             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    12                     "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);
    13         }
    14         catch (SAXException ex) {
    15             throw new XmlBeanDefinitionStoreException(resource.getDescription(),
    16                     "XML document from " + resource + " is invalid", ex);
    17         }
    18         catch (ParserConfigurationException ex) {
    19             throw new BeanDefinitionStoreException(resource.getDescription(),
    20                     "Parser configuration exception parsing XML from " + resource, ex);
    21         }
    22         catch (IOException ex) {
    23             throw new BeanDefinitionStoreException(resource.getDescription(),
    24                     "IOException parsing XML document from " + resource, ex);
    25         }
    26         catch (Throwable ex) {
    27             throw new BeanDefinitionStoreException(resource.getDescription(),
    28                     "Unexpected exception parsing XML document from " + resource, ex);
    29         }
    30     }

    registerBeanDefinitions是按照spring的bean配置规则解析,源码如下:

    1 public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
    2         BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
    3         int countBefore = getRegistry().getBeanDefinitionCount();
    4         documentReader.registerBeanDefinitions(doc, createReaderContext(resource));// 核心方法
    5         return getRegistry().getBeanDefinitionCount() - countBefore;
    6     }

    至此就完成了BeanDefinition的载入,BeanDefinition的载入分为两个部分,

    1.调用xml解析器得到的document对象,但是这个对象并没有按照spring的bean规则进行解析。

    2.DefaultBeanDefinitionDocumentReader的registerBeanDefinitions按照Spring的Bean规则进行解析。

    2.5 BeanDefinition解析和注册

    registerBeanDefinitions方法调用了doRegisterBeanDefinitions

     1 protected void doRegisterBeanDefinitions(Element root) {
     2         // Any nested <beans> elements will cause recursion in this method. In
     3         // order to propagate and preserve <beans> default-* attributes correctly,
     4         // keep track of the current (parent) delegate, which may be null. Create
     5         // the new (child) delegate with a reference to the parent for fallback purposes,
     6         // then ultimately reset this.delegate back to its original (parent) reference.
     7         // this behavior emulates a stack of delegates without actually necessitating one.
     8         BeanDefinitionParserDelegate parent = this.delegate;
     9         this.delegate = createDelegate(getReaderContext(), root, parent);
    10 
    11         if (this.delegate.isDefaultNamespace(root)) {
    12             String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
    13             if (StringUtils.hasText(profileSpec)) {
    14                 String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
    15                         profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
    16                 if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
    17                     if (logger.isInfoEnabled()) {
    18                         logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec +
    19                                 "] not matching: " + getReaderContext().getResource());
    20                     }
    21                     return;
    22                 }
    23             }
    24         }
    25 
    26         preProcessXml(root);
    27         parseBeanDefinitions(root, this.delegate);// 从Document的根元素开始进行Bean定义的Document对象
    28         postProcessXml(root);
    29 
    30         this.delegate = parent;
    31     }
     1 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
     2         if (delegate.isDefaultNamespace(root)) {
     3             NodeList nl = root.getChildNodes();
     4             for (int i = 0; i < nl.getLength(); i++) {
     5                 Node node = nl.item(i);
     6                 if (node instanceof Element) {
     7                     Element ele = (Element) node;
     8                     if (delegate.isDefaultNamespace(ele)) {
     9                         parseDefaultElement(ele, delegate);
    10                     }
    11                     else {
    12                         delegate.parseCustomElement(ele);
    13                     }
    14                 }
    15             }
    16         }
    17         else {
    18             delegate.parseCustomElement(root);
    19         }
    20     }
    21 
    22     private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
    23         if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
    24             importBeanDefinitionResource(ele);
    25         }
    26         else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
    27             processAliasRegistration(ele);
    28         }
    29         else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
    30             processBeanDefinition(ele, delegate);
    31         }
    32         else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
    33             // recurse
    34             doRegisterBeanDefinitions(ele);
    35         }
    36     }
    processBeanDefinition就是对bean标签的解析和注册
     1 protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
     2         BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);// 1.解析
     3         if (bdHolder != null) {
     4             bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);//代理去装饰:典型的装饰器模式
     5             try {
     6                 // 2.向IOC容器注册Bean定义+bean工厂
     7                 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
     8             }
     9             catch (BeanDefinitionStoreException ex) {
    10                 getReaderContext().error("Failed to register bean definition with name '" +
    11                         bdHolder.getBeanName() + "'", ele, ex);
    12             }
    13             // 3.触发注册事件: spring只提供了EmptyReaderEventListener空实现,如果需要你可以自定义
    14             getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    15         }
    16     }

    解析parseBeanDefinitionElement方法就是具体的解析入口。解析elemnent->BeanDefinitionHolder,追踪parseBeanDefinitionElement:

     1 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
     2         String id = ele.getAttribute(ID_ATTRIBUTE);// 获取id
     3         String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);// 获取name
     4 
     5         List<String> aliases = new ArrayList<String>();// 获取别名
     6         if (StringUtils.hasLength(nameAttr)) {
     7             String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);
     8             aliases.addAll(Arrays.asList(nameArr));
     9         }
    10 
    11         String beanName = id;
    12         if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
    13             beanName = aliases.remove(0);
    14             if (logger.isDebugEnabled()) {
    15                 logger.debug("No XML 'id' specified - using '" + beanName +
    16                         "' as bean name and " + aliases + " as aliases");
    17             }
    18         }
    19 
    20         if (containingBean == null) {
    21             checkNameUniqueness(beanName, aliases, ele);
    22         }
    23 
    24         AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);
    25         if (beanDefinition != null) {
    26             if (!StringUtils.hasText(beanName)) {
    27                 try {
    28                     if (containingBean != null) {
    29                         beanName = BeanDefinitionReaderUtils.generateBeanName(
    30                                 beanDefinition, this.readerContext.getRegistry(), true);
    31                     }
    32                     else {
    33                         beanName = this.readerContext.generateBeanName(beanDefinition);
    34                         // Register an alias for the plain bean class name, if still possible,
    35                         // if the generator returned the class name plus a suffix.
    36                         // This is expected for Spring 1.2/2.0 backwards compatibility.
    37                         String beanClassName = beanDefinition.getBeanClassName();
    38                         if (beanClassName != null &&
    39                                 beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
    40                                 !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
    41                             aliases.add(beanClassName);
    42                         }
    43                     }
    44                     if (logger.isDebugEnabled()) {
    45                         logger.debug("Neither XML 'id' nor 'name' specified - " +
    46                                 "using generated bean name [" + beanName + "]");
    47                     }
    48                 }
    49                 catch (Exception ex) {
    50                     error(ex.getMessage(), ele);
    51                     return null;
    52                 }
    53             }
    54             String[] aliasesArray = StringUtils.toStringArray(aliases);
    55             return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
    56         }
    57 
    58         return null;
    59     }

    好吧,parseBeanDefinitionElement才是核心方法,追踪:

     1 public AbstractBeanDefinition parseBeanDefinitionElement(
     2             Element ele, String beanName, BeanDefinition containingBean) {
     3 
     4         this.parseState.push(new BeanEntry(beanName));
     5 
     6         String className = null;
     7         if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
     8             className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
     9         }
    10 
    11         try {
    12             String parent = null;
    13             if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
    14                 parent = ele.getAttribute(PARENT_ATTRIBUTE);
    15             }// 这里生成需要的BeanDefinition对象,为Bean定义信息的载入做准备
    16             AbstractBeanDefinition bd = createBeanDefinition(className, parent);
    17             // 1.解析<bean>元素属性
    18             parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);
    19             bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));//2.解析description
    20             //对各种BEAN元素信息进行解析
    21             parseMetaElements(ele, bd);// 3.解析<meta>子元素
    22             parseLookupOverrideSubElements(ele, bd.getMethodOverrides());//4.解析<lookup-method>子元素
    23             parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//5.解析<replaced-method>子元素
    24 
    25             parseConstructorArgElements(ele, bd);//6.解析<constructor-arg>
    26             parsePropertyElements(ele, bd);//7.解析<property>
    27             parseQualifierElements(ele, bd);//8.解析<qualifier>
    28 
    29             bd.setResource(this.readerContext.getResource());
    30             bd.setSource(extractSource(ele));
    31 
    32             return bd;
    33         }
    34         catch (ClassNotFoundException ex) {
    35             error("Bean class [" + className + "] not found", ele, ex);
    36         }
    37         catch (NoClassDefFoundError err) {
    38             error("Class that bean class [" + className + "] depends on not found", ele, err);
    39         }
    40         catch (Throwable ex) {
    41             error("Unexpected failure during bean definition parsing", ele, ex);
    42         }
    43         finally {
    44             this.parseState.pop();
    45         }
    46 
    47         return null;
    48     }

    经过这样逐层的分析,我们在xml文件中定义的BeanDefinition就被整个载入到IOC容器中,并在容器中建立了数据映射。这些数据结构可以以AbstractBeanDefinition为入口让IOC容器执行索引,查询和操作。

    注册registerBeanDefinition方法就是具体的注册入口。追踪registerBeanDefinition:

     1 public static void registerBeanDefinition(
     2             BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
     3             throws BeanDefinitionStoreException {
     4 
     5         // Register bean definition under primary name.
     6         String beanName = definitionHolder.getBeanName();
     7         registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());//向IoC容器注册BeanDefinition
     8 
     9         // 如果解析的BeanDefinition有别名, 向容器为其注册别名. 
    10         String[] aliases = definitionHolder.getAliases();
    11         if (aliases != null) {
    12             for (String alias : aliases) {
    13                 registry.registerAlias(beanName, alias);
    14             }
    15         }
    16     }

    registerBeanDefinition具体现类:DefaultListableBeanFactory.registerBeanDefinition方法

     1 public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
     2             throws BeanDefinitionStoreException {
     3 
     4         Assert.hasText(beanName, "Bean name must not be empty");
     5         Assert.notNull(beanDefinition, "BeanDefinition must not be null");
     6 
     7         if (beanDefinition instanceof AbstractBeanDefinition) {
     8             try {
     9                 ((AbstractBeanDefinition) beanDefinition).validate();
    10             }
    11             catch (BeanDefinitionValidationException ex) {
    12                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    13                         "Validation of bean definition failed", ex);
    14             }
    15         }
    16 
    17         BeanDefinition oldBeanDefinition;
    18 
    19         oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    20         if (oldBeanDefinition != null) {
    21             if (!isAllowBeanDefinitionOverriding()) {
    22                 throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    23                         "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
    24                         "': There is already [" + oldBeanDefinition + "] bound.");
    25             }
    26             else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) {
    27                 // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE
    28                 if (this.logger.isWarnEnabled()) {
    29                     this.logger.warn("Overriding user-defined bean definition for bean '" + beanName +
    30                             "' with a framework-generated bean definition: replacing [" +
    31                             oldBeanDefinition + "] with [" + beanDefinition + "]");
    32                 }
    33             }
    34             else if (!beanDefinition.equals(oldBeanDefinition)) {
    35                 if (this.logger.isInfoEnabled()) {
    36                     this.logger.info("Overriding bean definition for bean '" + beanName +
    37                             "' with a different definition: replacing [" + oldBeanDefinition +
    38                             "] with [" + beanDefinition + "]");
    39                 }
    40             }
    41             else {
    42                 if (this.logger.isDebugEnabled()) {
    43                     this.logger.debug("Overriding bean definition for bean '" + beanName +
    44                             "' with an equivalent definition: replacing [" + oldBeanDefinition +
    45                             "] with [" + beanDefinition + "]");
    46                 }
    47             }
    48             this.beanDefinitionMap.put(beanName, beanDefinition);
    49         }
    50         else {
    51             if (hasBeanCreationStarted()) {
    52                 // Cannot modify startup-time collection elements anymore (for stable iteration)
    53                 synchronized (this.beanDefinitionMap) {
    54                     this.beanDefinitionMap.put(beanName, beanDefinition);
    55                     List<String> updatedDefinitions = new ArrayList<String>(this.beanDefinitionNames.size() + 1);
    56                     updatedDefinitions.addAll(this.beanDefinitionNames);
    57                     updatedDefinitions.add(beanName);
    58                     this.beanDefinitionNames = updatedDefinitions;
    59                     if (this.manualSingletonNames.contains(beanName)) {
    60                         Set<String> updatedSingletons = new LinkedHashSet<String>(this.manualSingletonNames);
    61                         updatedSingletons.remove(beanName);
    62                         this.manualSingletonNames = updatedSingletons;
    63                     }
    64                 }
    65             }
    66             else {
    67                 // Still in startup registration phase
    68                 this.beanDefinitionMap.put(beanName, beanDefinition);
    69                 this.beanDefinitionNames.add(beanName);
    70                 this.manualSingletonNames.remove(beanName);
    71             }
    72             this.frozenBeanDefinitionNames = null;
    73         }
    74 
    75         if (oldBeanDefinition != null || containsSingleton(beanName)) {
    76             resetBeanDefinition(beanName);
    77         }
    78     }

    完成了BeanDefinition的注册,就完成了IOC容器的初始化过程。容器的作用就是对这些信息进行处理和维护,这些信息就是容器建立依赖反转的基础。

    三、总结

    本文先介绍ApplicationContext接口设计,再从其一个最常见实现类ClassPathXmlApplicationContext写了一个小例子,作为源码追踪的入口。

    追踪了主要包括Resourse定位、BeanDefinition的载入、解析和注册3个模块。至此,容器初始化(Bean已生成)已完成,下一章我们看依赖注入的源码。

  • 相关阅读:
    uoj35 后缀排序
    bzoj1026windy数
    poj2761 feed the dog
    codevs2875RY哥查字典
    bzoj1683[Usaco2005 Nov]City skyline 城市地平线
    codevs2464超级麻将
    初赛乱记
    让NOI Linux变得可用
    [HAOI2015] 按位或
    一句话CF
  • 原文地址:https://www.cnblogs.com/dennyzhangdd/p/7688411.html
Copyright © 2011-2022 走看看