向spring大佬低头--大量源码流出解析

来源:互联网 发布:域名查询哪家最好 编辑:程序博客网 时间:2024/04/28 21:51

       spring框架做了几年的开发,只停留在会用的阶段上,然而spring的设计思想和原理确实一个巨大的宝库.大部分人仅仅知道怎么去配,或着加上什么属性就能达到什么效果,这些东西都可以通过查文档,查google来解决.关键是在怎么理解它,把它的思想变为你的东西。博主这几天没有学习(装逼),感觉心里甚是空虚,索性研究了下一直很好奇的spring大佬,毕竟写代码天天都在用,文章有什么说的不对的地方,你来打我呀(评论区来信砍).

        前方高能,非战斗人员迅速投入战斗.本文将从实际出发,对spring实施剥洋葱,只要你愿意一层一层剥开它的心,你就能发现spring的全心全意(不要唱出来):

        1.spring ioc容器

        2.ApplicationContext与BeanFactory探究.

        3.bean的加载

        4.FactoryBean

        5.spring Aop实现原理及探究

      文章篇幅有限,只对大概内容做阐述,有兴趣的可以看看《spring源码深度解析》,本文也是基于该书总结出来的.

1.spring ioc容器

     很多人一提ioc,遍张口就来:控制反转.究竟哪些方面被反转了呢?答案是依赖对象的获得被反转了.很多时候,我们通过多个对象之间的协作来完成一个功能,如果获取所依赖对象靠自身来实现,这将导致代码的耦合度高和难以测试.当然,控制反转还有一个好听的名字:依赖注入.

    spring ioc通过引入xml配置,由ioc容器来管理对象的生命周期,依赖关系等.

             

它的加载过程是什么样的呢?

         

         BeanDefinition是一个接口,用于属性承载,比如<bean>元素标签拥有class、scope、lazy-init等配置。Bean的定义方式有千千万万种,无论是何种标签,无论是何种资源定义,无论是何种容器,只要按照spring的规范编写xml配置文件,最终的bean定义内部表示都将转换为内部的唯一结构:BeanDefinition。当BeanDefinition注册完毕以后,spring的BeanFactory就可以随时根据需要进行实例化了。

