Spring源码分析(八)依赖注入源码解析1:autowire自动注入 和 @Autowired注入

news/2024/5/6 5:19:34/文章来源:https://blog.csdn.net/weixin_41947378/article/details/127336111

Spring中到底有几种依赖注入的方式?

首先分两种:

  1. 手动注入
  2. 自动注入

手动注入

在XML中定义Bean时,就是手动注入,因为是程序员手动给某个属性指定了值

<bean name="userService" class="com.luban.service.UserService"><property name="orderService" ref="orderService"/>
</bean>

上面这种底层是通过set方法进行注入。

<bean name="userService" class="com.luban.service.UserService"><constructor-arg index="0" ref="orderService"/>
</bean>

上面这种底层是通过构造方法进行注入。

所以手动注入的底层也就是分为两种:

  1. set方法注入
  2. 构造方法注入

自动注入

自动注入也分为两种:

  1. XML的autowire自动注入
  2. @Autowired注解的自动注入

接下来开始源码分析

入口 - 属性填充阶段

直接看Bean生命周期的属性填充阶段:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {if (bw == null) {...}// 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()) {...}//属性值,用来通过set方法注入的值PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);//1. autowire自动注入int resolvedAutowireMode = mbd.getResolvedAutowireMode();if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {MutablePropertyValues newPvs = new MutablePropertyValues(pvs);// Add property values based on autowire by name if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {//autowire根据Name自动注入(其实只是收集注入值到newPvs中)autowireByName(beanName, mbd, bw, newPvs);}// Add property values based on autowire by type if applicable.if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {//autowire根据Type自动注入(其实只是收集注入值到newPvs中)autowireByType(beanName, mbd, bw, newPvs);}//核心,ByName或者ByType找到属性对应的值以后,就会放到pvs中pvs = newPvs;}boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}//2.@Autowired注解注入for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {//默认提供的实现里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法直接给对象中的属性赋值//	AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了//	AutowiredAnnotationBeanPostProcessor会处理@Autowired、@Value、 @Inject 注解//	CommonAnnotationBeanPostProcessor会处理@Resource注解PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {if (filteredPds == null) {//获取筛选后的propertydescriptor,属性描述器集合(排除被忽略的依赖项类型 或 在被忽略的依赖项接口上 定义的属性)filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}//过时了,在工厂将给定的属性值应用到给定的bean之前,对它们进行后处理。//允许检查是否满足了所有依赖项,例如基于bean属性设置器上的“Required”注解。//	默认实现RequiredAnnotationBeanPostProcessor中,支持给"setXXX"方法加上@Required注解//	标记为“必需的”,简单来说,就是要求pvs属性值中一定要存在 给@Required标记的set方法注入的值  pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {return;}}pvs = pvsToUse;}}//依赖项检查,确保所有公开的属性都已设置//依赖项检查可以是对象引用、“简单”属性(原语和String)或所有(两者都是)if (needsDepCheck) {if (filteredPds == null) {filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);}checkDependencies(beanName, mbd, filteredPds, pvs);}if (pvs != null) {//3.属性赋值(把pvs里的属性值给bean进行赋值!!!!!)//autowire自动注入,其实只是收集注入的值,放到pvs中,最终赋值的动作还是在这里!!//PropertyValues中的值优先级最高//	如果当前Bean中的BeanDefinition中设置了PropertyValues,那么最终将是PropertyValues中的值,覆盖@Autowired的applyPropertyValues(beanName, mbd, bw, pvs);}
}

1. autowire自动注入

xml中可以通过autowire属性设置:

<bean id="user" class="com.yth.service.User" autowire="byName"/>

@Bean方式也行

@ComponentScan("com.yth")
public class AppConfig {@Bean(autowire = Autowire.BY_TYPE)public OrderService orderService() {return new OrderService();}
}

ByName

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireByName

