配置所需要的依赖_Spring 源码分析之 bean 依赖注入原理(注入属性)

最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spring bean 的生命周期讲清楚,所以最后决定分解成几个模块来写,最后在写一篇文章把各个内容串联起来,这样可以讲的更细更深入不会犹豫篇幅而讲的太笼统。bean 生命周期所涉及的主要流程如下图所示。

6909edbf79792a10af130bf93541a620.png

本文想写bean 生命周期的第二阶段 bean 的依赖注入(注入属性)部分按下面几个步骤来讲解。

  • Spring容器与依赖注入
  • 什么时候会触发依赖注入?
  • 关于依赖注入与属性注入的几点说明
  • 解析Spring 依赖注入源码部分
  • 总结

一. Spring容器与依赖注入

Spring最有名的高级特性非ioc莫属了,虽然ioc 不是本次要讨论的重点,但还是有必要说一下。对于Spring的ioc我不想过多教科书式的解释这名次,我也相信每个使用Spring的程序员都有自己的理解,只是有时很难把自己的理解清楚的解释给别人而已。下面我说说我自己的理解,有说错的地方欢迎大家指正。Spring ioc 至少要具备一下两点功能:

准备Bean 整个生命周期需要的数据

这一步是Spring 容器启动的时候会 定位 我们的配置文件, 加载 文件,并 解析 成Bean的定义文件 BeanDefinition 来为下一步作准备,这个 BeanDefinition 会贯穿Spring 启动初始化的整个流程,非常重要,因为他是数据基础。

管理Bean的整个生命周期

  • 需要具备创建一个Bean的功能
  • 需要具备根据Bean与Bean之间的关系依赖注入功能(本次要讲的内容)
  • 需要能够执行初始化方法以及销毁方法

有了以上几个功能之后Spring ioc 就能够控制bean的流程了,这不控制反转了么。而我们只需用注解或者配置文件配置bean的特性以及依赖关系即可。下面说一下有关ApplicationContext 和 BeanDefinition:

1. 核心容器ApplicationContext

上述这些功能都可以由Spring容器(比如 ApplicationContext )来实现,Spring启动时会把所有需要的bean扫描并注册到容器里,在这个过程当中Spring会根据我们定义的bean之间的依赖关系来进行注入,依赖关系的维护方式有两种即 XML配置 文件或者 注解 ,Spring启动时会把这些依赖关系转化成Spring能够识别的数据结构 BeanDefinition ,并根据它来进行bean的初始化,依赖注入等操作。下面看看一个简单的Spring容器如下图:

5e359a281bbd239b7cd81074bac176af.png

Spring 依赖注入的实现是由像ApplicationContext这种容器来实现的,右边的Map里存储这bean之间的依赖关系的定义BeanDefinition,比如OrderController依赖OrderService这种,具体定义下面介绍。

结论:BeanDefinition提供了原材料数据基础,而ApplicationContext 提供了流程的设计与实现的算法

2. Bean依赖关系的定义

我们需要为Spring容器提供所有bean的定义以及bean之间的依赖关系,从而进行bean的依赖注入通常有两种方式, XML配置 或者 注解 ,不管是那种最终都会解析成BeanDefinition。

通过XML配置Bean依赖关系

复制代码public class OrderController { private OrderService orderService; public OrderService getOrderService() { return orderService; } public void setOrderService(OrderService orderService) { this.orderService = orderService; }}复制代码

这种注入方式叫做set 方法注入,只需xml配置 加上对引用的bean的get set方法即可

通过注解定义置Bean依赖关系

复制代码@Controllerpublic class OrderController {  @Autowired private OrderService orderService; public OrderController() { }}复制代码@Servicepublic class OrderService { @Autowired private OrderDao orderDao; public OrderService() { }}复制代码@Repositorypublic class OrderDao { public OrderDao() { }}复制代码

Spring 启动时会把我们的定义信息转化成Spring能看懂的BeanDefinition,然后就可以由容器来创建bean以及依赖注入了,具体依赖注入的时候对于配置文件和注解的处理手段还不同,这个一会儿在解释。

二. 什么时候会触发依赖注入?

  • Spring 容器启动初始化的时候(所有单例非懒加载的bean)
  • 懒加载(lazy-init)的bean 第一次进行getBean的时候

1.Spring 容器启动初始化的时候

ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");复制代码public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { // 容器初始化入口 refresh(); }}复制代码public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { prepareRefresh(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory); // Allows post-processing of the bean factory in context subclasses. postProcessBeanFactory(beanFactory); // Invoke factory processors registered as beans in the context. invokeBeanFactoryPostProcessors(beanFactory); // Register bean processors that intercept bean creation. registerBeanPostProcessors(beanFactory); // Instantiate all remaining (non-lazy-init) singletons. // 初始化所有非 懒加载的bean!!!! finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } }复制代码

