Spring之依赖注入源码解析

您所在的位置:网站首页 实现依赖注入的两种方法 Spring之依赖注入源码解析

Spring之依赖注入源码解析

2023-06-27 10:40| 来源: 网络整理| 查看: 265

系列文章目录

文章目录 系列文章目录前言Spring容器的主要步骤依赖注入在Spring框架中的触发点源码解析

前言

  Spring的依赖注入(Dependency Injection,DI)是Spring框架核心的一部分,它是实现控制反转(Inversion of Control,IoC)的一种方式。依赖注入可以帮助我们减少代码的耦合度,提高模块间的独立性和可测试性。Spring框架的依赖注入主要发生在Spring容器初始化应用上下文时

Spring容器的主要步骤

先说说Spring容器生命周期的一些主要步骤和依赖注入的阶段:

配置阶段:在这个阶段,Spring容器会读取配置文件(例如XML配置文件或者使用注解的配置类),并根据这些配置信息创建Bean定义。Bean定义包含了创建和装配一个Bean所需要的所有信息。实例化阶段:在这个阶段,Spring容器会根据Bean定义创建Bean实例。这通常是通过调用Bean的构造函数或工厂方法来完成的。依赖注入阶段:在这个阶段,Spring容器会将依赖注入到已经创建的Bean实例中。这通常是通过调用Bean的setter方法或者通过反射直接设置字段值来完成的。这个阶段也可能会触发更多的Bean的创建和注入,如果被注入的Bean依赖于其他的Bean的话。初始化阶段:在这个阶段,Spring容器会调用Bean的初始化方法。这通常是通过调用Bean实现的InitializingBean接口的afterPropertiesSet方法或者调用在配置中指定的自定义初始化方法来完成的。使用阶段:在这个阶段,应用代码可以开始使用已经初始化和装配好的Bean了。销毁阶段:在这个阶段,当应用上下文被关闭时,Spring容器会调用Bean的销毁方法。这通常是通过调用Bean实现的DisposableBean接口的destroy方法或者调用在配置中指定的自定义销毁方法来完成的。

总的来说,Spring的依赖注入主要发生在Spring容器初始化应用上下文的过程中,具体是在实例化阶段之后,初始化阶段之前的依赖注入阶段。

依赖注入在Spring框架中的触发点

先看看触发依赖注入方法调用堆栈的流程图: 在这里插入图片描述

AbstractApplicationContext#refresh():这个方法是整个Spring应用上下文刷新的入口点,包括Bean的创建和初始化。AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory): 这个方法会预实例化所有的单例Bean。DefaultListableBeanFactory#preInstantiateSingletons(): 这个方法会遍历所有的Bean定义,对于每个非懒加载的单例Bean,通过getBean()方法获取Bean的实例。AbstractBeanFactory#getBean(String): 这个方法会检查是否已经存在一个Bean的实例,如果没有,那么它会触发Bean的创建过程。AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[]): 这个方法会创建一个新的Bean实例。AbstractAutowireCapableBeanFactory#doCreateBean(String, RootBeanDefinition, Object[]): 这个方法会创建一个新的Bean实例,填充Bean的属性(也就是依赖注入),并调用Bean的初始化方法。AbstractAutowireCapableBeanFactory#populateBean(String, RootBeanDefinition, BeanWrapper): 这个方法会进行依赖注入,它会遍历Bean的所有属性,对于每个属性,如果它有一个匹配的Bean定义或者已存在的Bean实例,那么这个Bean会被注入到属性中。 源码解析

下面是依赖注入的主要代码

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. // 实例化之后,属性设置之前 if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) { for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) { return; } } } PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); int resolvedAutowireMode = mbd.getResolvedAutowireMode(); if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) { // MutablePropertyValues是PropertyValues具体的实现类 MutablePropertyValues newPvs = new MutablePropertyValues(pvs); // Add property values based on autowire by name if applicable. if (resolvedAutowireMode == AUTOWIRE_BY_NAME) { autowireByName(beanName, mbd, bw, newPvs); } // Add property values based on autowire by type if applicable. if (resolvedAutowireMode == 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 (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { // 这里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,会直接给对象中的属性赋值 // AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了 PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName); if (pvsToUse == null) { return; } } pvs = pvsToUse; } } if (needsDepCheck) { if (filteredPds == null) { filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching); } checkDependencies(beanName, mbd, filteredPds, pvs); } // 如果当前Bean中的BeanDefinition中设置了PropertyValues,那么最终将是PropertyValues中的值,覆盖@Autowired if (pvs != null) { applyPropertyValues(beanName, mbd, bw, pvs); }![在这里插入图片描述](https://img-blog.csdnimg.cn/fbf72b3c614c4efdb5b3ad5bfd6f5a6a.png) }

先是判断BeanWrapper是否为空,为空则抛出异常,然后再进行实例化之后的步骤。也就是执行postProcessAfterInstantiation(Object bean, String beanName)方法 在这里插入图片描述 这里是获取该Bean的自动装配模式,然后基于不同的装配模式添加属性值,Spring的自动装配(autowire)有以下几种模式:

no:这是默认的设置,意味着没有自动装配,bean之间的关系需要通过 或 显式配置。byName:Spring容器通过bean的名称自动装配属性。如果一个bean的属性名称与另一个bean的名称相同,那么它们将被自动装配。byType:Spring容器通过类型自动装配属性。如果一个bean的属性类型与另一个bean的类型相同,那么它们将被自动装配。如果有多个相同类型的bean,则会抛出异常。constructor:类似于 byType,但是适用于构造函数。如果容器中存在不止一个与构造函数参数相同类型的bean,则会抛出异常。autodetect:Spring首先尝试通过构造函数自动装配,如果不能通过构造函数自动装配,那么Spring会尝试通过 byType 模式自动装配。

自动装配虽然可以减少配置的复杂性,但也可能引入歧义性。因此,对于大型项目,通常推荐使用显式装配。 在这里插入图片描述 后面会根据缓存的注入点进行注入。injectionMetadataCache就是用来缓存注入点的。在Spring框架中,injectionMetadataCache是AutowiredAnnotationBeanPostProcessor类(以及它的子类,如CommonAnnotationBeanPostProcessor)的一个成员变量。 在这里插入图片描述 寻找注入点的过程主要发生在AutowiredAnnotationBeanPostProcessor类的findAutowiringMetadata方法中。这个方法首先会尝试从injectionMetadataCache中获取指定类的InjectionMetadata。如果没有找到,就会创建一个新的InjectionMetadata,并将其添加到injectionMetadataCache中。

private InjectionMetadata findAutowiringMetadata(String beanName, Class clazz, @Nullable PropertyValues pvs) { // Fall back to class name as cache key, for backwards compatibility with custom callers. String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName()); // Quick check on the concurrent map first, with minimal locking. 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) { // 如果一个Bean的类型是String...,那么则根本不需要进行依赖注入 if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) { return InjectionMetadata.EMPTY; } List elements = new ArrayList(); Class targetClass = clazz; do { final List currElements = new ArrayList(); // 遍历targetClass中的所有Field ReflectionUtils.doWithLocalFields(targetClass, field -> { // field上是否存在@Autowired、@Value、@Inject中的其中一个 MergedAnnotation ann = findAutowiredAnnotation(field); if (ann != null) { // static filed不是注入点,不会进行自动注入 if (Modifier.isStatic(field.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static fields: " + field); } return; } // 构造注入点 boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } }); // 遍历targetClass中的所有Method ReflectionUtils.doWithLocalMethods(targetClass, method -> { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } // method上是否存在@Autowired、@Value、@Inject中的其中一个 MergedAnnotation ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { // static method不是注入点,不会进行自动注入 if (Modifier.isStatic(method.getModifiers())) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation is not supported on static methods: " + method); } return; } // set方法最好有入参 if (method.getParameterCount() == 0) { if (logger.isInfoEnabled()) { logger.info("Autowired annotation should only be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new AutowiredMethodElement(method, required, pd)); } }); elements.addAll(0, currElements); targetClass = targetClass.getSuperclass(); } while (targetClass != null && targetClass != Object.class); return InjectionMetadata.forElements(elements, clazz); }

当找到所有注入点就会返回。通过注入点注入主要是InstantiationAwareBeanPostProcessor接口中的PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)方法实现,在具体实现类AutowiredAnnotationBeanPostProcessor中找到了注入点的元数据,就开始注入。

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) { // 找注入点(所有被@Autowired注解了的Field或Method) 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; }

注入的元素会有两种,一种是类的字段,还有一种是类的方法,不同类型的元素有不同的注入方法:

这是字段的注入

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { Field field = (Field) this.member; Object value; if (this.cached) { // 对于原型Bean,第一次创建的时候,也找注入点,然后进行注入,此时cached为false,注入完了之后cached为true // 第二次创建的时候,先找注入点(此时会拿到缓存好的注入点),也就是AutowiredFieldElement对象,此时cache为true,也就进到此处了 // 注入点内并没有缓存被注入的具体Bean对象,而是beanName,这样就能保证注入到不同的原型Bean对象 try { value = resolvedCachedArgument(beanName, this.cachedFieldValue); } catch (NoSuchBeanDefinitionException ex) { // Unexpected removal of target bean for cached argument -> re-resolve value = resolveFieldValue(field, bean, beanName); } } else { // 根据filed从BeanFactory中查到的匹配的Bean对象 value = resolveFieldValue(field, bean, beanName); } // 反射给filed赋值 if (value != null) { ReflectionUtils.makeAccessible(field); field.set(bean, value); } }

这是方法的注入 方法的注入首先会去找到该方法参数的Bean对象,然后利用反射调用该方法

@Override protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable { // 如果pvs中已经有当前注入点的值了,则跳过注入 if (checkPropertySkipping(pvs)) { return; } Method method = (Method) this.member; Object[] arguments; if (this.cached) { try { arguments = resolveCachedArguments(beanName); } catch (NoSuchBeanDefinitionException ex) { // Unexpected removal of target bean for cached argument -> re-resolve arguments = resolveMethodArguments(method, bean, beanName); } } else { arguments = resolveMethodArguments(method, bean, beanName); } if (arguments != null) { try { ReflectionUtils.makeAccessible(method); method.invoke(bean, arguments); } catch (InvocationTargetException ex) { throw ex.getTargetException(); } } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3