getBean方法源码

简介: getBean方法源码

一、 三个API

// 根据name获取bean 
@Override
public Object getBean(String name) throws BeansException {
  return doGetBean(name, null, null, false);
}
// 根据name获取bean,如果获取到的bean和指定类型不匹配,则抛出异常
@Override
public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
  return doGetBean(name, requiredType, null, false);
}
// 根据name获取bean,如果是一个有参构造器生成的bean,则将参数对象注入到构造器中
@Override
public Object getBean(String name, Object... args) throws BeansException {
  return doGetBean(name, null, args, false);
}

二、源码

2.1. 获取name获取bean的真名,一个bean可以定义多个别名,这里会从map中递归获取到真名。  

2.2  根据beanName去单例池获取bean,如果存在直接返回。

  3. 如果单例池不存在bean,判断当前beanFactory是否有父的beanFactory,并且当前beanFactory能不能找到bean,如果当前beanFactory找到bean直接从当前beanFactory寻找后返回bean。否则则去父的bean工厂取。

  4. 真正的获取bean逻辑

  4.1 根据beanName得到合并后的beanDefinition

  4.2 判断得到的beanDefinition是否是抽象bean,是则抛异常

  5. 判断beanDefinition有没有@dependentOn注解,如果有,则判断被依赖的对象是否又依赖了当前beanDefinition,即出现了自定义的循环依赖,如果是则抛异常。

  6. 如果有@dependentOn但没有循环依赖,则将依赖的对象加入dependentOnMap中,dep为key你,beanName为value。再接着先完成依赖对象的getbean();

  7. 根据合并后的beanDefinition的作用域来真正创建bean对象。

     7.1 如果是单例bean,创建bean后将bean添加到单例池。

     7.2 如果是原型bean,创建bean后将直接返回。

     7.3 其他类型的作用域如request、session等则是基于HttpRequest、HttpSession等来实现bean的存储的。

三、createBean源码

  3.1. 加载类

  3.2. 将合并后的beanDefinition的Beanclass属性设置为加载的类。

  3. 进行实例化前操作:有定义实现了InstantiationAwareBeanPostProcessor接口的实现类,则可对每个对象进行实例化前操作,即调用InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation(),如果实例化前方法有返回对象,则直接返回,否则进入下一步。

   4. 实例化:

   4.1 判断当前bean是否已在别的bean创建过程中被创建了(被别的bean依赖注入)。如果没有则真正的创建bean。

   4.2 推断构造方法:

  5. 判断是否有实现了MergedBeanDefinitionPostProcessor.postProcessMergedInstantiation(),如果有通过它来修改beanDefinition的值。    

  5. 进行实例化后操作:有定义InstantiationAwareBeanPostProcessor接口的实现类,则可对每个对象进行实例化后操作,即调用InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation(),如果实例化后方法返回false,则直接返回,否则进入下一步。

  6. 属性的依赖注入:

   6.1 执行spring自带的属性注入,即@Bean(Autowired.BY_NAME)这种。Autowired.BY_NAME是根据set方法名去找。

   6.2 执行@Autowired、@Resource、@Value注解,如果到这一步之前已经给属性赋值了则跳过这一步,因为有可能程序员手动赋值了。没有则是通过InstantiationAwareBeanPostProcessor.postProcessProperties()实现。@Autowired、@Resource、@Value注解都是通过实现了InstantiationAwareBeanPostProcessor接口来处理的。

  7. 依赖注入完后就是初始化操作,分为四步:

  7.1 Aware回调,如果bean实现了Aware或其子接口,则会进行Aware的回调。

  7.1 初始化前,同初始化后一样是通过BeanPostProcessor机制实现的。

  7.2. 初始化,这里如果bean实现了InitializingBean接口,则会调用它的afterPropertiesSet()方法

  7.3. 初始化后

  8.  销毁方法,在初始化后还有最后一步,就是收集bean的销毁方法信息,将其加入disposableBeans中(一个LinkedHashMap)