protected void autowireByName(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {//1.1 获取当前bean中能进行自动注入的属性名String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);//遍历每个属性名,并去获取Bean对象,并设置到pvs中for (String propertyName : propertyNames) {if (containsBean(propertyName)) {//直接根据beanName获取BeanObject bean = getBean(propertyName);//这里把propertyName对应的属性值保存到了MutablePropertyValues//暂时只是记录了一下,还没有赋值pvs.add(propertyName, bean);//记录一下propertyName对应的Bean被beanName给依赖了//(之前讲DependsOn注解也走过这个方法)registerDependentBean(propertyName, beanName);if (logger.isTraceEnabled()) {...}}else {...}}
}
  • 直接根据beanName获取Bean
  • 只做了记录,还没有进行赋值的动作!!

ByType

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#autowireByType

protected void autowireByType(String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {TypeConverter converter = getCustomTypeConverter();if (converter == null) {...}Set<String> autowiredBeanNames = new LinkedHashSet<>(4);//1.1 获取当前bean中能进行自动注入的属性名String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);for (String propertyName : propertyNames) {try {PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);// Don't try autowiring by type for type Object: never makes sense,// even if it technically is an unsatisfied, non-simple property.// 如果需要注入的属性类型是Object类型没有意义(注入的时候发现类型是Object这咋注入)if (Object.class != pd.getPropertyType()) {MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);// Do not allow eager init for type matching in case of a prioritized post-processor.// 在优先级后处理器的情况下,不允许为了类型匹配而立即初始化。//	为什么不允许,因为我自己是PriorityOrdered,是优先级最高的,不能有比我创建得更早的//	PriorityOrdered:Ordered接口的扩展,表示优先级排序:priorityorordered对象总是应用在普通Ordered对象之前,而不管其顺序值如何。// 	eager表示立即初始化,表示在根据类型查找Bean时,允不允许进行Bean的创建,如果当前Bean实现了PriorityOrdered则不允许boolean eager = !(bw.getWrappedInstance() instanceof PriorityOrdered);//依赖注入描述器DependencyDescriptor desc = new AutowireByTypeDependencyDescriptor(methodParam, eager);// 1.2 根据类型找到结果(@Autowired注解也是用的这个方法,非常重要和复杂)// 这个方法下一节再讲,很复杂!!Object autowiredArgument = resolveDependency(desc, beanName, autowiredBeanNames, converter);if (autowiredArgument != null) {//和ByName同理,只是记录pvs.add(propertyName, autowiredArgument);}//因为有可能注入的时候是个List<XXXX>,所以这里autowiredBeanNames是个集合for (String autowiredBeanName : autowiredBeanNames) {//记录一下autowiredBeanName对应的Bean被beanName给依赖了registerDependentBean(autowiredBeanName, beanName);if (logger.isTraceEnabled()) {...}}autowiredBeanNames.clear();}}catch (BeansException ex) {...}}
}

同理,只做了记录,还没有进行赋值的动作!!

1.1 获取当前bean中能进行自动注入的属性名

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#unsatisfiedNonSimpleProperties

protected String[] unsatisfiedNonSimpleProperties(AbstractBeanDefinition mbd, BeanWrapper bw) {Set<String> result = new TreeSet<>();PropertyValues pvs = mbd.getPropertyValues();//获取当前对象中,所有符合javaBean定义的有get/set方法的属性的属性描述器//	底层其实只会判断get/set方法,有get/set方法就会解析成一个属性描述器,但是要求get/set方法满足一定的条件//  条件简单理解总结就是://		get方法的定义是: 方法参数个数为0个,并且方法名字以"get"开头 //						或者 方法名字以"is"开头并 且方法的返回类型为boolean//		set方法的定义是:方法参数个数为1个,方法名字以"set"开头,且方法返回类型为 voidPropertyDescriptor[] pds = bw.getPropertyDescriptors();//什么样的属性能进行自动注入?//1.该属性有对应的set方法	pd.getWriteMethod() != null//2.该属性类型没有在ignoredDependencyTypes中//3.如果该属性对应的set方法是实现的某个接口中所定义的,那么接口没有在ignoredDependencyInterfaces中 //4.getPropertyValues中不能包含该属性 !pvs.contains(pd.getName())//5.属性类型不是简单类型,比如int、Integer、int[]for (PropertyDescriptor pd : pds) {if (pd.getWriteMethod() != null && !isExcludedFromDependencyCheck(pd) && !pvs.contains(pd.getName()) &&!BeanUtils.isSimpleProperty(pd.getPropertyType())) {result.add(pd.getName());}}return StringUtils.toStringArray(result);
}

什么样的属性能进行自动注入?

  1. 该属性有对应的set方法 pd.getWriteMethod() != null
  2. 该属性类型没有在ignoredDependencyTypes中
  3. 如果该属性对应的set方法是实现的某个接口中所定义的,那么接口没有在ignoredDependencyInterfaces中
  4. getPropertyValues中不能包含该属性 !pvs.contains(pd.getName())
  5. 属性类型不是简单类型,比如int、Integer、int[]

[2,3]:
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#isExcludedFromDependencyCheck

protected boolean isExcludedFromDependencyCheck(PropertyDescriptor pd) {//AutowireUtils.isExcludedFromDependencyCheck:排除了CGLIB定义的属性//ignoredDependencyTypes:依赖项检查和自动装配时要忽略的依赖项类型,是一个类对象集合:例如,字符串。默认是没有的。//ignoredDependencyInterfaces:依赖项检查和自动装配时要忽略的依赖项接口,是一个类对象的集合。默认情况下,只有BeanFactory接口被忽略。return (AutowireUtils.isExcludedFromDependencyCheck(pd) ||this.ignoredDependencyTypes.contains(pd.getPropertyType()) ||AutowireUtils.isSetterDefinedInInterface(pd, this.ignoredDependencyInterfaces));
}

[4]:比如我们可以在Bean生命周期的 BeanDefinition后置处理阶段,给PropertyValues赋值,这样相同的属性名称,在当前流程中就会跳过该属性,肯定程序员自定义的优先级高喽。
在这里插入图片描述

[5]:判断是否是简单类型
org.springframework.beans.BeanUtils#isSimpleProperty

public static boolean isSimpleProperty(Class<?> type) {Assert.notNull(type, "'type' must not be null");return isSimpleValueType(type) || (type.isArray() && isSimpleValueType(type.getComponentType()));
}public static boolean isSimpleValueType(Class<?> type) {//isPrimitiveOrWrapper方法中,void/Void也会返回true,所以这里一开始就单独判断了一下。return (Void.class != type && void.class != type &&//以下这些都属于简单类型//isPrimitiveOrWrapper:检查给定的类是否代表//		一个原语(即boolean、byte、char、short、int、long、float或double)、void//		或这些类型的包装器(即Boolean、Byte, Character, Short, Integer, Long, Float, Double, or Void)。(ClassUtils.isPrimitiveOrWrapper(type) ||Enum.class.isAssignableFrom(type) ||CharSequence.class.isAssignableFrom(type) ||Number.class.isAssignableFrom(type) ||Date.class.isAssignableFrom(type) ||Temporal.class.isAssignableFrom(type) ||URI.class == type ||URL.class == type ||Locale.class == type ||Class.class == type));
}

注意:

  • isPrimitiveOrWrapper方法中,void/Void也会返回true,所以在isSimpleValueType中一开始会单独判断。
  • Enum、CharSequence、Number…这些都认为是简单类型
  • autowire自动注入会忽略简单数据类型,但是@Autowire不会忽略。

PropertyDescriptor

属性描述器,java.beans提供的。 (java.beans.PropertyDescriptor)
java规范中,认为Bean的属性要有get和set方法
在这里插入图片描述

我们找下PropertyDescriptor是怎么生成的:

org.springframework.beans.BeanWrapper#getPropertyDescriptors    //接口
org.springframework.beans.BeanWrapperImpl#getPropertyDescriptors
org.springframework.beans.BeanWrapperImpl#getCachedIntrospectionResults
org.springframework.beans.CachedIntrospectionResults#forClass
org.springframework.beans.CachedIntrospectionResults#CachedIntrospectionResults	//构造方法
org.springframework.beans.CachedIntrospectionResults#getBeanInfo(java.lang.Class<?>)
org.springframework.beans.BeanInfoFactory#getBeanInfo	//接口
org.springframework.beans.ExtendedBeanInfoFactory#getBeanInfo
java.beans.Introspector#getBeanInfo(java.lang.Class<?>) //从这里开始就是jdk提供的方法了
java.beans.Introspector#getBeanInfo()
java.beans.Introspector#getTargetPropertyInfo

在这里插入图片描述

java.beans.Introspector#getTargetPropertyInfo

private PropertyDescriptor[] getTargetPropertyInfo() {// Check if the bean has its own BeanInfo that will provide// explicit information.// 检查bean是否有自己的BeanInfo来提供显式信息。 (支持自定义BeanInfo)PropertyDescriptor[] explicitProperties = null;if (explicitBeanInfo != null) {...}//检查父类有没有自定义的BeanInfo来提供显式信息if (explicitProperties == null && superBeanInfo != null) {...}//检查额外的类信息(也是通过explicitBeanInfo,自定义BeanInfo提供的)for (int i = 0; i < additionalBeanInfo.length; i++) {...}//explicitProperties是自定义的,如果没有自定义指定,会利用反射解析获取属性信息if (explicitProperties != null) {// Add the explicit BeanInfo data to our results.addPropertyDescriptors(explicitProperties);} else {// 如果没有自定义指定,会利用反射解析获取属性信息// Apply some reflection to the current class.// 否则对当前类应用反射进行解析// First get an array of all the public methods at this level// 获取所有public方法Method methodList[] = getPublicDeclaredMethods(beanClass);// Now analyze each method.for (int i = 0; i < methodList.length; i++) {Method method = methodList[i];if (method == null) {continue;}// skip static methods.// 跳过静态方法int mods = method.getModifiers();if (Modifier.isStatic(mods)) {continue;}//方法名String name = method.getName();//方法入参Class<?>[] argTypes = method.getParameterTypes();//方法返回值Class<?> resultType = method.getReturnType();int argCount = argTypes.length;PropertyDescriptor pd = null;//方法名长度小于3且不是is开头,肯定不属于规范的get/set方法if (name.length() <= 3 && !name.startsWith(IS_PREFIX)) {// Optimization. Don't bother with invalid propertyNames.continue;}try {//方法入参个数0的情况if (argCount == 0) {if (name.startsWith(GET_PREFIX)) {// Simple getterpd = new PropertyDescriptor(this.beanClass, name.substring(3), method, null);} else if (resultType == boolean.class && name.startsWith(IS_PREFIX)) {// Boolean getterpd = new PropertyDescriptor(this.beanClass, name.substring(2), method, null);}} //方法入参个数1的情况else if (argCount == 1) {if (int.class.equals(argTypes[0]) && name.startsWith(GET_PREFIX)) {pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, method, null);} else if (void.class.equals(resultType) && name.startsWith(SET_PREFIX)) {// Simple setterpd = new PropertyDescriptor(this.beanClass, name.substring(3), null, method);if (throwsException(method, PropertyVetoException.class)) {pd.setConstrained(true);}}}//方法入参个数2的情况else if (argCount == 2) {if (void.class.equals(resultType) && int.class.equals(argTypes[0]) && name.startsWith(SET_PREFIX)) {pd = new IndexedPropertyDescriptor(this.beanClass, name.substring(3), null, null, null, method);if (throwsException(method, PropertyVetoException.class)) {pd.setConstrained(true);}}}} catch (IntrospectionException ex) {...}if (pd != null) {// If this class or one of its base classes is a PropertyChange// source, then we assume that any properties we discover are "bound".if (propertyChangeSource) {...}addPropertyDescriptor(pd);}}}//通过合并属性描述符列表来填充属性描述符表。(属性分类合并)//	按照java规范来说,一个属性至少有get/set两个方法,对于一个属性描述器processPropertyDescriptors();// Allocate and populate the result array.PropertyDescriptor result[] =properties.values().toArray(new PropertyDescriptor[properties.size()]);// Set the default index.if (defaultPropertyName != null) {...}return result;
}

判断方法入参个数:

  • 0个的情况:
    • 方法名以"get"开头认为是get方法
    • 方法名以"is"开头,且返回值为boolean类型认为是get方法
  • 1个的情况:
    • 入参类型为int,且方法名以"get"开头认为是get方法(IndexedPropertyDescriptor)
    • 返回值类型为void,且方法名以"set"开头认为是set方法
  • 2个的情况:
    • 返回值类型为void,第一个入参类型为int,且方法名以"set"开头认为是set方法(IndexedPropertyDescriptor)

IndexedPropertyDescriptor:

  • 描述了一个类似数组的属性,它具有索引读和/或索引写方法来访问数组的特定元素。
  • 索引属性还可以提供简单的非索引读和写方法。如果存在,则读写. 索引read方法返回的类型 的数组。

简单概括就是:

  • get方法的定义是: 方法参数个数为0个,并且方法名字以"get"开头

    或者 方法名字以"is"开头并 且方法的返回类型为boolean

  • set方法的定义是:方法参数个数为1个,方法名字以"set"开头,且方法返回类型为 void

所以getClass方法也被解析成了一个属性PropertyDescriptor
在这里插入图片描述

1.2 根据类型找结果

@Autowired注解也是用的这个方法,非常重要和复杂
这个方法下一节再讲,很复杂!!

2. @Autowired注解注入

注解注入的实现是依赖BeanPostProcessor的扩展机制实现的,即InstantiationAwareBeanPostProcessor

if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}//2.@Autowired注解注入for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {//默认提供的实现里会调用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法直接给对象中的属性赋值//	AutowiredAnnotationBeanPostProcessor内部并不会处理pvs,直接返回了//	AutowiredAnnotationBeanPostProcessor会处理@Autowired、@Value、 @Inject 注解//	CommonAnnotationBeanPostProcessor会处理@Resource注解PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);if (pvsToUse == null) {...}pvs = pvsToUse;}
}

