关闭

Spring Bean研究

2199人阅读 评论(0) 收藏 举报
分类:

1.Spring IOC容器装载及注册bean的过程

ApplicationContext context = newClassPathXmlApplicationContext(

               new String[] {"applicationContext-aop1.xml"});

其中ClassPathXmlApplicationContext继承抽象类AbstractApplicationContext

上面那行代码的通过调用ClassPathXmlApplicationContext的构造函数,调用AbstractApplicationContext的refresh()方法,实现IOC容器读取配置源数据,实例化,配置和组装bean。

由于Spring,每实例化一次ClassPathXmlApplicationContext,就会对应于一个beanFactory,也就是说一个IOC容器对应一个beanFactory,所以在IOC容器读取配置源数据,实例化,配置和组装bean前,要刷新beanFactory,并获取刷新后的beanFactory。

抽象类AbstractRefreshableApplicationContext继承抽象类AbstractApplicationContext,并实现AbstractApplicationContextrefreshBeanFactory()刷新beanFactory.

/**

     * This implementation performs an actual refresh of this context's underlying

     * bean factory, shutting down the previous bean factory (if any) and

     * initializing a fresh bean factory for the next phase of the context's lifecycle.

     */

    @Override

    protectedfinalvoid refreshBeanFactory() throws BeansException {

      if (hasBeanFactory()) {

           destroyBeans();

           closeBeanFactory();

       }

       try {

             //创建一个DefaultListableBeanFactory的beanFactory

           DefaultListableBeanFactory beanFactory = createBeanFactory();

           beanFactory.setSerializationId(getId());

           customizeBeanFactory(beanFactory);

             //这段代码是真正意义上的通过创建的beanFactory,读取源配置文件以及装载bean。

           loadBeanDefinitions(beanFactory);

           synchronized (this.beanFactoryMonitor) {

              this.beanFactory = beanFactory;

           }

       }

       catch (IOException ex) {

           thrownew ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);

       }

    }

从上面的代码可以看出,在创建beanFactory的时候,要判断是否已经存在beanFactory,如果存在就销毁,并关闭beanFactory。

  抽象类AbstractXmlApplicationContext继承抽象类AbstractRefreshableApplicationContext,并实现loadBeanDefinitions()抽象方法。

/**

     * Loads the bean definitions via an XmlBeanDefinitionReader.

     * @see org.springframework.beans.factory.xml.XmlBeanDefinitionReader

     * @see #initBeanDefinitionReader

     * @see #loadBeanDefinitions

     */

    @Override

    protectedvoid 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.setEnvironment(this.getEnvironment());

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

        //解析并装载bean

       loadBeanDefinitions(beanDefinitionReader);

    }

从loadBeanDefinitions()方法可以看出,Spring主要是通过XmlBeanDefinitionReader来解析源配置文件。

/**

     * Load the bean definitions with the given XmlBeanDefinitionReader.

     * <p>The lifecycle of the bean factory is handled by the {@link #refreshBeanFactory}

     * method; hence this method is just supposed to load and/or register bean definitions.

     * @param reader the XmlBeanDefinitionReader to use

     * @throws BeansException in case of bean registration errors

     * @throws IOException if the required XML document isn't found

     * @see #refreshBeanFactory

     * @see #getConfigLocations

     * @see #getResources

     * @see #getResourcePatternResolver

     */

    protectedvoidloadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

      Resource[] configResources = getConfigResources();

       if (configResources != null) {

           reader.loadBeanDefinitions(configResources);

       }

       String[] configLocations = getConfigLocations();

       if (configLocations != null) {

           reader.loadBeanDefinitions(configLocations);

       }

    }

调用XmlBeanDefinitionReader的子类AbstractBeanDefinitionReaderloadBeanDefinitions()方法

