• Spring 源码分析之 bean 依赖注入原理(注入属性)


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

     

    本文想写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容器如下图:

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

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

    2. Bean依赖关系的定义

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

    通过XML配置Bean依赖关系:

    <beans xmlns="http://www.springframework.org/schema/beans">
        <!-- orderDao 不需要任何的依赖 -->
        <bean id="orderDao" class="spring.DI.OrderDao"/>
        <!-- orderService 需要依赖orderDao -->
        <bean id="orderService" class="spring.DI.OrderService">
            <property name="orderDao" ref="orderDao"/>
        </bean>
        <!-- orderController orderService 也间接依赖了orderDao -->
        <bean id="orderController" class="spring.DI.OrderController">
            <property name="orderService" ref="orderService"/>
        </bean>
    </beans>
    1 public class OrderController {
    2     private OrderService orderService;
    3     public OrderService getOrderService() {
    4         return orderService;
    5     }
    6     public void setOrderService(OrderService orderService) {
    7         this.orderService = orderService;
    8     }
    9 }

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

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

    <context:component-scan base-package="xxx.yyy"/>
     1 @Controller
     2 public class OrderController {
     3     
     4     @Autowired
     5     private OrderService orderService;
     6     public OrderController() {
     7     }
     8 }
     9 
    10 Service
    11 public class OrderService {
    12     @Autowired
    13     private OrderDao orderDao;
    14     public OrderService() {
    15     }
    16 }
    17 
    18 @Repository
    19 public class OrderDao {
    20     public OrderDao() {
    21     }
    22 }

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

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

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

     1 ApplicationContext context = new ClassPathXmlApplicationContext("spring-beans.xml");
     2 
     3 public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)throws BeansException {
     4     super(parent);
     5     setConfigLocations(configLocations);
     6     if (refresh) {
     7         // 容器初始化入口
     8         refresh();
     9     }
    10 }
    11 
    12 public void refresh() throws BeansException, IllegalStateException {
    13     synchronized (this.startupShutdownMonitor) {
    14         prepareRefresh();
    15         // Prepare the bean factory for use in this context.
    16         prepareBeanFactory(beanFactory);
    17         // Allows post-processing of the bean factory in context subclasses.
    18         postProcessBeanFactory(beanFactory);
    19         // Invoke factory processors registered as beans in the context.
    20         invokeBeanFactoryPostProcessors(beanFactory);
    21         // Register bean processors that intercept bean creation.
    22         registerBeanPostProcessors(beanFactory);
    23         // Instantiate all remaining (non-lazy-init) singletons.
    24         // 初始化所有非 懒加载的bean!!!!
    25         finishBeanFactoryInitialization(beanFactory);
    26         // Last step: publish corresponding event.
    27         finishRefresh();
    28     }
    29   }

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

     1 protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
     2        // Stop using the temporary ClassLoader for type matching.
     3        beanFactory.setTempClassLoader(null);
     4        // 此处省略多行与本次无关代码
     5        // Instantiate all remaining (non-lazy-init) singletons.
     6        beanFactory.preInstantiateSingletons();
     7    }
     8 
     9 public void preInstantiateSingletons() throws BeansException {
    10    // 所有beanDefinition集合
    11    List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames);
    12    // 触发所有非懒加载单例bean的初始化
    13    for (String beanName : beanNames) {
    14       RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    15       // 判断是否是懒加载单例bean,如果是单例的并且不是懒加载的则在Spring 容器
    16       if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
    17           // 判断是否是FactoryBean
    18          if (isFactoryBean(beanName)) {
    19              // 对FactoryBean的处理
    20          }else {
    21              // 如果是普通bean则进行初始化依赖注入,此 getBean(beanName)接下来触发的逻辑跟
    22              // context.getBean("beanName") 所触发的逻辑是一样的
    23             getBean(beanName);
    24          }
    25       }
    26    }
    27 }
    28 
    29 @Override
    30 public Object getBean(String name) throws BeansException {   
    31     return doGetBean(name, null, null, false);
    32 }

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

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

    1 @Override
    2 public Object getBean(String name) throws BeansException {   
    3     return doGetBean(name, null, null, false);
    4 }

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

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

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

    普通的属性的值用 value

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

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

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

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

    1. 依赖注入实现的入口

     1 protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
     2     //第一步 创建bean实例 还未进行属性填充和各种特性的初始化
     3     BeanWrapper instanceWrapper = null;
     4     if (instanceWrapper == null) {
     5         instanceWrapper = createBeanInstance(beanName, mbd, args);
     6     }
     7     final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
     8     Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
     9     Object exposedObject = bean;
    10     try {
    11         // 第二步 进行依赖注入(注入属性)
    12         populateBean(beanName, mbd, instanceWrapper);
    13         if (exposedObject != null) {
    14          // 第三步  执行bean的初始化方法
    15         exposedObject = initializeBean(beanName, exposedObject, mbd);
    16         }
    17     }catch (Throwable ex) {
    18      //  抛相应的异常
    19     }
    20     return exposedObject;
    21 }

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

     1 populateBean(beanName, mbd, instanceWrapper);
     2 
     3 protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
     4         // 所有的属性
     5     PropertyValues pvs = mbd.getPropertyValues();
     6     // 这里是处理自动装配类型的, autowire=byName 或者byType。如果不配置不走这个分支,xml或注解都可配 
     7     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
     8             mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
     9         pvs = newPvs;
    10     }
    11     // 后处理器是否已经准备好(后处理器会处理已@Autowired 形式来注入的bean, 有一个  
    12     // 子类AutowiredAnnotationBeanPostProcessor来处理@Autowired注入的bean)
    13     boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
    14     // 是否需要依赖检查
    15     boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
    16     if (hasInstAwareBpps || needsDepCheck) {
    17         PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
    18         if (hasInstAwareBpps) {
    19             for (BeanPostProcessor bp : getBeanPostProcessors()) {
    20                 if (bp instanceof InstantiationAwareBeanPostProcessor) {
    21                     InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
    22                     // 这里会处理对注解形式的注入 重点!!!!
    23                     pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
    24                     if (pvs == null) {
    25                         return;
    26                     }
    27                 }
    28             }
    29         }
    30     }
    31     // 注入参数的方法(注解的Bean的依赖注入除外)
    32     applyPropertyValues(beanName, mbd, bw, pvs);
    33 }

    2. 注解形式注入的源码

     1 // 后处理器是否已经准备好(后处理器会处理已@Autowired 形式来注入的bean, 有一个  
     2 // 子类AutowiredAnnotationBeanPostProcessor来处理@Autowired注入的bean)
     3 boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
     4 // 是否需要依赖检查
     5 boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);
     6 if (hasInstAwareBpps || needsDepCheck) {
     7     PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
     8     if (hasInstAwareBpps) {
     9         for (BeanPostProcessor bp : getBeanPostProcessors()) {
    10             if (bp instanceof InstantiationAwareBeanPostProcessor) {
    11                 InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor)bp;
    12                 // 这里会处理对注解形式的注入,比如 @Autowired注解 由类AutowiredAnnotationBeanPostProcessor来处理
    13                 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
    14                 if (pvs == null) {
    15                     return;
    16                 }
    17             }
    18         }
    19     }
    20 }
    21 
    22 pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
     1 @Override
     2 public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
     3         // 这里定义了把谁注入到哪里
     4     InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
     5     try {  
     6        // 进行注入
     7        metadata.inject(bean, beanName, pvs);
     8     }catch (Throwable ex) {
     9         throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
    10     }
    11     return pvs;
    12 }

    InjectionMetadata在这个类里头封装了依赖的bean与被依赖的bean的信息,比如orderCcontroller 依赖orderService,需要把orderService 注入到orderController。

    其中injectedElements就是所有需要被注入的bean

     1 protected void inject(Object target, String requestingBeanName, PropertyValues pvs) throws Throwable {
     2     if (this.isField) {
     3         Field field = (Field) this.member;
     4         ReflectionUtils.makeAccessible(field);
     5         field.set(target, getResourceToInject(target, requestingBeanName));
     6     }else {
     7         if (checkPropertySkipping(pvs)) {
     8            return;
     9         }
    10         try {
    11            Method method = (Method) this.member;
    12            ReflectionUtils.makeAccessible(method);
    13            method.invoke(target, getResourceToInject(target, requestingBeanName));
    14         }catch (InvocationTargetException ex) {
    15           throw ex.getTargetException();
    16         }
    17     }
    18 }

    3. xml 配置形式注入的源码

    1 applyPropertyValues(beanName, mbd, bw, pvs);

    这个步骤主要做的就是把属性转 换成 相对应的类的属性类型,并最后注入到依赖的bean里头,由一下步骤组成:

      • 判断是否已转换
      • 进行转换
      • 注入到bean
     1 protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
     2         MutablePropertyValues mpvs = null;
     3         List<PropertyValue> original;
     4         if (pvs instanceof MutablePropertyValues) {
     5             mpvs = (MutablePropertyValues) pvs;
     6             // 判断是否已转换,已经转换了则return
     7             if (mpvs.isConverted()) {
     8                 // Shortcut: use the pre-converted values as-is.
     9                 bw.setPropertyValues(mpvs);
    10                 return;
    11             }
    12             original = mpvs.getPropertyValueList();
    13         }
    14         TypeConverter converter = getCustomTypeConverter();
    15         BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
    16         // Create a deep copy, resolving any references for values.
    17         List<PropertyValue> deepCopy = new ArrayList<PropertyValue>(original.size());
    18         boolean resolveNecessary = false;
    19         for (PropertyValue pv : original) {
    20             if (pv.isConverted()) {
    21                 deepCopy.add(pv);
    22             } else {
    23                 // 属性名 如(name,orderService)
    24                 String propertyName = pv.getName();
    25                 // 未转换前的值,稍后贴出debug时的图
    26                 Object originalValue = pv.getValue();
    27                 // 转换后的值,进行转换处理(重要!!!!)
    28                 Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
    29                 Object convertedValue = resolvedValue;
    30                 // 
    31                 if (resolvedValue == originalValue) {
    32                     if (convertible) {
    33                         pv.setConvertedValue(convertedValue);
    34                     }
    35                     deepCopy.add(pv);
    36                 } else if (convertible && originalValue instanceof TypedStringValue &&
    37                         !((TypedStringValue) originalValue).isDynamic() &&
    38                         !(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {
    39                     pv.setConvertedValue(convertedValue);
    40                     deepCopy.add(pv);
    41                 } else {
    42                     resolveNecessary = true;
    43                     deepCopy.add(new PropertyValue(pv, convertedValue));
    44                 }
    45             }
    46         }
    47         // 转换完成
    48         if (mpvs != null && !resolveNecessary) {
    49             mpvs.setConverted();
    50         }
    51         // 这里就是进行属性注入的地方,跟上面的inject方法类似
    52         try {
    53             bw.setPropertyValues(new MutablePropertyValues(deepCopy));
    54         } catch (BeansException ex) {
    55             throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Error setting property values", ex);
    56         }
    57     }

    下面介绍上述步骤中的两个核心的流程:

    • 进行转换操作,生成最终需要注入的类型的对象
    • 进行注入操作

    1.进行转换操作,生成最终需要注入的类型的对象

    这个方法会返回一个我们最终要注入的一个属性对应类的一个对象

    1 Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

    根据参数类型做具体的转换处理,参数类型包括 1.Bean 2.Array 3.List 4.Set 5.Map 6.String 等等。

     1 public Object resolveValueIfNecessary(Object argName, Object value) {
     2      // Bean 类型
     3     if (value instanceof RuntimeBeanReference) {
     4         RuntimeBeanReference ref = (RuntimeBeanReference) value;
     5         return resolveReference(argName, ref);
     6     }
     7     else if (value instanceof ManagedArray) {
     8         // 处理数组
     9         return resolveManagedArray(argName, (List<?>) value, elementType);
    10     }
    11     else if (value instanceof ManagedList) {
    12         // 处理list
    13         return resolveManagedList(argName, (List<?>) value);
    14     }
    15     else if (value instanceof ManagedSet) {
    16         // 处理set
    17         return resolveManagedSet(argName, (Set<?>) value);
    18     }
    19     else if (value instanceof ManagedMap) {
    20         // 处理map
    21         return resolveManagedMap(argName, (Map<?, ?>) value);
    22     }
    23     else if (value instanceof TypedStringValue) {
    24     // 处理字符串
    25     }
    26     else {
    27         return evaluate(value);
    28     }
    29 }
    30 
    31 private Object resolveReference(Object argName, RuntimeBeanReference ref) {
    32     try {
    33     String refName = ref.getBeanName();
    34     refName = String.valueOf(doEvaluate(refName));
    35     if (ref.isToParent()) {
    36         if (this.beanFactory.getParentBeanFactory() == null) {
    37             throw new BeanCreationException("");
    38         }
    39         return this.beanFactory.getParentBeanFactory().getBean(refName);
    40     }else {
    41         Object bean = this.beanFactory.getBean(refName);
    42         this.beanFactory.registerDependentBean(refName, this.beanName);
    43         return bean;
    44     }
    45     }catch (BeansException ex) {throw new BeanCreationException(this.beanDefinition.getResourceDescription(), this.beanName,
    46                 "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName,ex);
    47     }
    48 }
    49 
    50 Object bean = this.beanFactory.getBean(refName);
    51 
    52 this.beanFactory.getParentBeanFactory().getBean(refName);

    从sprig ioc 容器的双亲中获取bean(被依赖的bean),假如orderCcontroller依赖orderService,则从容器中获取orderService。这里有个关键点,也就是这个获取bean的过程也是一个依赖注入的过程,换句话说依赖注入是个递归的过程!!!!!!知道被依赖的bean不依赖任何bean。

    • orderCcontroller 依赖 orderService 的操作会触发 orderService 依赖 orderDao的操作

    2.进行注入操作

    这一步是通过Java的反射机制根据set 方法把属性注入到bean里。

     1 bw.setPropertyValues(new MutablePropertyValues(deepCopy));
     2 
     3 protected void setPropertyValue(AbstractNestablePropertyAccessor.PropertyTokenHolder tokens, PropertyValue pv) throws BeansException {
     4     String propertyName = tokens.canonicalName;
     5     String actualName = tokens.actualName;
     6     if (tokens.keys != null) {
     7      // 处理集合类型
     8     }
     9     else {
    10         // 对非集合类型的处理
    11         AbstractNestablePropertyAccessor.PropertyHandler ph = getLocalPropertyHandler(actualName);
    12         Object oldValue = null;
    13         try {
    14             Object originalValue = pv.getValue();
    15             Object valueToApply = originalValue;
    16             if (!Boolean.FALSE.equals(pv.conversionNecessary)) {
    17                 if (pv.isConverted()) {
    18                     valueToApply = pv.getConvertedValue();
    19                 }else {
    20                     if (isExtractOldValueForEditor() && ph.isReadable()) {
    21                         try {
    22                             oldValue = ph.getValue();
    23                         }catch (Exception ex) {}
    24                     }
    25                     valueToApply = convertForProperty(propertyName, oldValue, originalValue, ph.toTypeDescriptor());
    26                 }
    27                 pv.getOriginalPropertyValue().conversionNecessary = (valueToApply != originalValue);
    28             }
    29              // 通过反射注入
    30             ph.setValue(object, valueToApply);
    31             }
    32         }
    33     }
    34 
    35 public void setValue(final Object object, Object valueToApply) throws Exception {
    36     final Method writeMethod = this.pd.getWriteMethod();
    37     if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers()) && !writeMethod.isAccessible()) {
    38         if (System.getSecurityManager() != null) {
    39             AccessController.doPrivileged(new PrivilegedAction<Object>() {
    40                 @Override
    41                 public Object run() {
    42                     writeMethod.setAccessible(true);
    43                     return null;
    44                 }
    45             });
    46         } else {
    47             writeMethod.setAccessible(true);
    48         }
    49     }
    50     final Object value = valueToApply;
    51     if (System.getSecurityManager() != null) {
    52     } else {
    53         // 通过反射 用set 方法注入属性
    54         writeMethod.invoke(getWrappedInstance(), value);
    55     }
    56 }

     转自:https://zhuanlan.zhihu.com/p/61744838?utm_source=wechat_session&utm_medium=social&utm_oi=791980836567289856

  • 相关阅读:
    仿苹果菜单的效果
    不用系统自带的复选框,单选按钮,选择框的样式,该怎么做
    js面向对象(三)---组件开发
    JS面向对象(二)---继承
    js面向对象(一)---基本的概念、属性、方法
    移动端新建html页面
    《程序员思维修炼》读后摘录
    做一个简单的贪吃蛇游戏
    做一个简单的遮罩层
    在不同设备上控制元素
  • 原文地址:https://www.cnblogs.com/fnlingnzb-learner/p/10694592.html
Copyright © 2020-2023  润新知