【Spring源码--IOC容器的实现】(四)BeanDefinition的注册

来源:互联网 发布:mac比较好用的浏览器 编辑:程序博客网 时间:2024/05/29 01:52
  • 前言

  1. 本篇是IOC容器启动的最后一遍,也就是注册。但并不是DI(依赖注入)已经完成,这里只是完成对xml文件的解析、IOC容器的启动,具体的依赖注入需要getBean的时候完成。但是也有一个例外:那就是通过控制lazy-init属性来让容器实现对bean的预实例化。这个后面我们在讲。
  2. 当代码读到这里,可以再针对前面的代码有目的的去回顾一下,先走通主线,再根据注释尽量去理解一些周边方法。
  • BeanDefinition在IOC容器注册

    首先我们要回忆两点:1、发起注册的地方;2、注册的实现类。
    我们先来看第一点,上一篇博客前半部分我们讲了Bean的解析,在DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法中,其中一个是去完成BeanDefinition的载入,另一个是完成注册。我们先来看下简略代码:

    代码1.1:DefaultBeanDefinitionDocumentReader类的processBeanDefinition方法

    1. protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    2. //解析方法
    3. BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    4. if (bdHolder != null) {
    5. bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
    6. try {
    7. //注册方法
    8. BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
    9. }
    10. catch (BeanDefinitionStoreException ex) {
    11. getReaderContext().error("Failed to register bean definition with name '" +
    12. bdHolder.getBeanName() + "'", ele, ex);
    13. }
    14. getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    15. }
    16. }

    现在我们找到了BeanDefinition的注册入口,我们知道BeanDefinitionHolder=BeanDefinition+beanName,所以这里数据我们是有的,来看下registerBeanDefinition的代码:

    代码1.2:BeanDefinitionReaderUtils类的registerBeanDefinition方法

    1. public static void registerBeanDefinition(
    2. BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry)
    3. throws BeanDefinitionStoreException {
    4. // 根据beanName注册Beandefinition.
    5. String beanName = definitionHolder.getBeanName();
    6. registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());
    7. // 如果有别名,注册别名
    8. String[] aliases = definitionHolder.getAliases();
    9. if (aliases != null) {
    10. for (String aliase : aliases) {
    11. registry.registerAlias(beanName, aliase);
    12. }
    13. }
    14. }

    这里我们需要回忆第二点了,因为当我们找这个registerBeanDefinition的实现类的时候,会发现有三个实现类,那么具体取哪个?还记得我们最初容器建立的时候用的是什么容器么?简单回顾下代码:

    代码1.3:AbstractRefreshableApplicationContext类的refreshBeanFactory方法

    1. @Override
    2. protected final void refreshBeanFactory() throws BeansException {
    3. if (hasBeanFactory()) {
    4. destroyBeans();
    5. closeBeanFactory();
    6. }
    7. try {
    8. //创建Factory
    9. DefaultListableBeanFactory beanFactory = createBeanFactory();
    10. beanFactory.setSerializationId(getId());
    11. customizeBeanFactory(beanFactory);
    12. loadBeanDefinitions(beanFactory);
    13. synchronized (this.beanFactoryMonitor) {
    14. this.beanFactory = beanFactory;
    15. }
    16. }
    17. catch (IOException ex) {
    18. throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
    19. }
    20. }

    而且,我们看下这个DefaultListFactory实现了BeanDefinitionRegistry接口,这个接口就是定义注册的。并且这个类中有这么一个HashMap,这里就是我们存放BeanDefinition的地方。

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

    那么我们继续来看代码:

    代码1.4:DefaultListableBeanFactory类的registerBeanDefinition方法

    1. public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
    2. throws BeanDefinitionStoreException {
    3. Assert.hasText(beanName, "Bean name must not be empty");
    4. Assert.notNull(beanDefinition, "BeanDefinition must not be null");
    5. //校验解析的BeanDefiniton
    6. if (beanDefinition instanceof AbstractBeanDefinition) {
    7. try {
    8. ((AbstractBeanDefinition) beanDefinition).validate();
    9. }
    10. catch (BeanDefinitionValidationException ex) {
    11. throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
    12. "Validation of bean definition failed", ex);
    13. }
    14. }
    15. //注册的过程中需要线程同步,以保证数据的一致性
    16. synchronized (this.beanDefinitionMap) {
    17. Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);
    18. //检查是否有同名的BeanDefinition已经在IoC容器中注册,如果已经注册,
    19. //并且不允许覆盖已注册的Bean,则抛出注册失败异常
    20. if (oldBeanDefinition != null) {
    21. if (!this.allowBeanDefinitionOverriding) {
    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 {//如果允许覆盖,则同名的Bean,后注册的覆盖先注册的
    27. if (this.logger.isInfoEnabled()) {
    28. this.logger.info("Overriding bean definition for bean '" + beanName +
    29. "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
    30. }
    31. }
    32. }
    33. else {
    34. //IoC容器中没有已经注册同名的Bean,按正常注册流程注册
    35. this.beanDefinitionNames.add(beanName);
    36. this.frozenBeanDefinitionNames = null;
    37. }
    38. this.beanDefinitionMap.put(beanName, beanDefinition);
    39. //重置所有已经注册过的BeanDefinition的缓存
    40. resetBeanDefinition(beanName);
    41. }
    42. }

    完了,这就结束了。到这里,代码就完成了IOC容器的初始化过程。此时,在使用的IOC容器DefaultListableBeanFactory中已经建立了整个Bean的配置信息,而且这些BeanDefinition已经可以被容器使用了,他们都在beanDefinitionMap中北检索和使用。容器的作用就是对这些信息进行处理和维护。这些信息室容器建立依赖反转的基础,有了这些基础数据,就可以完成最后的依赖注入了。

0 0