getbean方法找不到bean_Spring 源码学习 - 单例bean的实例化过程

v2-cb76ee0ca5f11799ecf19454e208ee49_1440w.jpg?source=172ae18b

本文作者:geek,一个聪明好学的同事

1. 简介

开发中我们常用@Commpont,@Service,@Resource等注解或者配置xml去声明一个类,使其成为spring容器中的bean,以下我将用从源码角度看以AnnotationConfigApplicationContext为例看spring如何把带有注解的类生成spring中bean。

2. 示例代码

public class TestContext {
 public static void main(String[] args) {
  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
  SingleBean singleBean = context.getBean(SingleBean.class);
  System.out.println("<=====>"+singleBean.getTestStr());
 }
}

@ComponentScan("com.geek")
public class AppConfig {
}

@Component
public class SingleBean {
 private String testStr = "testStr";

 public String getTestStr() {
  return testStr;
 }
}

注意:以上代码仅需要引入spring-context依赖即可。

3. 源码分析

​ 上面的demo在调用AnnotationConfigApplicationContext构造函数的时候,AppConfig类会被注册到AnnotatedBeanDefinitionReader,由这个reader把AppConfig解释为beanDefination,从而被spring获取到要实例化的类信息,以下为bean生产的源码及其注释。(源码基于springFramework 5.1.X)

3.1 创建入口

​ 单例bean的创建的入口为DefaultListableBeanFactory.java#preInstantiateSingletons,下面源码可见创建的bean条件为非抽象,非@LazyInit注解,Scope为singleTon(默认为singleTon)。

@Override
 public void preInstantiateSingletons() throws BeansException {
  if (logger.isTraceEnabled()) {
   logger.trace("Pre-instantiating singletons in " + this);
  }
  // Iterate over a copy to allow for init methods which in turn register new bean definitions.
  // While this may not be part of the regular factory bootstrap, it does otherwise work fine.
  //所有可能需要去实例化的class(lazy,scope)
  List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

  // Trigger initialization of all non-lazy singleton beans...
  for (String beanName : beanNames) {
   RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
   /**
    * 非抽象,非懒初始化,单例bean
    */
   if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    if (isFactoryBean(beanName)) {
     Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
     if (bean instanceof FactoryBean) {
      final FactoryBean<?> factory = (FactoryBean<?>) bean;
      boolean isEagerInit;
      if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
       isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
           ((SmartFactoryBean<?>) factory)::isEagerInit,
         getAccessControlContext());
      }
      else {
       isEagerInit = (factory instanceof SmartFactoryBean &&
         ((SmartFactoryBean<?>) factory).isEagerInit());
      }
      if (isEagerInit) {
       getBean(beanName);
      }
     }
    }
    //非工厂bean实例化
    else {
     getBean(beanName);
    }
   }
  }
  /**
   * 实例化完成后触发实现了SmartInitializingSingleton方法的bean
   * 的afterSingletonsInstantiated方法
    */
  // Trigger post-initialization callback for all applicable beans...
  for (String beanName : beanNames) {
   Object singletonInstance = getSingleton(beanName);
   if (singletonInstance instanceof SmartInitializingSingleton) {
    final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance;
    if (System.getSecurityManager() != null) {
     AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
      smartSingleton.afterSingletonsInstantiated();
      return null;
     }, getAccessControlContext());
    }
    else {
     smartSingleton.afterSingletonsInstantiated();
    }
   }
  }
 }

3.2 创建前doGetBean代码逻辑

