前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >深入理解-Spring-之源码剖析IOC(二)

深入理解-Spring-之源码剖析IOC(二)

作者头像
用户5224393
发布2019-08-13 14:57:59
3310
发布2019-08-13 14:57:59
举报
文章被收录于专栏:Java研发军团Java研发军团

这章节还是接上上次没有写完的继续写了没有看到上一章节的可以点击此处

5. 如何创建Bean实例并构建Bean的依赖关系网

我们刚刚创建了Bean工厂,并创建 BeanDefinitions 放进Map里,以beanName为key。那么我们现在有了Bean定义,但还没有实例,也没有构建Bean与Bean之间的依赖关系。

我们知道,构建依赖关系是 IOC 的一个重要的任务,我们怎么能放过。那么是在哪里做的呢?在 finishBeanFactoryInitialization(beanFactory) 方法中。该方法中重要的一步是 : beanFactory.preInstantiateSingletons(),我们有必要看看该方法实现:

代码语言:javascript
复制
@Override
 public void preInstantiateSingletons() throws BeansException {
   if (this.logger.isDebugEnabled()) {
     this.logger.debug("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.
   List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

   // Trigger initialization of all non-lazy singleton beans...
   for (String beanName : beanNames) {
     RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
     if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
       if (isFactoryBean(beanName)) {
         final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName);// 注意:FactoryBean
         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);
         }
       }
       else {
         getBean(beanName);// 创建bean
       }
     }
   }

   // 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();
       }
     }
   }
 }

该方法首先循环所有的BeanNames,并且调用getBean方法,该方法实际上就是创建bean并递归构建依赖关系。该方法会调用 doGetBean(name, null, null, false),我们进入该方法查看,该方法很长,楼主挑选重要代码:

代码语言:javascript
复制
String[] dependsOn = mbd.getDependsOn();// if (dependsOn != null) {
 for (String dep : dependsOn) {
   if (isDependent(beanName, dep)) {
     throw new BeanCreationException(mbd.getResourceDescription(), beanName,
         "Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
   }
   registerDependentBean(dep, beanName);
   getBean(dep);// 递归
 }}// Create bean instance.if (mbd.isSingleton()) {
 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);}

可以看到,该方法首先会获取依赖关系,拿着依赖的BeanName 递归调用 getBean方法,直到调用 getSingleton 方法返回依赖bean,而 getSingleton 方法的参数是 createBean 返回的实例,该方法内部调用 AbstractAutowireCapableBeanFactory.doCreateBean 方法:

代码语言:javascript
复制
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
     throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (mbd.isSingleton()) {
     instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
   }
   if (instanceWrapper == null) {
     instanceWrapper = createBeanInstance(beanName, mbd, args);
   }
   final Object bean = instanceWrapper.getWrappedInstance();
   Class<?> beanType = instanceWrapper.getWrappedClass();
   if (beanType != NullBean.class) {
     mbd.resolvedTargetType = beanType;
   }

   // Allow post-processors to modify the merged bean definition.
   synchronized (mbd.postProcessingLock) {
     if (!mbd.postProcessed) {
       try {
         applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
       }
       catch (Throwable ex) {
         throw new BeanCreationException(mbd.getResourceDescription(), beanName,
             "Post-processing of merged bean definition failed", ex);
       }
       mbd.postProcessed = true;
     }
   }

   // Eagerly cache singletons to be able to resolve circular references
   // even when triggered by lifecycle interfaces like BeanFactoryAware.
   boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
       isSingletonCurrentlyInCreation(beanName));
   if (earlySingletonExposure) {
     if (logger.isDebugEnabled()) {
       logger.debug("Eagerly caching bean '" + beanName +
           "' to allow for resolving potential circular references");
     }
     addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
     populateBean(beanName, mbd, instanceWrapper);
     exposedObject = initializeBean(beanName, exposedObject, mbd);
   }
   catch (Throwable ex) {
     if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
       throw (BeanCreationException) ex;
     }
     else {
       throw new BeanCreationException(
           mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
     }
   }

   if (earlySingletonExposure) {
     Object earlySingletonReference = getSingleton(beanName, false);
     if (earlySingletonReference != null) {
       if (exposedObject == bean) {
         exposedObject = earlySingletonReference;
       }
       else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
         String[] dependentBeans = getDependentBeans(beanName);
         Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
         for (String dependentBean : dependentBeans) {
           if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
             actualDependentBeans.add(dependentBean);
           }
         }
         if (!actualDependentBeans.isEmpty()) {
           throw new BeanCurrentlyInCreationException(beanName,
               "Bean with name '" + beanName + "' has been injected into other beans [" +
               StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
               "] in its raw version as part of a circular reference, but has eventually been " +
               "wrapped. This means that said other beans do not use the final version of the " +
               "bean. This is often the result of over-eager type matching - consider using " +
               "'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
         }
       }
     }
   }

   // Register bean as disposable.
   try {
     registerDisposableBeanIfNecessary(beanName, bean, mbd);
   }
   catch (BeanDefinitionValidationException ex) {
     throw new BeanCreationException(
         mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
   }

   return exposedObject;
 }