2.ApplicationContext与BeanFactory探究.

     对于XmlBeanFactory来说,实例化是默认延迟加载的,也就是说只有getBean时才会实例化,而ApplicationContext,实例化会在容器启动后过AbstractApplicationContext中reflash方法自动进行。而reflash方法是spring初始ioc容器一个非常重要的方法,不管你是ApplicationContext哪个实现类,最终都会进入这个方法。

    @Override      public void refresh() throws BeansException, IllegalStateException {          synchronized (this.startupShutdownMonitor) {              // 设置和校验系统变量和环境变量的值            prepareRefresh();              //主要是创建beanFactory,同时加载配置文件.xml中的beanDefinition              //通过String[] configLocations = getConfigLocations()获取资源路径,然后加载beanDefinition              ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();                 //给beanFactory注册一些标准组建,如ClassLoader,StandardEnvironment,BeanProcess              prepareBeanFactory(beanFactory);                try {                    //提供给子类实现一些postProcess的注册,如AbstractRefreshableWebApplicationContext注册一些Servlet相关的                  //postProcess,真对web进行生命周期管理的Scope,通过registerResolvableDependency()方法注册指定ServletRequest,HttpSession,WebRequest对象的工厂方法                  postProcessBeanFactory(beanFactory);                     //调用所有BeanFactoryProcessor的postProcessBeanFactory()方法                  invokeBeanFactoryPostProcessors(beanFactory);                    //注册BeanPostProcessor,BeanPostProcessor作用是用于拦截Bean的创建                  registerBeanPostProcessors(beanFactory);                      //初始化消息Bean                  initMessageSource();                    //初始化上下文的事件多播组建,ApplicationEvent触发时由multicaster通知给ApplicationListener                  initApplicationEventMulticaster();                  //ApplicationContext初始化一些特殊的bean                  onRefresh();                     //注册事件监听器,事件监听Bean统一注册到multicaster里头,ApplicationEvent事件触发后会由multicaster广播                  registerListeners();                    //非延迟加载的单例Bean实例化                  finishBeanFactoryInitialization(beanFactory);                    finishRefresh();              }                catch (BeansException ex) {                  logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);                   destroyBeans();                  cancelRefresh(ex);                    throw ex;              }          }      }  

        代码逻辑清晰的值得mark一下。这个方法的作用是创建加载Spring容器配置(包括.xml配置,property文件和数据库模式等),IOC中最核心的接口是Beanfactory提供IOC的高级服务,而ApplicationContext是建立在BeanFactory基础之上提供抽象的面向应用的服务。那么,究竟BeanFactory里到底是什么样的呢?

package org.springframework.beans.factory;public interface BeanFactory {    /**     * 用来引用一个实例,或把它和工厂产生的Bean区分开,就是说,如果一个FactoryBean的名字为a,那么,&a会得到那个Factory     */    String FACTORY_BEAN_PREFIX = "&";    /*     * 四个不同形式的getBean方法,获取实例     */    Object getBean(String name) throws BeansException;    <T> T getBean(String name, Class<T> requiredType) throws BeansException;    <T> T getBean(Class<T> requiredType) throws BeansException;    Object getBean(String name, Object... args) throws BeansException;    boolean containsBean(String name); // 是否存在    boolean isSingleton(String name) throws NoSuchBeanDefinitionException;// 是否为单实例    boolean isPrototype(String name) throws NoSuchBeanDefinitionException;// 是否为原型(多实例)    boolean isTypeMatch(String name, Class<?> targetType)            throws NoSuchBeanDefinitionException;// 名称、类型是否匹配    Class<?> getType(String name) throws NoSuchBeanDefinitionException; // 获取类型    String[] getAliases(String name);// 根据实例的名字获取实例的别名}

        我们看出在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是怎样定义怎样加载的 - 就像我们只关心从这个工厂里我们得到到什么产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心这些。

         如果要关心工厂是怎样产生对象的,应用程序需要使用具体的IOC容器实现- 当然你可以自己根据这个BeanFactory来实现自己的IOC容器,但这个没有必要,因为Spring已经为我们准备好了一系列工厂来让我们使用。比如XmlBeanFactory就是针对最基础的BeanFactory的IOC容器的实现,ApplicationContext接口也继承了BeanFactory接口。

3.bean的加载。

        当我们getBean时,肯定是实现类起了作用,而AbstractBeanFactory实现了BeanFactory接口的方法

                             

        AbstractBeanFactory有四个重载的getBean方法,不管哪一个都会去调用doGetBean方法

                

                

那么doGetBean里干了什么事情呢?

protected <T> T doGetBean(final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)throws BeansException { //bean name处理,去除FactoryBean前缀等       final String beanName = transformedBeanName(name);       Object bean = null;    //先从singleton缓存中查看是否已经实例化过该Bean,根据是否有缓存分为两个分支分别处理      Object sharedInstance = getSingleton(beanName);      if (sharedInstance != null && args == null) {  // 分支一,若缓存中获取到了并且该BeanDefinition信息表明该bean是singleton的,直接将获取到的缓存Bean  //(有可能是半成品)交给getObjectForBeanInstance处理   /*.........省略logger部分代码............*/  //调用getObjectForBeanInstance处理       bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);      }else {  // 分之二:没有缓存,则需要从头实例化该bean              // We're assumably within a circular reference.        if (isPrototypeCurrentlyInCreation(beanName)) {              throw new BeanCurrentlyInCreationException(beanName);}    // 检查BeanDefinition是否在当前工厂或父工厂              BeanFactory parentBeanFactory = getParentBeanFactory();              if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {                  // Not found -> check parent.                  String nameToLookup = originalBeanName(name);                  if (args != null) {  // 父工厂getBean                      return parentBeanFactory.getBean(nameToLookup, args);                  }                  else {                      // No args -> delegate to standard getBean method.                      return parentBeanFactory.getBean(nameToLookup, requiredType);                  }              }  //将bean加入“正在创建”的集合,完成后会remove,对应afterSingletonCreation/afterPrototypeCreation方法              if (!typeCheckOnly) {                  markBeanAsCreated(beanName);              }                final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);              checkMergedBeanDefinition(mbd, beanName, args);    // 解决依赖关系,将依赖的bean提前实例化              String[] dependsOn = mbd.getDependsOn();              if (dependsOn != null) {                  for (int i = 0; i < dependsOn.length; i++) {                      String dependsOnBean = dependsOn[i];                      getBean(dependsOnBean);                      registerDependentBean(dependsOnBean, beanName);                  }              }    // 这里又需要根据bean的类型分为三种情况:singleton、prototype、request/session              if (mbd.isSingleton()) {                             //通过自定义ObjectFactory实例化Bean,此结果可能是半成品(是FactoryBean等)                  sharedInstance = getSingleton(beanName, new ObjectFactory() {                      public Object getObject() throws BeansException {                          try {                            //真正实例化装配的逻辑在createBean方法中                              return createBean(beanName, mbd, args);                          }                          catch (BeansException ex) {                               destroySingleton(beanName);                              throw ex;                          }                      }                  });                          //上一步半成品的Bean交给getObjectForBeanInstance方法处理                  bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);              }                else if (mbd.isPrototype()) {                  Object prototypeInstance = null;                  try {                      beforePrototypeCreation(beanName);                       //真正实例化装配的逻辑在createBean方法中                      prototypeInstance = createBean(beanName, mbd, args);                  }                  finally {                      afterPrototypeCreation(beanName);                  }                      //上一步半成品的Bean交给getObjectForBeanInstance方法处理                 bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);              }                else {                              //request、session 的bean                  String scopeName = mbd.getScope();                  final Scope scope = (Scope) this.scopes.get(scopeName);                  if (scope == null) {          throw new IllegalStateException("No Scope registered for scope '" + scopeName + "'");                  }                  try {                      Object scopedInstance = scope.get(beanName, new ObjectFactory() {                          public Object getObject() throws BeansException {                              beforePrototypeCreation(beanName);                              try {                           //真正实例化装配的逻辑在createBean方法中                                  return createBean(beanName, mbd, args);                              }                              finally {                                  afterPrototypeCreation(beanName);                              }                          }                      });                         //上一步半成品的Bean交给getObjectForBeanInstance方法处理                  bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);                  }                  catch (IllegalStateException ex) {                      throw new BeanCreationException(beanName,                  "Scope '" + scopeName + "' is not active for the current thread; " +      "consider defining a scoped proxy for this bean if you intend to refer to it from a singleton",                              ex);                  }              }          }             if (requiredType != null && bean != null &&                                !requiredType.isAssignableFrom(bean.getClass())) {              throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());          }          return bean;      }  

    bean的加载经历了一个复杂的过程,其主要做了以下几件事(此段摘抄自《spring源码深度解析》):

       1.转换对应的beanName。如果name=“&aa”的,会去除&符号。或者<bean>标签带有alias(别名的意思),则取alias所表示最终的beanName。

       2.尝试从缓存中加载单例bean。如果加载不成功,会再次尝试从singletonFactories中加载。

       3.bean的实例化。假如我们需要对工厂bean进行处理,那么这里得到的其实是工厂bean 的初始状态。真正干活的则是getObjectForBeanInstance定义factory-method方法返回的bean。

       4.原型模式的依赖检查。如果A类有B的属性,B中有A的属性,则会产生循环依赖。spring如何解决循环依赖问题

        5.将存储的Xml配置文件的GernericBeanDefinition转换为RootBeanDefinition。前文提到的用于承载属性的BeanDefinition有三个实现,GernericBeanDefinition,RootBeanDefinition和ChildBeanDefinition,如果父类bean不为空的话,这里会把所有的属性一并合并父类属性,因为后续所有的Bean都是针对RootBeanDefinition的。

         6.寻找依赖。在初始化一个bean的时候,会首先初始化这个bean所对应的依赖。

         7.根据不同的scope创建bean。scope属性默认是singleton,还有prototype、request等。

         8.类型转换。如果bean是个String,而requiredType传入了Integer.然后返回bean,加载结束.

其中,最重要的步骤是(7),spring的常用特性都在这里实现.

4.FactoryBean

        首先要分辨BeanFactory 与 FactoryBean的区别, 两个名字很像,所以容易搞混,使用实例:spring中BeanFactory与FactoryBean的区别。

       1.BeanFactory前文讲过是个Factory,也就是 IOC 容器或对象工厂,所有的 Bean 都是由 BeanFactory( 也就是 IOC 容器 ) 来进行管理。ApplicationContext是BeanFactory的扩展,功能得到了进一步增强,比如更易与Spring AOP集成、消息资源处理(国际化处理)、事件传递及各种不同应用层的context实现。

          2.FactoryBean:以Bean结尾,表示它是一个Bean,是一个能生产或者修饰生成对象的工厂Bean,可以在IOC容器中被管理。

public interface FactoryBean<T> {    //返回由FactoryBean创建的Bean实例,如果isSingleton返回true,则该实例会放到spring容器中单例缓存池中.T getObject() throws Exception;   //返回FactoryBean创建的bean类型.Class<?> getObjectType();    //返回由FactoryBean创建的bean实例的作用域是singleton还是prototypeboolean isSingleton();}

写到这里,博主总结一下阅读spring源码的心得:

     1.学习spring思想和编码规范。spring的很多函数代码量大,逻辑复杂,而spring的编码风格就是将复杂的逻辑分解,分成N个小函数的嵌套,每一层都是对下一层的总结和概要。博主在工作中最佩服的一个大神说过:学习spring源码思想为我所用,哪怕是一天学习一个变量名.他在工作中设计很多小组件的时候都是基于spring思想和规范,他说,不要迷茫学什么技术,其实每天只要进步一点点就好,突破的是自己,而不是某个领域.用10年其实才敢说入门一门技术.

    2.跟了spring代码的函数,你会或多或少发现一些规律:一个真正干活的函数其实是以do开头的,如doGetObjectFromFactoryBean,而给我们错觉的函数,如getObjectFromFactoryBean和createBean等等方法,其实只是从全局角度做一些统筹工作.

      3.放弃阅读源码是一个不明智的选择,因为你失去了跟大师学习的机会.当你硬着头皮读完一个框架的源码,则其他框架都是想通的.

      4.博主的下一篇文章,敬请期待:spring Aop实现原理及探究   因为篇幅有限,而博主的已经搞了一天代码,手已经快练成麒麟臂,Aop又是一个重要且内容比较多的部分,所以打算单独拿出来搞事情。



原创粉丝点击