getBean方法进来后便是直接调用doGetBean,doGetBean执行的源码解释如下:
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
   @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
  /**
   * 获取beanName
   * 1,去掉factortoryBean前缀&
   * 2,带有别名的bean转换为原来名字
   */
  final String beanName = transformedBeanName(name);
  Object bean;
  // Eagerly check singleton cache for manually registered singletons.
  /**
   * 从DefaultSingletonBeanRegistry的singletonObjects
   * (spring内部用来缓存单例bean的currentHashMap)检查是否存在该bean,不存在则创建
   * 涉及单例模式下的循环依赖解决
   */
  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 + "'");
    }
   }
   /**
    *获取给定bean实例的对象,如果是Factory Bean,
    * 则可以是bean实例本身或其创建的对象。
    */
   bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
  }
  else {
   // Fail if we're already creating this bean instance:
   // We're assembly within a circular reference.
   /**
    * 原型模式下的bean存在循环依赖则会抛异常
    */
   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 (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);
   }
   try {
    /**
     * 父容器中也找不到该bean,则需要重新实例化
     * 1,获取要实例化bean的beanDefinition,
     * 2,检查bean的实例化需要依赖的其他bean
     */
    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 dep : dependsOn) {
      /**
       * 若给定的依赖 bean 已经注册为依赖给定的bean
       */
      if (isDependent(beanName, dep)) {
       throw new BeanCreationException(mbd.getResourceDescription(), beanName,
         "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
      }
      registerDependentBean(dep, beanName);
      try {
       /**
        * 递归调用getBean,优先创建依赖的bean
        */
       getBean(dep);
      }
      catch (NoSuchBeanDefinitionException ex) {
       throw new BeanCreationException(mbd.getResourceDescription(), beanName,
         "'" + beanName + "' depends on missing bean '" + dep + "'", ex);
      }
     }
    }
    // Create bean instance.
    if (mbd.isSingleton()) {
     /**
      * 通过调用DefaultSingletonBeanRegistry的getSingleton,从而调用核心方法createBean创建
      */
     sharedInstance = getSingleton(beanName, () -> {
      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()) {
     // It's 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 name '" + scopeName + "'");
     }
     try {
      Object scopedInstance = scope.get(beanName, () -> {
       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);
     }
    }
   }
   catch (BeansException ex) {
    cleanupAfterBeanCreationFailure(beanName);
    throw ex;
   }
  }
  /**
   * 检查需要的bean类型是否符合
   */
  // Check if required type matches the type of the actual bean instance.
  if (requiredType != null && !requiredType.isInstance(bean)) {
   try {
    T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
    if (convertedBean == null) {
     throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
    }
    return convertedBean;
   }
   catch (TypeMismatchException ex) {
    if (logger.isTraceEnabled()) {
     logger.trace("Failed to convert bean '" + name + "' to required type '" +
       ClassUtils.getQualifiedName(requiredType) + "'", ex);
    }
    throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
   }
  }
  return (T) bean;
 }

doGetBean的操作流程如下:

1,执行transformedBeanName方法转换beanName

​ 传递的参数可能是bean的alias或者为FactoryBean,transformedBeanName执行的操作:(1)若传进来的FactoryBean(FactoryBean以&作为前缀标记),去掉&修饰符。(2)经过(1)的处理后,有alias的bean则从aliasMap中获取bean的原始beanName。

2,从容器的缓存中获取bean

​ getSingleton先从spring三级缓存中的第一级singletonObjects(Map结构)中获取,若不存在,则检查该bean是否正在创建isSingletonCurrentlyInCreation(beanName)) ,正在创建的bean会从二级缓存earlySingletonObjects(Map结构)获取。获取到缓存的bean后会调用AbstractBeanFactory#getObjectForBeanInstance转换bean的实例本身返回。因为从缓存中拿到的可能是factoryBean,所以getObjectForBeanInstance需要把是通过从缓存factoryBeanObjectCache获取或通过factory.getObject()获得相应的bean返回。

3,bean实例化前检查

​ (1)先检查是否原型模式下的bean是否存在循环依赖,是则会抛异常。

​ (2)检查父类工厂(parentBeanFactory)是否存在,存在则从parentBeanFactory中递归调用doGetBean。

​ (3)获取改bean的beanDefinition,检查该bean实例化过程中是否涉及依赖了其他的bean,若是则递归调用getBean,优先创建依赖的bean。(涉及单例下的循环以来解决,下篇文章详细介绍)。

​ (4)对创建bean代码加synchronized和执行beforeSingletonCreation(beanName)前置处理。

3.3 创建前createBean逻辑

​ 经过前面的doGetBean的一轮检查与准备后,便在AbstractAutowireCapableBeanFactory#createBean中开始bean的创建。