InstantiationAwareBeanPostProcessor的实现中:

  • AutowiredAnnotationBeanPostProcessor会处理@Autowired、@Value、 @Inject 注解
  • CommonAnnotationBeanPostProcessor会处理@Resource注解

我们先分析AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor相对简单,逻辑也和@Autowired的差不多。

AutowiredAnnotationBeanPostProcessor

AutowiredAnnotationBeanPostProcessors实现了两个接口:
在这里插入图片描述

其中SmartInstantiationAwareBeanPostProcessor继承于InstantiationAwareBeanPostProcessor,比它更强大:
在这里插入图片描述


以后讲,先不管。

看到它实现了两个接口:InstantiationAwareBeanPostProcessor(SmartInstantiationAwareBeanPostProcessor),MergedBeanDefinitionPostProcessor

按照Bean的生命周期流程的执行顺序:

  • 我们先看MergedBeanDefinitionPostProcessor.postProcessMergedBeanDefinition方法的实现
  • 再看InstantiationAwareBeanPostProcessor.postProcessProperties方法的实现

在这里插入图片描述

postProcessMergedBeanDefinition:解析注入点并缓存
postProcessProperties:基于注入点属性注入

2.1 解析注入点并缓存

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition

public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);metadata.checkConfigMembers(beanDefinition);
}
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.// 首先快速检查并发map,尽量减少锁的范围。// InjectionMetadata:封装了当前类中所有的注入点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);}//解析注入点并缓存(被@Autowired标记的属性、方法..)metadata = buildAutowiringMetadata(clazz);this.injectionMetadataCache.put(cacheKey, metadata);}}}return metadata;
}