/**

     * Load bean definitions from the specified resource location.

     * <p>The location can also be a location pattern, provided that the

     * ResourceLoader of this bean definition reader is a ResourcePatternResolver.

     * @param location the resource location, to be loaded with the ResourceLoader

     * (or ResourcePatternResolver) of this bean definition reader

     * @param actualResources a Set to be filled with the actual Resource objects

     * that have been resolved during the loading process. May be <code>null</code>

     * to indicate that the caller is not interested in those Resource objects.

     * @return the number of bean definitions found

     * @throws BeanDefinitionStoreException in case of loading or parsing errors

     * @see #getResourceLoader()

     * @see #loadBeanDefinitions(org.springframework.core.io.Resource)

     * @see #loadBeanDefinitions(org.springframework.core.io.Resource[])

     */

    publicint loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {

      ResourceLoader resourceLoader = getResourceLoader();

       if (resourceLoader == null) {

           thrownew BeanDefinitionStoreException(

                  "Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");

       }

 

       if (resourceLoader instanceof ResourcePatternResolver) {

           // Resource pattern matching available.

           try {

                 //获取配置文件的path

              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) {

              thrownew 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;

       }

    }

其实正在意义上读取xml文件里面的信息,主要是通过XmlBeanDefinitionReader里面的loadBeanDefinitions()方法

/**

     * Load bean definitions from the specified XML file.

     * @param encodedResource the resource descriptor for the XML file,

     * allowing to specify an encoding to use for parsing the file

     * @return the number of bean definitions found

     * @throws BeanDefinitionStoreException in case of loading or parsing errors

     */

    publicint loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

       Assert.notNull(encodedResource, "EncodedResource must not be null");

       if (logger.isInfoEnabled()) {

           logger.info("Loading XML bean definitions from " + encodedResource.getResource());

       }

 

       Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();

       if (currentResources == null) {

           currentResources = new HashSet<EncodedResource>(4);

           this.resourcesCurrentlyBeingLoaded.set(currentResources);

       }

       if (!currentResources.add(encodedResource)) {

           thrownew BeanDefinitionStoreException(

                  "Detected cyclic loading of " + encodedResource + " - check your import definitions!");

       }

       try {

            //通过传入的Resources(包含配置文件的path),进行I/O操作,读取配置文件

           InputStream inputStream = encodedResource.getResource().getInputStream();

           try {

              InputSourceinputSource = new InputSource(inputStream);

              if (encodedResource.getEncoding() != null) {

                 inputSource.setEncoding(encodedResource.getEncoding());

              }

              return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

           }

           finally {

              inputStream.close();

           }

       }

       catch (IOException ex) {

           thrownew BeanDefinitionStoreException(

                  "IOException parsing XML document from " + encodedResource.getResource(), ex);

       }

       finally {

           currentResources.remove(encodedResource);

           if (currentResources.isEmpty()) {

              this.resourcesCurrentlyBeingLoaded.remove();

           }

       }

    }

最后通过XmlBeanDefinitionReader里面的doLoadBeanDefinitions,读取数据,当然如果我们自己实现Spring的IOC的时候,也是基于DOM编程,一层层的读取节点。

/**

     * Actually load bean definitions from the specified XML file.

     * @param inputSource the SAX InputSource to read from

     * @param resource the resource descriptor for the XML file

     * @return the number of bean definitions found

     * @throws BeanDefinitionStoreException in case of loading or parsing errors

     */

    protectedint doLoadBeanDefinitions(InputSource inputSource, Resource resource)

           throws BeanDefinitionStoreException {

       try {

           int validationMode = getValidationModeForResource(resource);

          Document doc =this.documentLoader.loadDocument(

                  inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());

           return registerBeanDefinitions(doc, resource);

       }

       catch (BeanDefinitionStoreException ex) {

           throw ex;

       }

       catch (SAXParseException ex) {

           thrownew XmlBeanDefinitionStoreException(resource.getDescription(),

                  "Line " + ex.getLineNumber() + " in XML document from " + resource + " is invalid", ex);

       }

       catch (SAXException ex) {

           thrownew XmlBeanDefinitionStoreException(resource.getDescription(),

                  "XML document from " + resource + " is invalid", ex);

       }

       catch (ParserConfigurationException ex) {

           thrownew BeanDefinitionStoreException(resource.getDescription(),

                  "Parser configuration exception parsing XML from " + resource, ex);

       }

       catch (IOException ex) {

           thrownew BeanDefinitionStoreException(resource.getDescription(),

                  "IOException parsing XML document from " + resource, ex);

       }

       catch (Throwable ex) {

           thrownew BeanDefinitionStoreException(resource.getDescription(),

                  "Unexpected exception parsing XML document from " + resource, ex);

       }

    }

