稀土掘金 稀土掘金

《Spring从0到1》:配置创建、注入bean原理

手把手带你看spring的配置创建、注入以及获取bean。

看源码最好的方式就是定义一个最最基本的流程,从开始debug到你认为懂了为止。

bean的配置

最基本的spring配置是将bean配置在spring的配置文件中,该配置文件还可以配置spring的配置属性,虽然标签不是<bean>,但是spring会将其注入到指定的类中,因此不论标签如何,spring都会将配置文件中的属性转化成类属性,最终创建对应的对象。有的朋友可能已经注意到了:配置都是放在<beans>标签中的。

spring配置.jpg

bean的生成与注入

启动spring的入口之一就是创建 ClassPathXmlApplicationContext 对象:

//创建Spring容器的对象:ApplicationContext的实现类 ----> ClassPathXmlApplicationContext
//ApplicationContext就是表示Spring容器,我们可以通过容器获取对象
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");

向下看之前不妨看一下该类的UML关系:

ClassPathXmlApplicationContext_UML.jpg

创建ClassPathXmlApplicationContext对象时就能看到整个spring创建对象的流程:

创建classpathxmlapplicationcontext.jpg 真正调用的是这里: 真正调用点.jpg 这里的setConfigLocations方法只是将传入的配置文件名注入到本类的configLocations字符串数组变量中。

真正的流程是在refresh方法中,该方法的实现其实是在父类AbstractApplicationContext中:

refresh调用点.jpg 将一些与主流程相关较小的代码剔除后如下:

public void refresh() throws BeansException, IllegalStateException {
   //在方法内对别的对象加锁,使得锁最小化。
   synchronized (this.startupShutdownMonitor) {
      //第一步就是创建bean的容器
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

      prepareBeanFactory(beanFactory);

      try {
         
         postProcessBeanFactory(beanFactory);
         
         invokeBeanFactoryPostProcessors(beanFactory);

         registerBeanPostProcessors(beanFactory);

         finishBeanFactoryInitialization(beanFactory);
         
      } catch (BeansException ex) {...}

      finally {
         resetCommonCaches();
         contextRefresh.end();
      }
   }
}

