springboot启动流程ioc依赖注入
Posted lay2017
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了springboot启动流程ioc依赖注入相关的知识,希望对你有一定的参考价值。
所有文章
https://www.cnblogs.com/lay2017/p/11478237.html
正文
在前面的几篇文章中,我们多次提到这么一个转化过程:
Bean配置 --> BeanDefinition --> Bean对象
Bean的配置可以是xml配置,也可以是java配置。BeanDefinition配置在内存中数据对象,也是Bean的元数据。在springboot启动过程当中,refresh上下文这个步骤将会解析xml配置以及java配置,从而把Bean的配置解析成为BeanDefinition。我们也可以将这个过程简称为Bean的元数据生成。
这里我们需要注意!refresh只是把BeanDefinition注册到BeanFactory中,而不是把Bean注册到BeanFactory中。(这里我们不讨论non-lazy-init=true的情况)
而是在我们调用上下文的getBean的时候才会去根据BeanDefinition生成
@Override public Object getBean(String name) throws BeansException // return getBeanFactory().getBean(name);
上下文的getBean方法把功能实现委托给了BeanFactory,跟进AbstractBeanFactory的getBean方法
@Override public Object getBean(String name) throws BeansException return doGetBean(name, null, null, false);
doGetBean获取Bean的逻辑
跟进doGetBean方法
protected <T> T doGetBean( final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException final String beanName = transformedBeanName(name); Object bean; // 如果拿到已经注册的单例Bean,直接返回结果 Object sharedInstance = getSingleton(beanName); if (sharedInstance != null && args == null) // bean = getObjectForBeanInstance(sharedInstance, name, beanName, null); else // try final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName); // // 创建单例 if (mbd.isSingleton()) // 回调创建 sharedInstance = getSingleton(beanName, () -> try return createBean(beanName, mbd, args); catch (BeansException ex) // ); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd); else if (mbd.isPrototype()) Object prototypeInstance = null; try beforePrototypeCreation(beanName); // 每次创建 prototypeInstance = createBean(beanName, mbd, args); finally // bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd); else // catch (BeansException ex) // // return (T) bean;
该方法的逻辑是先去单例的缓存中找,如果找得到直接返回。如果找不到,那么判断是单例还是原型,如果是单例创建并缓存,如果是原型那么每次都创建新的。
getSingleton获取单例
跟进创建单例的时候的getSingleton方法
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) // 内置锁控制 synchronized (this.singletonObjects) // 双重校验 Object singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) // boolean newSingleton = false; // try // 回调创建Bean singletonObject = singletonFactory.getObject(); newSingleton = true; catch (IllegalStateException ex) // catch (BeanCreationException ex) // finally // if (newSingleton) // 添加单例到缓存中 addSingleton(beanName, singletonObject); return singletonObject;
这里采用双重校验机制控制了单例,如果二次校验的时候发现缓存中没有Bean,那么就会回调创建的方法去创建一个Bean,然后再注册到本地堆缓存当中。
createBean创建Bean
我们先回到调用getSingleton的方法位置,看一下回调方法实什么
if (mbd.isSingleton()) sharedInstance = getSingleton(beanName, () -> try return createBean(beanName, mbd, args); catch (BeansException ex) // ); bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
创建实现委托给了createBean方法,该方法的实现属于AbstractAutowireCapableBeanFactory,跟进该类的CreateBean方法
@Override protected Object createBean( String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException // RootBeanDefinition mbdToUse = mbd; // try // 创建Bean实例 Object beanInstance = doCreateBean(beanName, mbdToUse, args); // return beanInstance; catch (BeanCreationException | ImplicitlyAppearedSingletonException ex) // catch (Throwable ex) //
继续跟进doCreateBean
protected Object doCreateBean( final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException // 创建Bean实例对象 BeanWrapper instanceWrapper = null; // if (instanceWrapper == null) instanceWrapper = createBeanInstance(beanName, mbd, args); // try // 自动注入 populateBean(beanName, mbd, instanceWrapper); // catch (Throwable ex) // // return exposedObject;
该方法主要包含两个步骤,创建Bean的实例对象和自动注入
createBeanInstance创建实例
跟进createBeanInstance
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) // 省略 // 默认使用无参数构造方法获取实例 return instantiateBean(beanName, mbd);
跟进instantiateBean方法
private InstantiationStrategy instantiationStrategy = new CglibSubclassingInstantiationStrategy(); 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) // // 获取实例化策略 protected InstantiationStrategy getInstantiationStrategy() return this.instantiationStrategy;
默认的实例化策略是CglibSubclassingInstantiationStrategy,它又继承自SimpleInstantiationStrategy,跟进SimpleInstantiationStrategy类的instantiate方法
public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) // 如果不存在需要被重写的方法,那么就不需要使用cglib重写并覆盖该类 if (!bd.hasMethodOverrides()) Constructor<?> constructorToUse; synchronized (bd.constructorArgumentLock) // // 通过构造方法实例化 return BeanUtils.instantiateClass(constructorToUse); else // 需要通过cglib生成 return instantiateWithMethodInjection(bd, beanName, owner);
到这里,BeanDefinition就被初步创建成为了一个Bean实例对象。
populateBean自动注入
前面我们说到,doCreateBean有两个步骤
1)创建Bean实例对象
2)自动注入
回顾一下doCreateBean的代码
protected Object doCreateBean( final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException // 创建Bean实例对象 BeanWrapper instanceWrapper = null; // if (instanceWrapper == null) instanceWrapper = createBeanInstance(beanName, mbd, args); // try // 自动注入 populateBean(beanName, mbd, instanceWrapper); // catch (Throwable ex) // // return exposedObject;
接下来,我们跟进populateBean方法看看当前这个创建好的Bean实例实怎么注入其它Bean的
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) // // 获取待注入的property,配置文件中配置的<property>将在这里被处理 PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); // 按照名字或者类型获取属性,这里会进行递归 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // 按照名字获取属性 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) autowireByName(beanName, mbd, bw, newPvs); // 按照类型获取属性 if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) autowireByType(beanName, mbd, bw, newPvs); pvs = newPvs; boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors(); boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE); PropertyDescriptor[] filteredPds = null; if (hasInstAwareBpps) if (pvs == null) pvs = mbd.getPropertyValues(); for (BeanPostProcessor bp : getBeanPostProcessors()) if (bp instanceof InstantiationAwareBeanPostProcessor) InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp; PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) if (filteredPds == null) filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); // 后置处理器处理@Autowired @Resource等注解 pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) return; pvs = pvsToUse; // 注入<property>属性 if (pvs != null) applyPropertyValues(beanName, mbd, bw, pvs);
我们看到populateBean主要做两件事,获取属性值,然后把属性值给注入到Bean里面去。我们重点关注后置处理器处理@Autowired @Resource注解的逻辑。
AutowiredAnnotationBeanPostProcessor处理@Autowired注入注解
跟进AutowiredAnnotationBeanPostProcessor类的postProcessPropertyValues方法
public PropertyValues postProcessPropertyValues( PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) return postProcessProperties(pvs, bean, beanName);
跟进postProcessProperties方法
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) // 获取当前Bean的元数据,将包含@Autowired等注解的标注的待注入元素 InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs); try // 注入元素 metadata.inject(bean, beanName, pvs); catch (BeanCreationException ex) throw ex; catch (Throwable ex) throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex); return pvs;
后置处理属性值包含两件事,找到当前Bean被@Autowired等注解标注的待注入的元素,然后注入相应的到元素。
跟进findAutowiringMetadata方法
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) . String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) synchronized (this.injectionMetadataCache) metadata = this.injectionMetadataCache.get(cacheKey); if (InjectionMetadata.needsRefresh(metadata, clazz)) if (metadata != null) metadata.clear(pvs); // 构造元数据 metadata = buildAutowiringMetadata(clazz); this.injectionMetadataCache.put(cacheKey, metadata); return metadata;
继续跟进buildAutowiringMetadata
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; do final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); ReflectionUtils.doWithLocalFields(targetClass, field -> // 找到注解@Autowired AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) // boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); ); // elements.addAll(0, currElements); // 往父类递归 targetClass = targetClass.getSuperclass(); while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements);
这里找到注解@Autowired的Field以后包装成Element,然后向父类递归,最后包装成元数据
我们回到postProcessProperties方法以后,再跟进inject注入方法看看
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs) throws Throwable if (this.isField) Field field = (Field) this.member; ReflectionUtils.makeAccessible(field); // 反射设置值,这里的取值会对依赖进行递归处理 field.set(target, getResourceToInject(target, requestingBeanName)); else // 省略
这里主要是对Bean的Field的一个反射来设置值,值的获取将会进行递归处理
CommonAnnotationBeanPostProcessor处理@Resource注入注解
触发后置处理器的逻辑跟AutowiredAnnotationBeanPostProcessor是一样的,我们直接来看看CommonAnnotationBeanPostProcessor的buildAutowiringMetadata方法
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) List<InjectionMetadata.InjectedElement> elements = new ArrayList<>(); Class<?> targetClass = clazz; do final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>(); ReflectionUtils.doWithLocalFields(targetClass, field -> if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) // else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) // // 如果注解了@Resource else if (field.isAnnotationPresent(Resource.class)) // if (!this.ignoredResourceTypes.contains(field.getType().getName())) // 添加element currElements.add(new ResourceElement(field, field, null)); ); // elements.addAll(0, currElements); // 向父类递归 targetClass = targetClass.getSuperclass(); while (targetClass != null && targetClass != Object.class); return new InjectionMetadata(clazz, elements);
元数据返回以后的流程和@Autowired也是一样的。
总结
本文粗略地过了一下ioc依赖注入的过程,从BeanDefinition --> Bean的过程。我们一开始创建了Bean的实例,然后再通过递归解析依赖注入处理把Bean之间的关系结合处理。在最后还提了一下@Autowired和@Resource的后置处理器。
依赖注入的过程相对来说还是很复杂的,包含了非常多的细节处理。但是我们可以简单地去概括一下它,整个依赖注入的过程就是创建Bean,并建立Bean之间的关系。
以上是关于springboot启动流程ioc依赖注入的主要内容,如果未能解决你的问题,请参考以下文章