由于SpringIOC容器创建bean的目的是要事后用的,所以必须得注册bean,会调用DefaultBeanDefinitionDocumentReader的doRegisterBeanDefinitions().

/**

     * Register each bean definition within the given root {@code <beans/>} element.

     * @throws IllegalStateException if {@code <beans profile="..."} attribute is present

     * and Environment property has not been set

     * @see #setEnvironment

     */

    protectedvoid doRegisterBeanDefinitions(Element root) {

       String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);

       if (StringUtils.hasText(profileSpec)) {

           Assert.state(this.environment != null, "environment property must not be null");

           String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);

           if (!this.environment.acceptsProfiles(specifiedProfiles)) {

              return;

           }

       }

 

       // any nested <beans> elements will cause recursion in this method. In

       // order to propagate and preserve <beans> default-* attributes correctly,

       // keep track of the current (parent) delegate, which may be null. Create

       // the new (child) delegate with a reference to the parent for fallback purposes,

       // then ultimately reset this.delegate back to its original (parent) reference.

       // this behavior emulates a stack of delegates without actually necessitating one.

        // BeanDefinitionParserDelegate有状态委托类用于解析XML bean定义

       BeanDefinitionParserDelegate parent = this.delegate;

      this.delegate = createHelper(readerContext, root, parent);

 

       preProcessXml(root);

        //通过这行代码解析配置文件,当然root肯定是xml文件的跟,比如beans

       parseBeanDefinitions(root, this.delegate);

       postProcessXml(root);

 

       this.delegate = parent;

    }

在BeanDefinitionParserDelegate定义了在配置文件中所有的属性标签

publicstaticfinal StringNAME_ATTRIBUTE = "name";

publicstaticfinal StringBEAN_ELEMENT = "bean";

publicstaticfinal StringMETA_ELEMENT = "meta";

publicstaticfinal StringID_ATTRIBUTE = "id";

publicstaticfinal StringPARENT_ATTRIBUTE = "parent";

publicstaticfinal StringCLASS_ATTRIBUTE = "class";

publicstaticfinal StringABSTRACT_ATTRIBUTE = "abstract";

publicstaticfinal StringSCOPE_ATTRIBUTE = "scope";

Spring中具体解析xml文件代码如下:

/**

     * Parse the elements at the root level in the document:

     * "import", "alias", "bean".

     * @param root the DOM root element of the document

     */

    protectedvoid parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {

       if (delegate.isDefaultNamespace(root)) {

           NodeList nl = root.getChildNodes();

           for (int i = 0; i < nl.getLength(); i++) {

              Node node = nl.item(i);

             if (nodeinstanceof Element) {

                  Element ele = (Element) node;

                  if (delegate.isDefaultNamespace(ele)) {

                     parseDefaultElement(ele, delegate);

                  }

                  else {

                     delegate.parseCustomElement(ele);

                  }

              }

           }

       }

       else {

           delegate.parseCustomElement(root);

       }

    }

当然Spring对bean的定义主要是放在接口BeanDefinition中。注册bean主要是通过BeanDefinitionRegistryregisterBeanDefinition()方法。如下的方法中传入的是封装了BeanDefinition的BeanDefinitionHolder以及BeanDefinitionRegistry。