逐步解析:

  1. obtainFreshBeanFactory():

    obtainFreshBeanFactory方法.jpg 其中:refreshBeanFactory() 才是创建beanFactory的关键:其在 AbstractApplicationContext 类中是抽象方法,需要子类实现,通常调用的是 AbstractRefreshableApplicationContext 类。

    refreshBeanFactory.jpg 其中 loadBeanDefinitions(beanFactory) 是最主要的,在子类 AbstractXmlApplicationContextloadBeanDefinitions.jpg loadBeanDefinitions(beanFactory) 创建了 XmlBeanDefinitionReader 对象。该类封装了读配置文件的逻辑。随后就是调用 XmlBeanDefinitionReader的方法 loadBeanDefinitionsreader.jpg 这个方法在其父类 AbstractBeanDefinitionReader 中实现: AbstractBeanDefinitionReader.jpg AbstractBeanDefinitionReader 将字符串类型的配置文件名转化为 Resource 对象,Resource是个接口,继承了InputStreamSource,Spring中对于文件的读取类都需实现该接口。 而通过Resource加载类的方法是在子类 XmlBeanDefinitionReader 实现: loadBeanBefinitions(EncodedReource).jpg 接着就是创建但是真正读配置文件的抽象类:BeanDefinitionDocumentReaderregisterBeanDefinitons.jpg registerBeanDefinitions 在子类 DefaultBeanDefinitionDocumentReader 中实现: doRegisterBeanDefinitions.jpg 然后挨个解析每一个标签 parseBeanDefinitions.jpg 通过工具类加载类定义.jpg 这里的 BeanDefinitionHolder 要注意,这个就是解析bean标签的生成对象,可以看出,bean 标签里设置的属性都在该对象中,没有配置的属性会采用默认值(这也解释了spring中创建的对象默认是懒加载的)。 DefinitionHolder对象.jpg 随后将对象名和类定义放入【DefaultListableBeanFactory】beanDefinitionMap 中。

    而事实上,后续的流程都是针对 DefaultListableBeanFactory类的。 BeanDefinitonReaderUtil.registerBeanDefinition.jpg 放入BeanDefinitonMap.jpg 就此,spring中一个完整的配置文件中bean的解析、注册就结束了!!!

  2. prepareBeanFactory(beanFactory)

    该方法就只是为Spring的BeanFactory赋值。比如后置处理器,添加一些Spring内部对象等:

    /**
     * 配置BeanFactory的一些上下文属性,比如上下文类加载器和后置处理器
     * @param 需要赋值的beanFactory 
     */
    protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
       //使用调用类的类加载器
       beanFactory.setBeanClassLoader(getClassLoader());
       if (!shouldIgnoreSpel) {
          beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
       }
       beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));
    
       // Configure the bean factory with context callbacks.
       beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
       beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
       beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
       beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
       beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
       beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
       beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);
       beanFactory.ignoreDependencyInterface(ApplicationStartupAware.class);
    
       // BeanFactory interface not registered as resolvable type in a plain factory.
       // MessageSource registered (and found for autowiring) as a bean.
       beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
       beanFactory.registerResolvableDependency(ResourceLoader.class, this);
       beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
       beanFactory.registerResolvableDependency(ApplicationContext.class, this);
    
       // Register early post-processor for detecting inner beans as ApplicationListeners.
       beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));
    
       // Detect a LoadTimeWeaver and prepare for weaving, if found.
       if (!NativeDetector.inNativeImage() && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
          beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
          // Set a temporary ClassLoader for type matching.
          beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
       }
    
       // 注册默认的环境类对象
       if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
          beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
       }
       if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
          beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
       }
       if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
          beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
       }
       if (!beanFactory.containsLocalBean(APPLICATION_STARTUP_BEAN_NAME)) {
          beanFactory.registerSingleton(APPLICATION_STARTUP_BEAN_NAME, getApplicationStartup());
       }
    }
    
  3. invokeBeanFactoryPostProcessors(beanFactory):

    该方法主要是加载和实例化 BeanFactory 后置处理器(所有实现了 BeanFactoryPostProcessor 接口的类)。后置处理器可以在 Bean 实例化、属性填充、初始化和销毁等不同的阶段对 Bean 进行自定义的处理和增强。典型的后处理器就是org.mybatis.spring.mapper.MapperScannerConfigurer,该类将指定的mapper接口注册到mybatisConfiguration类的MapperRegistry属性中。

  4. registerBeanPostProcessors(beanFactory):

    主要是将上一步实例化的后置处理器对象添加到 beanFactorybeanPostProcessors 变量中。

  5. finishBeanFactoryInitialization(beanFactory):

    从方法名也能看出该方法是最终的一步:初始化所有的单例模式,所有的非懒加载的类。该方法内封装的其实就是之前构建的 ConfigurableListableBeanFactory 接口实现类的方法,spring中该接口的实现类用的是 DefaultListableBeanFactory

finishBeanFactoryInitialization方法.jpg preInstantiateSingletons.jpg 可以看出,初始化类的时候是会根据类是否是工厂类而作出额外的初始化,最重要的还是 getBean方法。 该方法是 ClassPathXmlApplication 的父类 AbstractApplicationContext 实现的: AbstractBeanDefinitionReader.getBean.jpgdoGetBean 也是 AbstractBeanFactory 实现的:

protected <T> T doGetBean(
      String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
      throws BeansException {

   String beanName = transformedBeanName(name);
   Object beanInstance;

   // 看看有无该类对象的缓存,有则直接返回
   Object sharedInstance = getSingleton(beanName);
   if (sharedInstance != null && args == null) {
      if (logger.isTraceEnabled()) {
         if (isSingletonCurrentlyInCreation(beanName)) {
            logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
                  "' that is not fully initialized yet - a consequence of a circular reference");
         }
         else {
            logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
         }
      }
      beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, null);
   }else {
      if (isPrototypeCurrentlyInCreation(beanName)) {
         throw new BeanCurrentlyInCreationException(beanName);
      }

      // 如果有父类的BeanFactory对象则调用父类BeanFactory独享的doGetBean方法。
      BeanFactory parentBeanFactory = getParentBeanFactory();
      if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
         // Not found -> check parent.
         String nameToLookup = originalBeanName(name);
         if (parentBeanFactory instanceof AbstractBeanFactory) {
            return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
                  nameToLookup, requiredType, args, typeCheckOnly);
         }
         else if (args != null) {
            // Delegation to parent with explicit args.
            return (T) parentBeanFactory.getBean(nameToLookup, args);
         }
         else if (requiredType != null) {
            // No args -> delegate to standard getBean method.
            return parentBeanFactory.getBean(nameToLookup, requiredType);
         }
         else {
            return (T) parentBeanFactory.getBean(nameToLookup);
         }
      }

      if (!typeCheckOnly) {
         markBeanAsCreated(beanName);
      }

      StartupStep beanCreation = this.applicationStartup.start("spring.beans.instantiate")
            .tag("beanName", name);
      try {
         if (requiredType != null) {
            beanCreation.tag("beanType", requiredType::toString);
         }
         RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
         checkMergedBeanDefinition(mbd, beanName, args);

         // 先初始化要初始化对象依赖的对象,其实就是递归调用getBean。
         String[] dependsOn = mbd.getDependsOn();
         if (dependsOn != null) {
            for (String dep : dependsOn) {
               if (isDependent(beanName, dep)) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
               }
               registerDependentBean(dep, beanName);
               try {
               
                  getBean(dep);
               }
               catch (NoSuchBeanDefinitionException ex) {
                  throw new BeanCreationException(mbd.getResourceDescription(), beanName,
                        "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
               }
            }
         }

         // 单例对象的初始化
         if (mbd.isSingleton()) {
            sharedInstance = getSingleton(beanName, () -> {
               try {
                  return createBean(beanName, mbd, args);
               }
               catch (BeansException ex) {
                  destroySingleton(beanName);
                  throw ex;
               }
            });
            beanInstance = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
         }
         //原型模式对象的创建
         else if (mbd.isPrototype()) {
            // It's a prototype -> create a new instance.
            Object prototypeInstance = null;
            try {
               beforePrototypeCreation(beanName);
               prototypeInstance = createBean(beanName, mbd, args);
            }
            finally {
               afterPrototypeCreation(beanName);
            }
            beanInstance = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
         }

         else {
            //Spring2.0之后又引入了另外三种scope类型:request、session、global session类型
            //只能在只能在Web应用中使用,若只是后台进程的话则不会走该分支。
            String scopeName = mbd.getScope();
            if (!StringUtils.hasLength(scopeName)) {
               throw new IllegalStateException("No scope name defined for bean '" + beanName + "'");
            }
            Scope scope = this.scopes.get(scopeName);
            if (scope == null) {
               throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
            }
            try {
               Object scopedInstance = scope.get(beanName, () -> {
                  beforePrototypeCreation(beanName);
                  try {
                     return createBean(beanName, mbd, args);
                  }
                  finally {
                     afterPrototypeCreation(beanName);
                  }
               });
               beanInstance = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
            }
            catch (IllegalStateException ex) {
               throw new ScopeNotActiveException(beanName, scopeName, ex);
            }
         }
      }
      catch (BeansException ex) {
         beanCreation.tag("exception", ex.getClass().toString());
         beanCreation.tag("message", String.valueOf(ex.getMessage()));
         cleanupAfterBeanCreationFailure(beanName);
         throw ex;
      }
      finally {
         beanCreation.end();
      }
   }

   return adaptBeanInstance(name, beanInstance, requiredType);
}