/**
  * Central method of this class: creates a bean instance,
  * populates the bean instance, applies post-processors, etc.
  * 解析指定 BeanDefinition 的 class
  * 处理 override 属性
  * 实例化的前置处理
  * 创建 bean
  * @see #doCreateBean
  */
 @Override
 protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
   throws BeanCreationException {

  if (logger.isTraceEnabled()) {
   logger.trace("Creating instance of bean '" + beanName + "'");
  }
  RootBeanDefinition mbdToUse = mbd;

  // Make sure bean class is actually resolved at this point, and
  // clone the bean definition in case of a dynamically resolved Class
  // which cannot be stored in the shared merged bean definition.
  /**
   * 解释bean的class,看beanDefinition是否有class,否则load class
   */
  Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
  if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
   mbdToUse = new RootBeanDefinition(mbd);
   mbdToUse.setBeanClass(resolvedClass);
  }
  /**
   * 对bean不存在lookup-method 和 replace-method
   * 标记其方法的overloaded为false
   */
  // Prepare method overrides.
  try {
   mbdToUse.prepareMethodOverrides();
  }
  catch (BeanDefinitionValidationException ex) {
   throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
     beanName, "Validation of method overrides failed", ex);
  }

  try {
   /**
    * 调用实现实现BeanPostProcessor的bean后置处理生成代理对象,
    * 有代理对象则直接返回代理对象
    */
   // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
   Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
   if (bean != null) {
    return bean;
   }
  }
  catch (Throwable ex) {
   throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
     "BeanPostProcessor before instantiation of bean failed", ex);
  }

  try {
   /**
    * 无需代理的bean实例化
    */
   Object beanInstance = doCreateBean(beanName, mbdToUse, args);
   if (logger.isTraceEnabled()) {
    logger.trace("Finished creating instance of bean '" + beanName + "'");
   }
   return beanInstance;
  }
  catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) {
   // A previously detected exception with proper bean creation context already,
   // or illegal singleton state to be communicated up to DefaultSingletonBeanRegistry.
   throw ex;
  }
  catch (Throwable ex) {
   throw new BeanCreationException(
     mbdToUse.getResourceDescription(), beanName, "Unexpected exception during bean creation", ex);
  }
 }

createBean的操作流程如下:

1,resolveBeanClass

​ 解释beanDefinition的class,并且保存在beanDefinition中。

2,prepareMethodOverrides

​ 处理bean中的lookup-method (在单例bean用 @Lookup注解标记的方法,注解的方法返回的对象是原型)和 replace-method( 标记的方法,标记bean中A的方法被实现被另外一个实现MethodReplacer接口的B方法替代)。

3,resolveBeforeInstantiation

​ 调用实现实现BeanPostProcessor的bean后置处理生成代理对象,有代理对象则直接返回代理对象。(spring AOP则是基于此处实现)

3.4 bean的真正实例化createBeanInstance

​ 在AbstractAutowireCapableBeanFactory#createBeanInstance中,真正创建bean,源码及注释如下:

protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
  // Make sure bean class is actually resolved at this point.
  Class<?> beanClass = resolveBeanClass(mbd, beanName);
  if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
   throw new BeanCreationException(mbd.getResourceDescription(), beanName,
     "Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
  }
  /**
   * 通过提供supplier回调方法创建
   */
  Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
  if (instanceSupplier != null) {
   return obtainFromSupplier(instanceSupplier, beanName);
  }
  /**
   * 通过工厂方法创建 bean 实例,可以是静态工厂方法或者实例工厂
   */
  if (mbd.getFactoryMethodName() != null) {
   return instantiateUsingFactoryMethod(beanName, mbd, args);
  }
  // Shortcut when re-creating the same bean...
  boolean resolved = false;
  boolean autowireNecessary = false;
  if (args == null) {
   synchronized (mbd.constructorArgumentLock) {
    /**
     * 查找已经bean已经缓存解析的构造函数或者工厂方法
     */
    if (mbd.resolvedConstructorOrFactoryMethod != null) {
     resolved = true;
     autowireNecessary = mbd.constructorArgumentsResolved;
    }
   }
  }
  /**
   * 已经有缓存的构造函数或者工厂方法,直接实例化
   */
  if (resolved) {
   if (autowireNecessary) {
    return autowireConstructor(beanName, mbd, null, null);
   }
   else {
    return instantiateBean(beanName, mbd);
   }
  }
  /**
   * 通过实现BeanPostProcessor的代理类autowired的构造函数实例化
   */
  // Candidate constructors for autowiring?
  Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
  if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
    mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
   return autowireConstructor(beanName, mbd, ctors, args);
  }
  /**
   * 通过本身带有autowired的构造函数实例化,通过调用反射newInstance实现
   */
  // Preferred constructors for default construction?
  ctors = mbd.getPreferredConstructors();
  if (ctors != null) {
   return autowireConstructor(beanName, mbd, ctors, null);
  }
  /**
   * 无参构造函数实例化,通过调用反射newInstance实现
   */
  // No special handling: simply use no-arg constructor.
  return instantiateBean(beanName, mbd);
 }

由上述源码可以看出,实例化bean操作流程如下:

1,如果存在 Supplier 回调,则通过提供supplier回调方法创建,如以下方式定义的bean:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = Spring5Application.class)
public class BeanRegistrationTest {
    @Autowired
    private GenericWebApplicationContext context;
    
