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已生成)已完成,下一章我们看依赖注入的源码。

  • 相关阅读:
    HDU 3681 Prison Break 越狱(状压DP,变形)
    POJ 2411 Mondriaan's Dream (状压DP,骨牌覆盖,经典)
    ZOJ 3471 Most Powerful (状压DP,经典)
    POJ 2288 Islands and Bridges (状压DP,变形)
    HDU 3001 Travelling (状压DP,3进制)
    POJ 3311 Hie with the Pie (状压DP)
    POJ 1185 炮兵阵地 (状压DP,轮廓线DP)
    FZU 2204 7
    POJ 3254 Corn Fields (状压DP,轮廓线DP)
    ZOJ 3494 BCD Code (数位DP,AC自动机)
  • 原文地址:https://www.cnblogs.com/dennyzhangdd/p/7688411.html
Copyright © 2011-2022 走看看