欢迎来到飞鸟慕鱼博客,开始您的技术之旅!
当前位置: 首页知识笔记正文

spring bean 创建,spring创建bean的几种方式

终极管理员 知识笔记 136阅读
Spring读书笔记——bean创建上

目录

Spring读书笔记——bean创建上

从getBean说起

AbstractBeanFactory

getBean

 

 

 

通过《Spring读书笔记——bean加载》和《Spring读书笔记——bean解析》我们明白了两件事。

Spring如何加载消化一个xml配置文件Spring如何将xml文件的各种标签转换为BeanDefinition并注册到Spring容器下 现在我们理所当然的还差bean是如何被创建出来这一环节了。 从getBean说起

我们经常使用下面的方式实现先加载xml文件然后获取相应的bean实例

BeanFactory beanFactory  new ClassPathXmlApplicationContext(application-context.xml);TestBean testBean  beanFactory.getBean(testBean);

显然我们是通过getBean方法获取到的Bean实例该方法是接口BeanFactory中定义的一个方法。具体实现在另外一个抽象类中就是我们一会要说到的AbstractBeanFactory。

AbstractBeanFactory

该抽象类集成了FactoryBeanRegistrySupport并实现了ConfigurableBeanFactory接口该接口间接实现了接口BeanFactory

通过上面的区块注释以及提供的方法getBean我们一眼就看出其余BeanFactory的密切关系。

getBean

该方法非常简单只是调用了一个函数真正的实现都在doGetBean方法中了。代码实现有点长但是我们还是得静下心来看看他到底做了哪些工作。

protected <T> T doGetBean(      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)      throws BeansException {   final String beanName  transformedBeanName(name);   Object bean;   // Eagerly check singleton cache for manually registered singletons.   Object sharedInstance  getSingleton(beanName);   if (sharedInstance ! null && args  null) {      if (logger.isDebugEnabled()) {         if (isSingletonCurrentlyInCreation(beanName)) {            logger.debug(Returning eagerly cached instance of singleton bean   beanName                    that is not fully initialized yet - a consequence of a circular reference);         }         else {            logger.debug(Returning cached instance of singleton bean   beanName  );         }      }      bean  getObjectForBeanInstance(sharedInstance, name, beanName, null);   }   else {      // Fail if were already creating this bean instance:      // Were assumably within a circular reference.      if (isPrototypeCurrentlyInCreation(beanName)) {         throw new BeanCurrentlyInCreationException(beanName);      }      // Check if bean definition exists in this factory.      BeanFactory parentBeanFactory  getParentBeanFactory();      if (parentBeanFactory ! null && !containsBeanDefinition(beanName)) {         // Not found -> check parent.         String nameToLookup  originalBeanName(name);         if (args ! null) {            // Delegation to parent with explicit args.            return (T) parentBeanFactory.getBean(nameToLookup, args);         }         else {            // No args -> delegate to standard getBean method.            return parentBeanFactory.getBean(nameToLookup, requiredType);         }      }      if (!typeCheckOnly) {         markBeanAsCreated(beanName);      }      final RootBeanDefinition mbd  getMergedLocalBeanDefinition(beanName);      checkMergedBeanDefinition(mbd, beanName, args);      // Guarantee initialization of beans that the current bean depends on.      String[] dependsOn  mbd.getDependsOn();      if (dependsOn ! null) {         for (String dependsOnBean : dependsOn) {            getBean(dependsOnBean);            registerDependentBean(dependsOnBean, beanName);         }      }      // Create bean instance.      if (mbd.isSingleton()) {         sharedInstance  getSingleton(beanName, new ObjectFactory<Object>() {            public Object getObject() throws BeansException {               try {                  return createBean(beanName, mbd, args);               }               catch (BeansException ex) {                  // Explicitly remove instance from singleton cache: It might have been put there                  // eagerly by the creation process, to allow for circular reference resolution.                  // Also remove any beans that received a temporary reference to the bean.                  destroySingleton(beanName);                  throw ex;               }            }         });         bean  getObjectForBeanInstance(sharedInstance, name, beanName, mbd);      }      else if (mbd.isPrototype()) {         // Its a prototype -> create a new instance.         Object prototypeInstance  null;         try {            beforePrototypeCreation(beanName);            prototypeInstance  createBean(beanName, mbd, args);         }         finally {            afterPrototypeCreation(beanName);         }         bean  getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);      }      else {         String scopeName  mbd.getScope();         final 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<Object>() {               public Object getObject() throws BeansException {                  beforePrototypeCreation(beanName);                  try {                     return createBean(beanName, mbd, args);                  }                  finally {                     afterPrototypeCreation(beanName);                  }               }            });            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);         }      }   }

归一化beanName 如果看了前面两篇文章这里你就知道beanName就是注册到Spring容器中的bean的名称具体来说就是放入BeanDefinitionMap中的一个键值对的key。 那么这里有什么好转换处理的呢。 我们看下transformedBeanName的具体实现

public static String transformedBeanName(String name) {   Assert.notNull(name, name must not be null);   String beanName  name;   while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {      beanName  beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());   }   return beanName;}