    context.registerBean(A.class, () -> new A());
}

2,如果存在工厂方法,则通过工厂方法创建 bean 实例,可以是静态工厂方法或者实例工厂,如以下方式定义的bean:

public class AFactory implements FactoryBean<A> {
 @Override
 public A getObject() throws Exception {
  return new A();
 }
 @Override
 public Class<?> getObjectType() {
  return A.class;
 }
}
//或:
@Configuration
public class BeanConfigration {
 @Bean
 public A a(){
  return new A();
 }

}

3,已经有缓存的构造函数或者工厂方法,直接实例化。

4,以上三点都不存在,则使用带参构造函数与无参构造函数实例化。如以下方式定义的bean:

@Commponet
public class A{}

4.总结

spring单例bean的实例化流程大概就是这样,很多细节地方,包括循环依赖处理,bean属性填充等细节点下一章介绍。

参考:

  • 《Spring 源码深度解析》- 郝佳
  • 《死磕spring源码》-chenssy

欢迎关注我的公众号:好奇心森林

v2-6074671613d134d334eb0818e47d084c_b.jpg
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MyBatis 目录(?)[-] mybatis实战教程mybatis in action之一开发环境搭建 mybatis实战教程mybatis in action之二以接口的方式编程 mybatis实战教程mybatis in action之三实现数据的增删改查 mybatis实战教程mybatis in action之四实现关联数据的查询 mybatis实战教程mybatis in action之五与spring3集成附源码 mybatis实战教程mybatis in action之六与Spring MVC 的集成 mybatis实战教程mybatis in action之七实现mybatis分页源码下载 mybatis实战教程mybatis in action之八mybatis 动态sql语句 mybatis实战教程mybatis in action之九mybatis 代码生成工具的使用 mybatis SqlSessionDaoSupport的使用附代码下载 转自:http://www.yihaomen.com/article/java/302.htm (读者注:其实这个应该叫做很基础的入门一下下,如果你看过Hibernate了那这个就非常的简单) (再加一条,其实大家可以看官方的教程更好些:http://mybatis.github.io/mybatis-3/,而且如果英文不是很好的那就看中文的:http://mybatis.github.io/mybatis-3/zh/sqlmap-xml.html) 写在这个系列前面的话: 以前曾经用过ibatis,这是mybatis的前身,当时在做项目时,感觉很不错,比hibernate灵活。性能也比hibernate好。而且也比较轻量级,因为当时在项目中,没来的及做很很多笔记。后来项目结束了,我也没写总结文档。已经过去好久了。但最近突然又对这个ORM 工具感兴趣。因为接下来自己的项目中很有可能采用这个ORM工具。所以在此重新温习了一下 mybatis, 因此就有了这个系列的 mybatis 教程. 什么是mybatis MyBatis是支持普通SQL查询,存储过程和高级映射的优秀持久层框架。MyBatis消除了几乎所有的JDBC代码和参数的手工设置以及结果集的检索。MyBatis使用简单的XML或注解用于配置和原始映射,将接口和Java的POJOs(Plan Old Java Objects,普通的Java对象)映射成数据库中的记录. orm工具的基本思想 无论是用过的hibernate,mybatis,你都可以法相他们有一个共同点: 1. 从配置文件(通常是XML配置文件中)得到 sessionfactory. 2. 由sessionfactory 产生 session 3. 在session 中完成对数据的增删改查和事务提交等. 4. 在用完之后关闭session 。 5. 在java 对象和 数据库之间有做mapping 的配置文件,也通常是xml 文件。 mybatis实战教程(mybatis in action)之一:开发环境搭建 mybatis 的开发环境搭建,选择: eclipse j2ee 版本,mysql 5.1 ,jdk 1.7,mybatis3.2.0.jar包。这些软件工具均可以到各自的官方网站上下载。 首先建立一个名字为 MyBaits 的 dynamic web project 1. 现阶段,你可以直接建立java 工程,但一般都是开发web项目,这个系列教程最后也是web的,所以一开始就建立web工程。 2. 将 mybatis-3.2.0-SNAPSHOT.jar,mysql-connector-java-5.1.22-bin.jar 拷贝到 web工程的lib目录. 3. 创建mysql 测试数据库和用户表,注意,这里采用的是 utf-8 编码 创建用户表,并插入一条测试数据 程序代码 程序代码 Create TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `userName` varchar(50) DEFAULT NULL, `userAge` int(11) DEFAULT NULL, `userAddress` varchar(200) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; Insert INTO `user` VALUES ('1', 'summer', '100', 'shanghai,pudong'

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值