/**

     * Register the given bean definition with the given bean factory.

     * @param definitionHolder the bean definition including name and aliases

     * @param registry the bean factory to register with

     * @throws BeanDefinitionStoreException if registration failed

     */

    publicstaticvoid registerBeanDefinition(

           BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)

           throws BeanDefinitionStoreException {

 

       // Register bean definition under primary name.

        // 得到bean的名字

      String beanName = definitionHolder.getBeanName();

        //注册bean到DefaultListableBeanFactory的bean工厂,传入bean的名称以及包含bean数据的BeanDefinition       registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

 

       // Register aliases for bean name, if any.

       String[] aliases = definitionHolder.getAliases();

       if (aliases != null) {

           for (String aliase :aliases) {

              registry.registerAlias(beanName, aliase);

           }

       }

    }

 

Spring在刷新beanFactory的时候,创建一个DefaultListableBeanFactory的beanFactory。

DefaultListableBeanFactory是继承BeanDefinitionRegistry类的,所以它实现了BeanDefinitionRegistry中的注册方法,如下:

//---------------------------------------------------------------------

    // Implementation of BeanDefinitionRegistry interface

    //---------------------------------------------------------------------

 

    publicvoid registerBeanDefinition(String beanName, BeanDefinition beanDefinition)

           throws BeanDefinitionStoreException {

 

       Assert.hasText(beanName, "Bean name must not be empty");

      Assert.notNull(beanDefinition,"BeanDefinition must not be null");

 

       if (beanDefinition instanceof AbstractBeanDefinition) {

           try {

              ((AbstractBeanDefinition) beanDefinition).validate();

           }

           catch (BeanDefinitionValidationException ex) {

              thrownew BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,

                     "Validation of bean definition failed", ex);

           }

       }

 

       synchronized (this.beanDefinitionMap) {

           Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);

           if (oldBeanDefinition != null) {

              if (!this.allowBeanDefinitionOverriding) {

                  thrownew BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,

                         "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +

                         "': There is already [" + oldBeanDefinition + "] bound.");

              }

              else {

                  if (this.logger.isInfoEnabled()) {

                     this.logger.info("Overriding bean definition for bean '" + beanName +

                            "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");

                  }

              }

           }

           else {

              this.beanDefinitionNames.add(beanName);

              this.frozenBeanDefinitionNames = null;

           }

           this.beanDefinitionMap.put(beanName, beanDefinition);

           resetBeanDefinition(beanName);

       }

    }

如果创建的bean为单例类型,就会调用如下方法:

/**

     * Destroy the given bean. Delegates to <code>destroyBean</code>

     * if a corresponding disposable bean instance is found.

     * @param beanName the name of the bean

     * @see #destroyBean

     */

    publicvoid destroySingleton(String beanName) {

       // Remove a registered singleton of the given name, if any.

      removeSingleton(beanName);

       // Destroy the corresponding DisposableBean instance.

       DisposableBean disposableBean;

       synchronized (this.disposableBeans) {

           disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);

       }

      destroyBean(beanName, disposableBean);

    }

删除依赖于这个单例bean的其他的bean,这一点Spring做的很好。

/**

     * Destroy the given bean. Must destroy beans that depend on the given

     * bean before the bean itself. Should not throw any exceptions.

     * @param beanName the name of the bean

     * @param bean the bean instance to destroy

     */

    protectedvoid destroyBean(String beanName, DisposableBean bean) {

       // Trigger destruction of dependent beans first...

       Set<String> dependencies = this.dependentBeanMap.remove(beanName);

       if (dependencies != null) {

           if (logger.isDebugEnabled()) {

              logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);

           }

           for (String dependentBeanName : dependencies) {

              destroySingleton(dependentBeanName);

           }

       }

       // Actually destroy the bean now...

       if (bean != null) {

           try {

              bean.destroy();

           }

           catch (Throwable ex) {

              logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);

           }

       }

       // Trigger destruction of contained beans...

       Set<String> containedBeans = this.containedBeanMap.remove(beanName);

       if (containedBeans != null) {

           for (String containedBeanName : containedBeans) {

              destroySingleton(containedBeanName);

           }

       }

       // Remove destroyed bean from other beans' dependencies.

       synchronized (this.dependentBeanMap) {

           for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {

              Map.Entry<String, Set<String>> entry = it.next();

              Set<String> dependenciesToClean = entry.getValue();

              dependenciesToClean.remove(beanName);

              if (dependenciesToClean.isEmpty()) {

                  it.remove();

              }

           }

       }

       // Remove destroyed bean's prepared dependency information.

      this.dependenciesForBeanMap.remove(beanName);

    }

  spring会在DefaultListableBeanFactory中完成bean的注册,包括注册bean的名称。

  定义bean的BeanDefinition以key为bean的名称,value为BeanDefinition封装到一个ConcurrentHashMap中,而bean的名称封装到ArrayList中。