finishBeanFactoryInitialization(beanFactory);// 初始化所有非 懒加载的bean!!!

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) { // Stop using the temporary ClassLoader for type matching. beanFactory.setTempClassLoader(null); // 此处省略多行与本次无关代码 // Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); }复制代码public void preInstantiateSingletons() throws BeansException { // 所有beanDefinition集合 List beanNames = new ArrayList(this.beanDefinitionNames); // 触发所有非懒加载单例bean的初始化 for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); // 判断是否是懒加载单例bean,如果是单例的并且不是懒加载的则在Spring 容器 if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { // 判断是否是FactoryBean if (isFactoryBean(beanName)) { // 对FactoryBean的处理 }else { // 如果是普通bean则进行初始化依赖注入,此 getBean(beanName)接下来触发的逻辑跟 // context.getBean("beanName") 所触发的逻辑是一样的 getBean(beanName); } } }}复制代码@Overridepublic Object getBean(String name) throws BeansException {  return doGetBean(name, null, null, false);}复制代码

2.懒加载(lazy-init)的bean 第一次进行getBean

懒加载的bean 第一次进行getBean的操作调用的也是同一个方法

@Overridepublic Object getBean(String name) throws BeansException {  return doGetBean(name, null, null, false);}复制代码

doCreateBean是依赖注入的入口,也是我们本次要谈的核心函数。该方法具体实现在AbstractAutowireCapableBeanFactory类,感兴趣的朋友可以进去看看调用链。下面才刚刚开始进入依赖注入源码阶段。

三. 关于依赖注入与属性注入的几点说明

依赖注入其实是属性注入的一种特殊类型,他的特殊之处在于他要注入的是Bean,同样由Spring管理的Bean,而不是其他的参数,如String,List,Set,Array这种。

0113c886963675e9d2b98c8e304727c5.png
305b1feacf671805ef8bc7553a7623a7.png

普通的属性的值用 value

(类型包括 String list set map ...)

Bean类型的属性的引用ref, 这种注入属于依赖注入

四. 解析Spring 依赖注入源码部分

  • 依赖注入实现的入口
  • 注解形式注入的源码
  • xml 配置形式注入的源码

1. 依赖注入实现的入口

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {//第一步 创建bean实例 还未进行属性填充和各种特性的初始化BeanWrapper instanceWrapper = null;if (instanceWrapper == null) {instanceWrapper = createBeanInstance(beanName, mbd, args);}final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);Class> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);Object exposedObject = bean;try { // 第二步 进行依赖注入(注入属性) populateBean(beanName, mbd, instanceWrapper); if (exposedObject != null) { // 第三步 执行bean的初始化方法exposedObject = initializeBean(beanName, exposedObject, mbd); }}catch (Throwable ex) { // 抛相应的异常}return exposedObject;}复制代码

我们这里需要关注的是第二步关于依赖注入这一块,下面这行代码

populateBean(beanName, mbd, instanceWrapper);复制代码protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) { // 所有的属性PropertyValues pvs = mbd.getPropertyValues();// 这里是处理自动装配类型的, autowire=byName 或者byType。如果不配置不走这个分支,xml或注解都可配 if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {pvs = newPvs;}// 后处理器是否已经准备好(后处理器会处理已@Autowired 形式来注入的bean, 有一个 // 子类AutowiredAnnotationBeanPostProcessor来处理@Autowired注入的bean)boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();// 是否需要依赖检查boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);if (hasInstAwareBpps || needsDepCheck) {PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);if (hasInstAwareBpps) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;// 这里会处理对注解形式的注入 重点!!!!pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvs == null) {return;}}}}} // 注入参数的方法(注解的Bean的依赖注入除外)applyPropertyValues(beanName, mbd, bw, pvs);}复制代码

2. 注解形式注入的源码

// 后处理器是否已经准备好(后处理器会处理已@Autowired 形式来注入的bean, 有一个 // 子类AutowiredAnnotationBeanPostProcessor来处理@Autowired注入的bean)boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();// 是否需要依赖检查boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);if (hasInstAwareBpps || needsDepCheck) {PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);if (hasInstAwareBpps) {for (BeanPostProcessor bp : getBeanPostProcessors()) {if (bp instanceof InstantiationAwareBeanPostProcessor) {InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;// 这里会处理对注解形式的注入,比如 @Autowired注解 由类AutowiredAnnotationBeanPostProcessor来处理pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvs == null) {return;}}}}}复制代码pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);复制代码
c13b0c51251284accb6eb60ff3404f99.png
@Overridepublic PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException { // 这里定义了把谁注入到哪里InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {  // 进行注入 metadata.inject(bean, beanName, pvs);}catch (Throwable ex) {throw new BeanCreationException(beanName, "Injection of autowired dependencies failed
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值