spring bean 实例化 和 @Autowired 注入原理
bean 实例化
1)在某一时刻 Spring 调用了 Bean 工厂 的 getBean(beanName) 方法。beanName 可能是 simpleController,或者 simpleService,simpleDao,顺序没关系(因为后面会有依赖关系的处理)。我们假设 simpleController 吧。
2)getBean 方法首先会调用 Bean 工厂中定义的 getSingleton(beanName) 方法,来判断是否存在该名字的 bean 单例,若果存在则返回,方法调用结束。
3)否则,Spring 会检查是否存在父工厂,如果有则返回,方法调用结束。
4)否则,Spring 会检查该 bean 定义(BeanDefinition 实例,用来描述 Bean 结构,上篇文章讲到过,component-scan 扫描后,就是将 beanDefinition 实例放入 Bean 工厂,此时 Bean 还没有被实例化。)是否有依赖关系,如果有,执行 1)步,获取依赖的 bean 实例。
5)否则,Spring 会尝试创建这个 bean 实例**,创建实例前,Spring 会检查确定调用的构造器,并实例化该 Bean**。
6)实例化完成后,Spring 会调用 Bean 工厂的 populateBean 方法来填充 bean 实例的属性,也就是我们前面提到的自动转配了。populateBean 方法便是调用了 BeanPostProcessor 实例来完成属性元素的自动装配工作。
7)在元素装配过程中,Spring 会检查被装配的属性是否存在自动装配的其他属性,然后递归调用 getBean 方法,直到所有 @Autowired 的元素都被装配完成。如在装配 simpleController 中的 simpleService 属性时,发现 SimpleServiceImpl 实例中存在 @Autowired 属性 simpleDao,然后调用 getBean(simpleDao)方法,同样会执行 1)-7)整个过程。所以可以看成一个递归过程。
8)装配完成后,Bean 工厂会将所有的 bean 实例都添加到工厂中来。
注:我们知道 Spring MVC 是多线程单实例的 MVC 框架,就是说,对于同一个 Controller,只会生成一个实例来处理所有的请求,因此 bean 实例只会实例化一次,并被存放在工厂中,以供其他请求使用。
实例化与装配
首先 Spring 会检查 beanName,获取规范的 beanName,然后它会检查是否存在已经注册的单例(查询上面提到的 singletonObjects 映射表),如果有的话就直接返回了,一切就结束了,否则的话,会查看是否存在父工厂,如果有调用父工厂的 getBean 方法,如果没有呢?
手创建实例了,首先查看 beanDefinitionMap 查找该 beanName 对应的 beanDefinition 实例,然后根据该实例判断是否存在依赖关系,如果存在在递归的调用 getBean 方法,直到所有的依赖关系都正确的实例化和装配完成,并且将这些依赖关系保存到上面提到的 dependencyForBeanMap 和 dependentBeanMap 中。
这里稍微清晰了,查看 singletonObjects 映射表,看是否存在已经注册的单例,如果没有调用 createBean 方法创建一个,并且注册到 singletonObjects 映射表中,否则直接返回就 Ok 了。
1)一切都是从 bean 工厂的 getBean 方法开始的,一旦该方法调用总会返回一个 bean 实例,无论当前是否存在,不存在就实例化一个并装配,否则直接返回。
2)实例化和装配过程中会多次递归调用 getBean 方法来解决类之间的依赖。
3)Spring 几乎考虑了所有可能性,所以方法特别复杂但完整有条理。
4)@Autowired 最终是根据类型来查找和装配元素的,但是我们设置了后会影响最终的类型匹配查找。因为在前面有根据 BeanDefinition 的 autowire 类型设置 PropertyValue 值得一步,其中会有新实例的创建和注册。就是那个 autowireByName 方法。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: 上瘾 PDF 文档
下一篇: 彻底找到 Tomcat 启动速度慢的元凶
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论