1. 当前Bean是否实现了DisposableBean接口

2. 或者,当前Bean是否实现了AutoCloseable接口

3. BeanDefinition中是否指定了destroyMethod

4. 调用DestructionAwareBeanPostProcessor.requiresDestruction(bean)进行判断

   i. ApplicationListenerDetector中直接使得ApplicationListener是DisposableBean

  ii. InitDestroyAnnotationBeanPostProcessor中使得拥有@PreDestroy注解了的方法就是

DisposableBean

5. 把符合上述任意一个条件的Bean适配成DisposableBeanAdapter对象,并存入

disposableBeans中(一个LinkedHashMap)

在Spring容器关闭过程时:

1. 首先发布ContextClosedEvent事件

2. 调用lifecycleProcessor的onCloese()方法

3. 销毁单例Bean

  i. 遍历disposableBeans

   a. 把每个disposableBean从单例池中移除

   b. 调用disposableBean的destroy()

   c. 如果这个disposableBean还被其他Bean依赖了,那么也得销毁其他Bean

   d. 如果这个disposableBean还包含了inner beans,将这些Bean从单例池中移除掉

(inner bean参考 https://docs.spring.io/spring-framework/docs/current/spring-

framework-reference/core.html#beans-inner-beans )

  ii. 清空manualSingletonNames,是一个Set,存的是用户手动注册的单例Bean的beanName

相关文章
|
Dubbo Java 应用服务中间件
从源码全面解析 dubbo 服务端服务调用的来龙去脉
从源码全面解析 dubbo 服务端服务调用的来龙去脉
|
Dubbo Java 应用服务中间件
深入理解Dubbo-5.服务注册源码分析(上)
深入理解Dubbo-5.服务注册源码分析
259 0
|
Android开发
解决E/RecyclerView: No layout manager attached; skipping layout
解决E/RecyclerView: No layout manager attached; skipping layout
575 1
|
12月前
|
SQL Java 数据库连接
【潜意识Java】MyBatis中的动态SQL灵活、高效的数据库查询以及深度总结
本文详细介绍了MyBatis中的动态SQL功能,涵盖其背景、应用场景及实现方式。
1374 6
|
安全 应用服务中间件 网络安全
简单比较 http https http2,我们要如何把http升级为https
【9月更文挑战第13天】本文对比了HTTP、HTTPS和HTTP/2的特点与适用场景。HTTP以明文传输,适合低安全要求的环境;HTTPS通过SSL/TLS加密,适用于电子商务等安全要求高的场景;HTTP/2采用二进制格式和多路复用,适合高性能Web应用。文章还详细介绍了将HTTP升级为HTTPS的步骤,包括申请和安装SSL证书、配置Web服务器、重定向HTTP流量到HTTPS以及测试HTTPS功能。升级到HTTPS可提高数据安全性和用户信任度。
665 13
|
IDE Java 开发工具
解决IntelliJ IDEA报错Error:Cannot determine path to ‘tools.jar‘ library for 17 (D:/JAVA)
解决IntelliJ IDEA报错Error:Cannot determine path to ‘tools.jar‘ library for 17 (D:/JAVA)
2455 0
|
Java 容器 Spring
Javaweb之SpringBootWeb案例之 Bean管理的获取Bean详细的解析
Javaweb之SpringBootWeb案例之 Bean管理的获取Bean详细的解析
420 0
|
SQL Oracle 关系型数据库
Seata常见问题之2.0报错找不到类如何解决
Seata 是一个开源的分布式事务解决方案,旨在提供高效且简单的事务协调机制,以解决微服务架构下跨服务调用(分布式场景)的一致性问题。以下是Seata常见问题的一个合集
530 0
|
Java Spring
Spring中Bean的五大作用域
Spring中Bean的五大作用域
492 0
|
Java 应用服务中间件 Linux
tomcat启动时黑窗口一闪而过的问题及解决方案
tomcat启动时黑窗口一闪而过的问题及解决方案
782 0

热门文章

最新文章