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

  • 相关阅读:
    STL与基础数据结构
    solr基础总结
    linux命令笔记
    SolrCloud集群部署
    oracle SQL笔记
    内存溢出之Tomcat内存配置
    solr查询优化(实践了一下效果比较明显)
    JAVA处理线程超时
    Solr 数据导入 <一>DIH简单使用
    几种防止表单重复提交的方法
  • 原文地址:https://www.cnblogs.com/lay2017/p/11509724.html
Copyright © 2020-2023  润新知