解析注入点:

private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {//a. 判断当前类是否需要查找注入点(包路径是java.开头的类不需要找注入点)//比如如果一个Bean的类型是String...那么则根本不需要进行依赖注入if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {//不是候选类,直接返回return InjectionMetadata.EMPTY;}List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();Class<?> targetClass = clazz;do {final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();//遍历targetClass中所有的fieldReflectionUtils.doWithLocalFields(targetClass, field -> {//b. field上是否存在@Autowired、@Value、@Inject其中的一个MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {//static field不是注入点,不会进行自动注入//e.因为静态属性是属于类的,而不是属于对象的。if (Modifier.isStatic(field.getModifiers())) {if (logger.isInfoEnabled()) {...}return;}//c.判断是否要必须注入,针对@Autowired的required属性。boolean required = determineRequiredStatus(ann);//构造字段注入点currElements.add(new AutowiredFieldElement(field, required));}});//遍历targetClass中所有的MethodReflectionUtils.doWithLocalMethods(targetClass, method -> {//d.找到所提供的桥接方法的原始方法Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);//比较桥接方法和它桥接的方法的特征。如果参数和返回类型相同,则它是Java 6中引入的“可见性”桥接方法if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {//“可见性”桥接方法也会过滤return;}//b. 判断method上是否存在@Autowired、@Value、@Inject其中的一个MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {//e.static method不是注入点,不会进行自动注入if (Modifier.isStatic(method.getModifiers())) {if (logger.isInfoEnabled()) {...}return;}//set方法最好有入参,做个日志提示(没有参数、1个参数、多个参数都可以)//就算@Autowired标记的方法没有入参,Spring也会去执行,只是不会去找参数类型对应的实例if (method.getParameterCount() == 0) {...}//c.判断是否要必须注入,针对@Autowired的required属性。boolean required = determineRequiredStatus(ann);PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);//构造方法注入点currElements.add(new AutowiredMethodElement(method, required, pd));}});elements.addAll(0, currElements);targetClass = targetClass.getSuperclass();}//do while循环,递归处理父类while (targetClass != null && targetClass != Object.class);//将所有注入点整体封装成一个对象返回return InjectionMetadata.forElements(elements, clazz);
}

a. 判断当前类是否需要查找注入点