doGetBean 方法是先看看该对象是否已经初始化,如果没有在创建并初始化,值得注意的是,其是先创建并初始化当前要创建的对象的依赖(还是调用doGetbean),最后再根据对象类型分开创建,但是核心是调用 父类 AbstractAutowireCapableBeanFactorycreateBean 方法。 createBean.jpg AbstractAutowireCapableBeanFactory.createBean.jpg createBeanInstance则很有意思,其是先判断是否由指定工厂创建,再有无注册的构造方法,最后才会通过反射获取该类的构造方法构造对象。 AbstractAutowireCapableBeanFactory.createBeanInstance.jpg AbstractAutowireCapableBeanFactory.InstantiateBean.jpg instantiate方法在 SimpleInstantiationStrategy类中。 SimpleInstantiationStrategy.instantiate.jpgBeanUtil.instantiateClass方法则是封装的的通过构造器获取对象。 BeanUtil.instantiateClass.jpg 由此,一个对象就被创建结束,而后虽然会对该对象进行一系列封装,但是归根结底,spring的bean创建还是上述这些过程。

bean的获取

其实通过 ClassPathXmlApplicationContext 对象获取指定类的对象的 getBean 方法其实就是第5步中的方法,对于非懒加载类对象就可以直接获取,而懒加载类的对象则在此刻构建。

最后再附上一张用到的UML图:

主要类uml.jpg

玻璃钢生产厂家海盐玻璃钢雕塑厂家福州玻璃钢广场雕塑北京商场美陈灯饰画加工厂河南玻璃钢浮雕大型城市雕塑上海玻璃钢雕塑灯定制永城商场美陈造景浦口商场美陈制作大型玻璃钢荷叶雕塑壁挂宜宾玻璃钢广场雕塑定制玻璃钢酒壶雕塑玻璃钢雕塑材质好云南卡通玻璃钢雕塑报价安顺玻璃钢雕塑定做电话解放玻璃钢雕塑价格黄冈玻璃钢考拉雕塑价格河南走廊商场美陈销售企业珠海公园玻璃钢雕塑江苏无锡品正企业玻璃钢花盆山东玻璃钢雕塑专业定制厂家人物雕像玻璃钢雕塑设计厂家山西玻璃钢浮雕雕塑批发晋城广场不锈钢玻璃钢景观雕塑台州大型玻璃钢雕塑批发灵山玻璃钢雕塑厂家山东做玻璃钢雕塑泰州玫红色玻璃钢花盆福建户外玻璃钢雕塑定制镇江玻璃钢园林雕塑价格南平玻璃钢人物雕塑价格如何黑龙江步行街玻璃钢雕塑图片香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声单亲妈妈陷入热恋 14岁儿子报警汪小菲曝离婚始末遭遇山火的松茸之乡雅江山火三名扑火人员牺牲系谣言何赛飞追着代拍打萧美琴窜访捷克 外交部回应卫健委通报少年有偿捐血浆16次猝死手机成瘾是影响睡眠质量重要因素高校汽车撞人致3死16伤 司机系学生315晚会后胖东来又人满为患了小米汽车超级工厂正式揭幕中国拥有亿元资产的家庭达13.3万户周杰伦一审败诉网易男孩8年未见母亲被告知被遗忘许家印被限制高消费饲养员用铁锨驱打大熊猫被辞退男子被猫抓伤后确诊“猫抓病”特朗普无法缴纳4.54亿美元罚金倪萍分享减重40斤方法联合利华开始重组张家界的山上“长”满了韩国人?张立群任西安交通大学校长杨倩无缘巴黎奥运“重生之我在北大当嫡校长”黑马情侣提车了专访95后高颜值猪保姆考生莫言也上北大硕士复试名单了网友洛杉矶偶遇贾玲专家建议不必谈骨泥色变沉迷短剧的人就像掉进了杀猪盘奥巴马现身唐宁街 黑色着装引猜测七年后宇文玥被薅头发捞上岸事业单位女子向同事水杯投不明物质凯特王妃现身!外出购物视频曝光河南驻马店通报西平中学跳楼事件王树国卸任西安交大校长 师生送别恒大被罚41.75亿到底怎么缴男子被流浪猫绊倒 投喂者赔24万房客欠租失踪 房东直发愁西双版纳热带植物园回应蜉蝣大爆发钱人豪晒法院裁定实锤抄袭外国人感慨凌晨的中国很安全胖东来员工每周单休无小长假白宫:哈马斯三号人物被杀测试车高速逃费 小米:已补缴老人退休金被冒领16年 金额超20万

玻璃钢生产厂家 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化