该方法很长,我们只关注二行代码:

  1. instanceWrapper = createBeanInstance(beanName, mbd, args) 创建实例。
  2. populateBean(beanName, mbd, instanceWrapper) , 该方法用于填充Bean,该 方法可以就是说就是发生依赖注入的地方。

我们看看 createBeanInstance 方法:

代码语言:javascript
复制
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<?> instanceSupplier = mbd.getInstanceSupplier();
   if (instanceSupplier != null) {
     return obtainFromSupplier(instanceSupplier, beanName);
   }

   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) {
       if (mbd.resolvedConstructorOrFactoryMethod != null) {
         resolved = true;
         autowireNecessary = mbd.constructorArgumentsResolved;
       }
     }
   }
   if (resolved) {
     if (autowireNecessary) {
       return autowireConstructor(beanName, mbd, null, null);
     }
     else {
       return instantiateBean(beanName, mbd);
     }
   }

   // Need to determine the constructor...
   Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
   if (ctors != null ||
       mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_CONSTRUCTOR ||
       mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args))  {
     return autowireConstructor(beanName, mbd, ctors, args);
   }

   // No special handling: simply use no-arg constructor.
   return instantiateBean(beanName, mbd);
 }

该方法的doc注释是这样介绍的:为指定的bean创建一个新的实例,使用适当的实例化策略:工厂方法、构造函数自动装配或简单实例化。

我们看,该方法首先创建Class 对象,然后获取构造器对象,最后调用 instantiateBean(beanName, mbd) 方法,我们看看该方法实现:

代码语言:javascript
复制
protected BeanWrapper instantiateBean(final String beanName, final RootBeanDefinition mbd) {
   try {
     Object beanInstance;
     final BeanFactory parent = this;
     if (System.getSecurityManager() != null) {
       beanInstance = AccessController.doPrivileged((PrivilegedAction<Object>) () ->
           getInstantiationStrategy().instantiate(mbd, beanName, parent),
           getAccessControlContext());
     }
     else {
       beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent);
     }
     BeanWrapper bw = new BeanWrapperImpl(beanInstance);
     initBeanWrapper(bw);
     return bw;
   }
   catch (Throwable ex) {
     throw new BeanCreationException(
         mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
   }
 }

该方法核心逻辑是 beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, parent),携带BeanName ,RootBeanDefinition ,发挥的策略对象是 SimpleInstantiationStrategy,该方法内部调用静态方法 BeanUtils.instantiateClass(constructorToUse), 组后调用 Constructor 的 newInstance 方法, 也就是最终使用反射创建了该实例:

代码语言:javascript
复制
public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
   Assert.notNull(ctor, "Constructor must not be null");
   try {
     ReflectionUtils.makeAccessible(ctor);
     return (KotlinDetector.isKotlinType(ctor.getDeclaringClass()) ?
         KotlinDelegate.instantiateClass(ctor, args) : ctor.newInstance(args));
   }
   catch (InstantiationException ex) {
     throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
   }
   catch (IllegalAccessException ex) {
     throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
   }
   catch (IllegalArgumentException ex) {
     throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
   }
   catch (InvocationTargetException ex) {
     throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
   }
 }

该方法会判断是否是 Kotlin 类型。如果不是,则调用构造器的实例方法。

到这里,我们的实例已经创建。但是我们的实例的依赖还没有设置,刚刚我们在 doCreateBean 方法说关心2行代码:

  1. instanceWrapper = createBeanInstance(beanName, mbd, args) 创建实例。
  2. populateBean(beanName, mbd, instanceWrapper) , 该方法用于填充Bean,该方法可以就是说就是发生依赖注入的地方。

我们已经解析了第一个,现在看第二个方法:

代码语言:javascript
复制
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
   if (bw == null) {
     if (mbd.hasPropertyValues()) {
       throw new BeanCreationException(
           mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
     }
     else {
       // Skip property population phase for null instance.
       return;
     }
   }

   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   boolean continueWithPropertyPopulation = true;

   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
     for (BeanPostProcessor bp : getBeanPostProcessors()) {
       if (bp instanceof InstantiationAwareBeanPostProcessor) {
         InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
         if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
           continueWithPropertyPopulation = false;
           break;
         }
       }
     }
   }

   if (!continueWithPropertyPopulation) {
     return;
   }

   PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);

   if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME ||
       mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
     MutablePropertyValues newPvs = new MutablePropertyValues(pvs);

     // Add property values based on autowire by name if applicable.
     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_NAME) {
       autowireByName(beanName, mbd, bw, newPvs);
     }

     // Add property values based on autowire by type if applicable.
     if (mbd.getResolvedAutowireMode() == RootBeanDefinition.AUTOWIRE_BY_TYPE) {
       autowireByType(beanName, mbd, bw, newPvs);
     }

     pvs = newPvs;
   }

   boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
   boolean needsDepCheck = (mbd.getDependencyCheck() != RootBeanDefinition.DEPENDENCY_CHECK_NONE);

   if (hasInstAwareBpps || needsDepCheck) {
     if (pvs == null) {
       pvs = mbd.getPropertyValues();
     }
     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;
           }
         }
       }
     }
     if (needsDepCheck) {
       checkDependencies(beanName, mbd, filteredPds, pvs);
     }
   }

   if (pvs != null) {
     applyPropertyValues(beanName, mbd, bw, pvs);
   }
 }

该方法核心逻辑是

PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null),

即获取该bean的所有属性,也就是我们配置property元素。最后执行 applyPropertyValues(beanName, mbd, bw, pvs) 方法。

注意,现在的PropertyValues 都是字符串,没有值的,这个方法的作用就是获取值,关键代码:

Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue)

该方法会获取 pvName 所对应的容器value,该方法内部会调用 BeanWrapperImpl.resolveReference(argName, ref) 方法,我们看看该方法:

代码语言:javascript
复制
@Nullable
 private Object resolveReference(Object argName, RuntimeBeanReference ref) {
   try {
     Object bean;
     String refName = ref.getBeanName();
     refName = String.valueOf(doEvaluate(refName));
     if (ref.isToParent()) {
       if (this.beanFactory.getParentBeanFactory() == null) {
         throw new BeanCreationException(
             this.beanDefinition.getResourceDescription(), this.beanName,
             "Can't resolve reference to bean '" + refName +
             "' in parent factory: no parent factory available");
       }
       bean = this.beanFactory.getParentBeanFactory().getBean(refName);
     }
     else {
       bean = this.beanFactory.getBean(refName);
       this.beanFactory.registerDependentBean(refName, this.beanName);
     }
     if (bean instanceof NullBean) {
       bean = null;
     }
     return bean;
   }
   catch (BeansException ex) {
     throw new BeanCreationException(
         this.beanDefinition.getResourceDescription(), this.beanName,
         "Cannot resolve reference to bean '" + ref.getBeanName() + "' while setting " + argName, ex);
   }
 }