org.springframework.core.annotation.AnnotationUtils#isCandidateClass(java.lang.Class<?>, java.util.Collection<java.lang.Class<? extends java.lang.annotation.Annotation>>)

autowiredAnnotationTypes的值:
在这里插入图片描述

public static boolean isCandidateClass(Class<?> clazz, Collection<Class<? extends Annotation>> annotationTypes) {//annotationTypes此时就是@Autowired、@Value、@Injectfor (Class<? extends Annotation> annotationType : annotationTypes) {if (isCandidateClass(clazz, annotationType)) {return true;}}return false;
}public static boolean isCandidateClass(Class<?> clazz, Class<? extends Annotation> annotationType) {return isCandidateClass(clazz, annotationType.getName());
}public static boolean isCandidateClass(Class<?> clazz, String annotationName) {//注解名字是java.开头的,代表需要查找注入点if (annotationName.startsWith("java.")) {return true;}//什么情况下不需要找注入点呢?主要看这:if (AnnotationsScanner.hasPlainJavaAnnotationsOnly(clazz)) {return false;}//默认true,大部分情况下类都是要找注入点的return true;
}

org.springframework.core.annotation.AnnotationsScanner#hasPlainJavaAnnotationsOnly(java.lang.Class<?>)

static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {//java.开头的类不需要找注入点return (type.getName().startsWith("java.") || type == Ordered.class);
}

b. 判断field/method上是否存在@Autowired、@Value、@Inject其中的一个

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#findAutowiredAnnotation

private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {//获取指定元素上的所有注解和元注解。(默认不包括任何继承的注解)MergedAnnotations annotations = MergedAnnotations.from(ao);for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {MergedAnnotation<?> annotation = annotations.get(type);if (annotation.isPresent()) {return annotation;}}return null;
}

其中autowiredAnnotationTypes值在构造函数里初始化了:@Autowired、@Value、@Inject
在这里插入图片描述

c. 判断是否要必须注入,针对@Autowired的required属性

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#determineRequiredStatus(org.springframework.core.annotation.MergedAnnotation<?>)

protected boolean determineRequiredStatus(MergedAnnotation<?> ann) {//调用MergedAnnotation.asMap方法,传入lambda表达式的一个对象,生成AnnotationAttributes对象return determineRequiredStatus(ann.<AnnotationAttributes> asMap(mergedAnnotation -> new AnnotationAttributes(mergedAnnotation.getType())));
}protected boolean determineRequiredStatus(AnnotationAttributes ann) {//requiredParameterName="required"//requiredParameterValue=true//判断注解上是否包含required属性,并且是否为truereturn (!ann.containsKey(this.requiredParameterName) ||this.requiredParameterValue == ann.getBoolean(this.requiredParameterName));
}

在这里插入图片描述

d. 找到所提供的桥接方法的原始方法

什么情况下会有桥接方法?

public interface UserInterface<T> {void setOrderService(T t);
}
@Component
public class UserService implements UserInterface<OrderService> {private OrderService orderService;@Override@Autowiredpublic void setOrderService(OrderService orderService) {this.orderService = orderService;}public void test() {System.out.println("test123");}}

此时这段代码应该只有一个注入点,但是我们看下UserService对应的字节码:
在这里插入图片描述

可以看到在UserSerivce的字节码中有两个setOrderService方法:

  1. public setOrderService(Lcom/zhouyu/service/OrderService;)V
  2. public synthetic bridge setOrderService(Ljava/lang/Object;)V

并且都是存在@Autowired注解的。

java字节码层面针对泛型方法,就会特殊处理生成一个synthetic bridge的方法
java泛型,翻译成字节码,底层其实就是一个Object类型。(泛型、桥接方法、泛型擦除)

简单通过反射就会拿到两个方法,所以在Spring中需要处理这种情况,当遍历到桥接方法时,得找到原方法。

e. static的字段或方法为什么不支持

Demo演示:

@Component
@Scope("prototype")
public class OrderService {}
@Component
@Scope("prototype")
public class UserService  {@Autowiredprivate static OrderService orderService;public void test() {System.out.println("test123");}}

看上面代码,UserService和OrderService都是原型Bean,假设Spring支持static字段进行自动注入,那么现在调用两次

  1. UserService userService1 = context.getBean(“userService”)
  2. UserService userService2 = context.getBean(“userService”)

问此时,userService1的orderService值是什么?还是它自己注入的值吗?
答案是不是,一旦userService2 创建好了之后,static orderService字段的值就发生了修改了,从而出现bug。

2.2 基于注入点属性注入

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties

public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//找注入点(所有被@Autowired注解了的Field或Method)//findAutowiringMetadata方法在上一步,BeanDefinition的后置流程中已经执行过了,所以此时直接从缓存拿了InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);try {//注入metadata.inject(bean, beanName, pvs);}catch (BeanCreationException ex) {...}catch (Throwable ex) {...}return pvs;
}

org.springframework.beans.factory.annotation.InjectionMetadata#inject

public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Collection<InjectedElement> checkedElements = this.checkedElements;Collection<InjectedElement> elementsToIterate =(checkedElements != null ? checkedElements : this.injectedElements);if (!elementsToIterate.isEmpty()) {//遍历每个注入点,进行依赖注入for (InjectedElement element : elementsToIterate) {element.inject(target, beanName, pvs);}}
}

方法和字段注入点对应的类型:
在这里插入图片描述