/** Map of bean definition objects, keyed by bean name */
 private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();

 /** List of bean definition names, in registration order */
 private final List<String> beanDefinitionNames = new ArrayList<String>();

 

注册beanDefinitionMap是在同步方法块中进行的(synchronized),确保线程安全。

synchronized (this.beanDefinitionMap) {
   Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
   if (oldBeanDefinition != null) {
    if (!this.allowBeanDefinitionOverriding) {
     throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
       "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName +
       "': There is already [" + oldBeanDefinition + "] bound.");
    }
    else {
     if (this.logger.isInfoEnabled()) {
      this.logger.info("Overriding bean definition for bean '" + beanName +
        "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
     }
    }
   }
   else {
    this.beanDefinitionNames.add(beanName);
    this.frozenBeanDefinitionNames = null;
   }
   this.beanDefinitionMap.put(beanName, beanDefinition);

   resetBeanDefinition(beanName);
  }

最后Spring还会注册别名

// Register aliases for bean name, if any.
  String[] aliases = definitionHolder.getAliases();
  if (aliases != null) {
   for (String aliase : aliases) {
    registry.registerAlias(beanName, aliase);
   }
  }

2.Spring IOC容器getbean的过程

     1)调用AbstractApplicationContext的getBean

//---------------------------------------------------------------------
 // Implementation of BeanFactory interface
 //---------------------------------------------------------------------

 public Object getBean(String name) throws BeansException {
  return getBeanFactory().getBean(name);
 }

//---------------------------------------------------------------------
 // Implementation of BeanFactory interface
 //---------------------------------------------------------------------

AbstractBeanFactory的getBean 

public Object getBean(String name) throws BeansException {
  return doGetBean(name, null, null, false);
 }

DefaultSingletonBeanRegistry的getSingleton

在获取bean之前,会先查找单例Bean实例的cache

/** Cache of singleton objects: bean name --> bean instance */
 private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>();

/**
  * Return the (raw) singleton object registered under the given name.
  * <p>Checks already instantiated singletons and also allows for an early
  * reference to a currently created singleton (resolving a circular reference).
  * @param beanName the name of the bean to look for
  * @param allowEarlyReference whether early references should be created or not
  * @return the registered singleton object, or <code>null</code> if none found
  */
 protected Object getSingleton(String beanName, boolean allowEarlyReference) {
  Object singletonObject = this.singletonObjects.get(beanName);
  if (singletonObject == null) {
   synchronized (this.singletonObjects) {
    singletonObject = this.earlySingletonObjects.get(beanName);
    if (singletonObject == null && allowEarlyReference) {
     ObjectFactory singletonFactory = this.singletonFactories.get(beanName);
     if (singletonFactory != null) {
      singletonObject = singletonFactory.getObject();
      this.earlySingletonObjects.put(beanName, singletonObject);
      this.singletonFactories.remove(beanName);
     }
    }
   }
  }
  return (singletonObject != NULL_OBJECT ? singletonObject : null);
 }

 补充:Spring是默认在IOC容器初始化的过程中会,依赖注入所有已经定义好的单例bean,并存在单例缓存之中,你也可以通过在xml的bean的定义中设置延迟加载为false。

0
1

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:65950次
    • 积分:994
    • 等级:
    • 排名:千里之外
    • 原创:32篇
    • 转载:9篇
    • 译文:1篇
    • 评论:19条
    文章分类
    最新评论