其中有一行熟悉的代码:bean = this.beanFactory.getBean(refName),对,这里就是发生递归的地方。该方法会拿着属性名称从容器中获取实例。

我们回到 applyPropertyValues 方法。此时deepCopy 集合已经有值了,不再仅仅是字符串了。

然后调用 setPropertyValues(new MutablePropertyValues(deepCopy)) 方法, 该方法会调用 AbstractPropertyAccessor.setPropertyValues 方法完成注入,而该方法会循环元素列表, 循环中调用 setPropertyValue(PropertyValue pv) 方法, 该方法最后会调用 nestedPa.setPropertyValue(tokens, pv) 方法, 该方法又会调用 processLocalProperty(tokens, pv) 方法,该方法最后又会调用 ph.setValue(valueToApply) 方法,也就是BeanWrapperImpl.setValue() 方法,终于,我们要看到反射了,看到反射说明到了尽头。

代码语言:javascript
复制
@Override
public void setValue(final @Nullable Object value) throws Exception {
     final Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?
         ((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :
         this.pd.getWriteMethod());
     if (System.getSecurityManager() != null) {
       AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         ReflectionUtils.makeAccessible(writeMethod);
         return null;
       });
       try {
         AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->
             writeMethod.invoke(getWrappedInstance(), value), acc);
       }
       catch (PrivilegedActionException ex) {
         throw ex.getException();
       }
     }
     else {
       ReflectionUtils.makeAccessible(writeMethod);
       writeMethod.invoke(getWrappedInstance(), value);
     }
}

该方法是最后一步,我们看到该方法会找的set方法,然后调用 Method 的 invoke 方法,完成属性注入。

6. 总结

我们从源码层面剖析 IOC 的初始化过程,也了解了 IOC 的底层原理实现, 我们总结一下:

Spring 的 Bean 其实就是 BeanDefinition, 在 Bean 的创建和依赖注入的过程中, 需要根据 BeanDefinition 的信息来递归的完成依赖注入。

从我们分析的代码可以看到,这些递归都是以 getBean() 为入口的, 一个递归是在上下文体系中查找需要的 Bean 和创建 Bean 的递归调用, 另一个 Bean 实在依赖注入时,通过递归调用容器的 getBean 方法, 得到当前的依赖 Bean, 同时也触发对依赖 Bean 的创建和注入。

在对 Bean 的属性尽心依赖注入时, 解析的过程也是一个递归的过程, 这样, 根据依赖关系, 一层一层的完成 Bean 的创建和注入, 知道最后完成当前 Bean 的创建, 有了这个顶层 Bean 的创建和对他的属性依赖注入的完成, 意味着当前 Bean 相关的整个依赖链的注入也完成了.

总结一下 IOC 的初始化过程吧:

  1. 资源(Resource)定位;
  2. BeanDefinition 的载入和 BeanFactory 的构造.
  3. 想 IOC 容器(BeanFactory)注册 BeanDefinition.
  4. 根据 lazy-init 属性初始化 Bean 实例和依赖注入.

现在回过头看看, 我们已经了解了 Spring IOC 的设计, 那么我们自己可以实现一个简单的 IOC 吗? 楼主想试试, 并且楼主已经写好了, 下篇, 和大家一起实现一个简单的 IOC.

END

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-07-12,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Java研发军团 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 5. 如何创建Bean实例并构建Bean的依赖关系网
  • 6. 总结
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档