没错做了一个断言处理通过对于一种FactoryBean形式的bean做了处理。从FactoryBean这个命名就知道他是一种bean不是病*有关FactoryBean的介绍以及使用可以参看博文

尝试从缓存中加载单例bean Object sharedInstance getSingleton(beanName); 该方法就是实现从缓存中获取单例bean。 对于单例应该都不陌生单例bean单例模式等等说的都是一个意思——一个东西只有一份。

Spring默认创建的bean就是单例bean也就是在容器中只会存在一份这样的bean这只是一次尝试加载如果加载不到通过后面的代码我们可以发现其会从singletonFactories中加载加载单例bean可能会遇到一个头疼的问题——循环依赖就是加载A时A依赖了B那么需要加载B发现B依赖了C这时候去加载C发现C依赖了A这样就形成了一个闭环也就是循环依赖A->B->C-A。后面会说Spring是如何解决这个问题的有关Spring中不同类型的bean的循环依赖问题和解决方法可以参看*一不留神的个人页面 - OSCHINA - 中文开源技术交流社区

bean实例化 假设我们从缓存中得到了bean但是这还不是bean的最终状态可以认为这只是一个引用要获得真正的bean实例我们还需要看下getObjectForBeanInstance方法。

原型模式的循环依赖检查 这里引用下上面提供有关循环依赖的链接中比较重要的内容

spring循环依赖的情况 1.构造器注入属性依赖(A B两个对象都使用构造方法注入依赖的属性) 无论是单例还是原型对象只要是通过构造器注入的属性依赖都会报错循环依赖错误 org.springframework.beans.factory.BeanCurrentlyInCreationException: 原因:试想构造器是创建对象的入口方法构造的时候都循环依赖了我这个对象压根就创建不了啊。那肯定是无法解决的大罗神仙也无能为力。 2.setter方法注入属性依赖 这个spring完美解决了支持这种循环依赖 原理创建对象A的时候先通过无参构造方法创建一个实例此时属性都是空的,但是对象引用已经创建出来然后把A的引用提前暴露出来。然后setter B属性的时候创建B对象此时同样通过无参构造方法构造然后将对象引用暴露出来。接着B执行setter方法去池中找A能找到A因为此时A已经暴露出来有指向改对象的引用了这么依赖B就构造完成也初始化完成然后A接着初始化完成。---循环依赖就这么解决了 3.原型对象的属性依赖(当然指的是通过setter方法注入依赖) 这个spring也无能为力因为是原型对象A创建的时候不会提前暴露出来所以每次都是要创建创建的时候发现有相同的对象正在创建同样报错循环依赖错误同第一种情况类似。

我们知道对于单例默认的循环依赖我们是可以解决的但是对于原型类型的循环依赖我们没有办法解决所以这里通过对于原型bean的检查适时抛出异常。

if (isPrototypeCurrentlyInCreation(beanName)) {   throw new BeanCurrentlyInCreationException(beanName);}

检测parentBeanFactory 顺着代码的逻辑很自然的来到了从parentBeanFactory中加载Bean的模块。当在缓存中没有加载到Bean的时候我们就会从parentBeanFactory中试试。

转换为RootBeanDefinition 前两篇我们介绍了从xml标签到BeanDefinition的转变这里我们需要将GenericBeanDefinition转为RootBeanDefinition这是处于后面的处理是一致对于RootBeanDefinition处理考量的。

解决bean依赖的问题

// Guarantee initialization of beans that the current bean depends on.String[] dependsOn  mbd.getDependsOn();if (dependsOn ! null) {   for (String dependsOnBean : dependsOn) {      getBean(dependsOnBean);      registerDependentBean(dependsOnBean, beanName);   }}

从注释就可以知道这块主要是解决在初始化一个bean的时候这个bean依赖了其他的bean所以需要在创建之前先初始化依赖的bean。

对于scope的处理以及对于类型转换的处理 后面剩下的代码主要是对于Spring中不同scope的处理比如singleton、prototype、request、session等等。

上面就是getBean这一抽象层次上关于如何创建bean的详细过程下面对于其中一些部分做详细解释。

等等写着写着发现后面的点还是有点多一篇恐怕撑不住了还是分上下集吧~~~

 

标签:
声明:无特别说明,转载请标明本文来源!