a. 字段注入

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject

    protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {Field field = (Field) this.member;Object value;//缓存,一开始肯定没有缓存if (this.cached) {...}else {//根据field从BeanFactory中查到匹配的Bean对象value = resolveFieldValue(field, bean, beanName);}//反射给field赋值if (value != null) {ReflectionUtils.makeAccessible(field);field.set(bean, value);}}

resolveFieldValue:关于怎么找的,比较复杂,下一节再说。

b.方法注入

org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement#inject

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {//如果pvs中已经有当前注入点的值了,则跳过注入(autowire注入、set方法注入的优先级更高)if (checkPropertySkipping(pvs)) {return;}Method method = (Method) this.member;Object[] arguments;//缓存,一开始肯定没有缓存if (this.cached) {...}else {//根据方法信息找值,@Autowired注解标记的方法允许多个参数//怎么找下一节再说。arguments = resolveMethodArguments(method, bean, beanName);}if (arguments != null) {try {//反射调方法ReflectionUtils.makeAccessible(method);method.invoke(bean, arguments);}catch (InvocationTargetException ex) {...}}
}

3. PropertyValues手动注入

把pvs(PropertyValues属性)里的属性值给bean进行赋值!

  • 如果当前Bean中的BeanDefinition中设置了PropertyValues,那么最终将是PropertyValues中的值,覆盖@Autowired
  • 通过pvs里的属性值给bean进行赋值,需要提供写方法才生效

PropertyValues怎么设置?

  • pvs里的属性值可以利用autowire自动注入的方式收集
  • 也可以手动设置(优先级最高),比如可以通过以下方式设置让属性赋值生效:
    在这里插入图片描述

applyPropertyValues 方法的主要逻辑是遍历 bd.propertyValues 中的 PropertyValue 属性,根据引用类型提取出对象实例,再将这个对象实例转换成可以直接注入的实例。

  1. 解析对象:valueResolver.resolveValueIfNecessary(pv, originalValue) 将 pv.value 解析成实例对象。
  2. 类型转换:convertForProperty(resolvedValue, propertyName, bw, converter) 将 resolvedValue 转换成可直接进行类型注入的类型。
  3. 依赖注入: bw.setPropertyValues(mpvs) 将解析后的属性注入到 bw 实例中
  4. 结果缓存:Spring 会将 valueResolver 和 converter 解析后的最终对象缓存到 pv 中,提高效率。如果全部 pv 都不需要重新解析,则设置 mpvs.converted=true。

org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#applyPropertyValues

protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {if (pvs.isEmpty()) {return;}if (System.getSecurityManager() != null && bw instanceof BeanWrapperImpl) {...}MutablePropertyValues mpvs = null;List<PropertyValue> original;//1.获取List<PropertyValue>,如果已经解析过,则直接注入后返回//通常来说,默认实现就是MutablePropertyValuesif (pvs instanceof MutablePropertyValues) {mpvs = (MutablePropertyValues) pvs;//isConverted:返回该holder是否只包含转换后的值(true),或者值是否仍然需要转换(false)。//MutablePropertyValues已经解析,直接注入,在方法解析后会缓存已经解析的PropertyValueif (mpvs.isConverted()) {// Shortcut: use the pre-converted values as-is.try {// BeanWrapper属性注入bw.setPropertyValues(mpvs);return;}catch (BeansException ex) {...}}original = mpvs.getPropertyValueList();}else {original = Arrays.asList(pvs.getPropertyValues());}//类型转换器TypeConverter converter = getCustomTypeConverter();if (converter == null) {converter = bw;}//BeanDefinitionValueResolver:解析器,用于解析PropertyValue,如间接引用替换成直接对象BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);//2.逐个解析、转换PropertyValue// Create a deep copy, resolving any references for values.// 创建一个深度拷贝,解析值的任何引用。List<PropertyValue> deepCopy = new ArrayList<>(original.size());boolean resolveNecessary = false;for (PropertyValue pv : original) {if (pv.isConverted()) {//已经类型转换过了deepCopy.add(pv);}else {String propertyName = pv.getName();Object originalValue = pv.getValue();//标记位,实际使用resolveDependency方法查找依赖注入的对象if (originalValue == AutowiredPropertyMarker.INSTANCE) {//必须要提供写方法Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();if (writeMethod == null) {throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);}//构建一个属性描述器originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);}//2.1 解析对象Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);//2.2 类型转换Object convertedValue = resolvedValue;//是否可转换//	检查属性是否可写,必须有写方法(setter method)//	检查给定的属性路径是否指示索引或嵌套属性。比如user.name[0],这种就不行boolean convertible = bw.isWritableProperty(propertyName) &&!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);if (convertible) {//转换器转换后的值convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);}//3. 缓存解析后的PropertyValue:resolvedValue -> convertedValue// Possibly store converted value in merged bean definition,// in order to avoid re-conversion for every created bean instance.//3.1 缓存情况1:解析后的对象实例没有被替换(地址匹配):如动态代理等,会直接替换对象。if (resolvedValue == originalValue) {if (convertible) {//可转换的,记录转换后的值pv.setConvertedValue(convertedValue);}deepCopy.add(pv);}//3.2 缓存情况2:如果是可转换的,对象类型是TypedStringValue且不需要动态转换、转换后不是集合或数组//	originalValue如果是TypedStringValue,则类型转换器会将String转换成指定类型targetTypeelse if (convertible && originalValue instanceof TypedStringValue &&!((TypedStringValue) originalValue).isDynamic() &&!(convertedValue instanceof Collection || ObjectUtils.isArray(convertedValue))) {pv.setConvertedValue(convertedValue);deepCopy.add(pv);}//3.3 不缓存:每次都重新解析else {resolveNecessary = true;//最终的值放到deepCopydeepCopy.add(new PropertyValue(pv, convertedValue));}}}//所有的字段都能成功解析,不会再变,才会标记mpvs为转换完成,否则下次还需要动态解析//也可能是mpvs包含的部分字段需要解析if (mpvs != null && !resolveNecessary) {mpvs.setConverted();}// Set our (possibly massaged) deep copy.try {//BeanWrapper属性注入bw.setPropertyValues(new MutablePropertyValues(deepCopy));}catch (BeansException ex) {...}
}

BeanDefinitionValueResolver

BeanDefinitionValueResolver#resolveValueIfNecessary(argName, value) 方法功能:解析 value 的真实类型,value 的类型不同,处理的结果也不同。本质就是进行依赖查找。

  • RuntimeBeanReference 类型:引用类型,根据 ref.beanType 或 ref.beanName 从容器中获取。
  • RuntimeBeanNameReference 类型:Spring EL 表达式解析 ref.beanName。
  • BeanDefinitionHolder 或 BeanDefinition 类型:根据 BeanDefinition 实例化 bean。
  • DependencyDescriptor:采用 beanFactory#resolveDependency 进行依赖查找。
  • ManagedList 等集合类型:规则和上述完全类似,只是返回集合而已。
  • 其它类型:如果是 String,则 Spring EL 表达式解析,其余的直接返回 originalValue。

如 applyPropertyValues 中的 AutowiredPropertyMarker.INSTANCE 类型:表示使用 beanFactory#resolveDependency 进行依赖查找。BeanDefinitionBuilder 添加属性时就会使用时这些类型。
在这里插入图片描述

BeanWrapper属性注入

BeanWrapper:对 Bean 操作的封装,如 JavaBean 的内省,属性的设置。其 bw.setPropertyValues(mpvs) 将属性注入到 bean 实例中。

  • BeanWrapperImpl:(默认)采用 PropertyDescriptor 进行注入,也就是 setter 方法反射注入,对应的处理器为 BeanPropertyHandler。
  • DirectFieldAccessor:采用字段注入,对应的处理器为 FieldPropertyHandler。

核心代码:
org.springframework.beans.BeanWrapperImpl.BeanPropertyHandler#setValue

public void setValue(@Nullable Object value) throws Exception {Method writeMethod = (this.pd instanceof GenericTypeAwarePropertyDescriptor ?((GenericTypeAwarePropertyDescriptor) this.pd).getWriteMethodForActualAccess() :this.pd.getWriteMethod());if (System.getSecurityManager() != null) {...}else {ReflectionUtils.makeAccessible(writeMethod);writeMethod.invoke(getWrappedInstance(), value);}
}

反射set方法赋值。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_24645.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

谷粒商城项目学-分布式基础

项目框架图 分布式基础概念 • 微服务、注册中心、配置中心、远程调用、Feign、网关 • 2、基础开发 • SpringBoot2.0、SpringCloud、Mybatis-Plus、Vue组件化、阿里云对象存储 • 3、环境 • Vagrant、Linux、Docker、MySQL、Redis、逆向工程&人人开源 • 4、开发规范 •…

【LeetCode48:旋转图像(附Java代码)】

旋转图像一、题目描述1.题目内容2.样例二、解决方案1.算法流程1&#xff09;分析2&#xff09;算法流程2.Java代码1&#xff09;核心代码2&#xff09;完整测试代码一、题目描述 1.题目内容 给定一个 n n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。 你必…

metamask api 请求 一般操作

参考文档&#xff1a;https://docs.metamask.io/guide/ 注意 metamask 必须是运行在站点之下的 web 页进行操作。 一、检查 metamask 是否安装 metamask 提供了 window.ethereum 供开发者对 metamask&#xff08;以太坊网络&#xff09; 进行交互&#xff0c;当然是需要你已…

DO、VO、BO、DTO、POJO

DO:Domain Object 即数据库表字段 在Java中一一对应关系(有人称它实体类) BO:Business Object 即业务对象,Service层向上传传输的对象。是多个DO的组合形式 VO:view oject 展示层对象,通过接口向前端输出展示的对象 DTO:Date Transfer Object 数据传输对象,controll…

《Linux下软件的管理》

【一】Linux软件包yum 什么是软件包&#xff1f; 在Linux下安装软件&#xff0c;一个通常的办法就是下载程序的源代码&#xff0c;并经行编译&#xff0c;既可得到可执行程序&#xff0c;但是这种办法属实是太麻烦了&#xff0c;因为下载要时间&#xff0c;编译要时间&#x…

根文件系统简介

根文件系统 根文件系统一般也叫做rootfs&#xff0c;那么什么叫根文件系统&#xff1f;看到“文件系统”这四个字&#xff0c;很多人&#xff0c;第一反应就是FATFS、FAT、EXT4、YAFFS和NTFS等这样的文件系统。在这里&#xff0c;根文件系统并不是FATFS这样的文件系统代码&…

SpringCloudAlibaba 通过Dubbo实现微服务之间的RPC调用

目录 一、创建模块化项目 二、公共api接口模块 三、服务提供者 四、服务调用者 五、测试 六、案例代码 在微服务架构中&#xff0c;微服务之间的调用一般我们有两种比较好的解决策略&#xff0c;分别是通过OpenFeign的基于http协议的传输的调用和基于RCP协议的Dubbo框架来…

基于SSM的餐饮管理系统的设计与实现

目 录 前 言 1 第1章 概述 2 1.1 选题背景及意义 2 1.2 技术概述 2 1.2.1 JSP技术概述 2 1.2.2 SpringSprngMVC介绍 3 1.2.3 MySQL数据库概述 3 1.2.4 Mybatis介绍 3 1.2.5 Maven介绍 3 1.3 开发平台介绍 4 1.3.1 Tomcat服务器 4 1.3.2 Eclipse简介 4 第2章 可行性研究 5 2.1 技…

Redis学习和笔记

Redis学习 作为一个程序员&#xff0c;你没有办法不学Redis redis是一个NoSql的&#xff08;远程字典服务的&#xff0c;key_value的数据库&#xff09; redis 能干嘛 内存存储&#xff0c;持久化&#xff0c;内存中是断电就失去&#xff0c;所有说持久化很重要效率高&#…

Linux Command mount 挂载

Linux Command mount 挂载 tags: 文件管理 文章目录Linux Command mount 挂载1. 简介2. 语法3. 退出状态4. 命令选项5. mount 挂载5.1 列出挂载的文件系统5.2 列出特定文件系统5.3 挂载文件系统5.4 使用 /etc/fstab 挂载文件系统5.5 挂载 USB 驱动器5.6 安装 CD-ROM5.7 挂载 I…

电路方案分析(十二)USB Type-C PD 移动电源参考设计方案

USB Type-C PD 移动电源参考设计方案 tips&#xff1a;TI设计方案参考分析&#xff1a;TI Designs&#xff1a;TIDA-01627 1.系统描述 2.系统概述 3.系统供电方案 4.测试数据 5.设计文件 6.关键术语 说明 此移动电源参考设计提供高度集成的 USB Type-C™电力传输 (PD) 解决…

Docter安装

上传安装包 docker-ce-18.06.0.ce-3.el7.x86_64.rpm 安装 yum install docker-ce-18.06.0.ce-3.el7.x86_64.rpm -y 启动docter systemctl start docker systemctl stop docker systemctl restart docker systemctl status docker&#xff08;查看状态&#xff09; 查看doct…

浮点型在内存中的存储

目录 1、浮点数的存储方式 (1) 转化为二进制 (2) 转化为国际标准形式 (3) 使用国际标准形式存储 (4) 存储方式验证 2、从内存中取出浮点数需满足的规则 (1) E 不全为0 或 不全为1 (2) E 全为 0 (3) E 全为 1 浮点数在内存中存储的方式和整型不一样。所以我们在存储的…

2022/10语音识别大作业:基于HMM(隐马尔可夫模型)的Matlab孤立数字语音识别

别看了你要找的就在这。csdn上所有这方面的资源都是收费的&#xff0c;而且没有直接能用的好的&#xff0c;我的也是基于重金买来的两份结合起来做了三天的大修之后才能运行。所以这也不是一份免费分享。但是本文解决了其他资源没有解决的问题&#xff0c;所以50是一个公道的价…

C++——程序员的逼格神器-github

github的重要性&#xff1a; 网络时代的程序员必备。 github的作用&#xff1a; 版本管理多人协作开源共享 常用方案&#xff1a; gitTortoiseGitgithub [Tortoise&#xff0c;程序员常称其为小乌龟&#xff0c;小海龟] 安装配置步骤 1.注册 GitHub: Where the world bui…

JVM之对象的内存模型、创建过程、对象引用、生命周期

JVM之对象的内存模型、创建过程、对象引用、生命周期Java对象内存模型对象头实例数据对齐填充部分对象的创建类加载检查分配内存初始化零值设置对象头执行init方法引用计数法对象的引用强引用软引用弱引用虚引用对象的生命周期创建阶段(Created)应用阶段(In Use)不可见阶段(Inv…

代理ARP (路由式代理ARP+vlan内代理ARP+vlan间代理ARP) [理论+实验验证]

衷心感谢三位大佬的博客 ! ! ! ! 这篇博客主要是为了记录笔记方便查看而整理&#xff0c; 主要内容整理来源&#xff1a; (58条消息) 代理ARP实验_在下小黄的博客-CSDN博客_arp代理实验 (58条消息) 代理ARP_士别三日wyx的博客-CSDN博客_arp代理 (59条消息) 华为ARP代理的三种方…

字节在职三年,如何想要三个月内将软件测试学好,我建议你这样学

目录 13年本科毕业&#xff0c;目前已经工作将近7年时间&#xff0c;第一段工作是在字节工作3年时间&#xff0c;目前是再另外一家大厂工作。今天跟大家分享一下我工作的心得&#xff0c;希望对你有所帮助 我对软件测试的理解 软件测试是软件开发的最后一道防线&#xff0c;…

【Vue 快速入门系列】样式绑定与条件渲染

文章目录前言样式绑定条件渲染前言 在vue中好像一切数据都是可以动态的&#xff0c;那么我们应如何让dom元素中的样式动起来呢&#xff1f;我们既然可以改变dom元素的样式&#xff0c;我们能不能将其隐藏起来呢&#xff1f;今天将会介绍到Vue中如何将属性与dom元素的样式进行绑…

Java List 扩容机制探究(ArrayList 、Vector、LinkedList)

文章目录List扩容ArrayList 扩容机制结论&#xff1a;无参构造创建的ArrayList的初始空间为0&#xff0c;在添加第一个元素的时候空间会默认为10&#xff0c;之后扩容会为当前容量的1.5倍。0->10->15->22->33->49源码分析1.ArrayList list new ArrayList();2. …