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之间的关系。

原文地址:https://www.cnblogs.com/lay2017/p/11509724.html

时间: 2024-10-12 17:34:18

springboot启动流程(九)ioc依赖注入的相关文章

SpringBoot启动流程分析(四):IoC容器的初始化过程

SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一):SpringApplication类初始化过程 SpringBoot启动流程分析(二):SpringApplication的run方法 SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法 SpringBoot启动流程分析(四

SpringBoot启动流程分析(五):SpringBoot自动装配原理实现

SpringBoot系列文章简介 SpringBoot源码阅读辅助篇: Spring IoC容器与应用上下文的设计与实现 SpringBoot启动流程源码分析: SpringBoot启动流程分析(一):SpringApplication类初始化过程 SpringBoot启动流程分析(二):SpringApplication的run方法 SpringBoot启动流程分析(三):SpringApplication的run方法之prepareContext()方法 SpringBoot启动流程分析(四

SpringBoot 启动流程

SpringBoot 启动流程 加载 resources/META-INF/spring.factories 中配置的 ApplicationContextInitializer 和 ApplicationListener. /** * 加载在框架内部使用的各种通用工厂 bean. * spring.factories 文件必须满足 Properties 文件格式,属性的 key 是接口或抽象类的全限定类名, * value 是一组由逗号分隔的实现类全类名. */ public final cl

IoC 依赖注入、以及在Spring中的实现

资源来自网络: 去年火得不行的Spring框架,一般的书籍都会从IoC和AOP开始介绍起,这个IoC概念,个人感觉资料里都写得让人看得有些痛苦,所谓IoC,就是控制反转(Inversion of Control)的缩写,这个大家都知道,但是个人觉得理解这个概念,最好应该从依赖(dependence)开始讲起,以下观点由此展开: UML中依赖关系如A依赖于B,就是A中有对方的引用;也就是说依赖就是引用:A依赖于B,就是A使用B来做事情. 所谓依赖,举个例子说明,一个类Person,另一个类Car,

图解IoC 依赖注入

图解IoC 依赖注入

IoC 依赖注入容器 Unity

原文:IoC 依赖注入容器 Unity IoC 是什么? 在软件工程领域,“控制反转(Inversion of Control,缩写为IoC)”是一种编程技术,表述在面向对象编程中,可描述为在编译时静态分析器并不知道具体被耦合的对象,而该对象是在运行时被对象装配器绑定的. 在传统编程中,决定业务流程的对象是被静态分配的.而在 IoC 中,业务流程取决于对象装配器实例化提供的对象,这使利用抽象来定义对象间的交互成为可能.对象装配器为了能绑定一个对象,要求该对象必须具备兼容的抽象定义.例如类 Cla

Spring-DI控制反转和IOC依赖注入

Spring-DI控制反转和IOC依赖注入 DI控制反转实例 IDEAJ自动导入Spring框架 创建UserDao.java接口 public interface UserDao { public void say(); } 创建UserDaoImpl.java继承UserDao.java并重写say()方法 public class UserDaoImpl implements UserDao{ @Override public void say() { System.out.println

ASP.NET MVC IOC依赖注入之Autofac系列(二)- WebForm当中应用

上一章主要介绍了Autofac在MVC当中的具体应用,本章将继续简单的介绍下Autofac在普通的WebForm当中的使用. PS:目前本人还不知道WebForm页面的构造函数要如何注入,以下在WebForm页面将主要采用属性注入的方式. 接下来我们正式进入主题,在上一章的基础上我们再添加一个web项目TianYa.DotNetShare.WebDemo,首先看我们的解决方案 本demo的web项目为ASP.NET Web 应用程序(.NET Framework 4.5) 空Web窗体,需要引用

springboot启动流程(一)构造SpringApplication实例对象

所有文章 https://www.cnblogs.com/lay2017/p/11478237.html 启动入口 本文是springboot启动流程的第一篇,涉及的内容是SpringApplication这个对象的实例化过程.为什么从SpringApplication这个对象说起呢?我们先看一段很熟悉的代码片段 @SpringBootApplication public class SpringBootLearnApplication { public static void main(Str