Spring中到底有几种依赖注入的方式?
首先分两种:
- 手动注入
- 自动注入
手动注入
在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>
上面这种底层是通过构造方法进行注入。
所以手动注入的底层也就是分为两种:
- set方法注入
- 构造方法注入
自动注入
自动注入也分为两种:
- XML的autowire自动注入
- @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);
}
什么样的属性能进行自动注入?
- 该属性有对应的set方法 pd.getWriteMethod() != null
- 该属性类型没有在ignoredDependencyTypes中
- 如果该属性对应的set方法是实现的某个接口中所定义的,那么接口没有在ignoredDependencyInterfaces中
- getPropertyValues中不能包含该属性 !pvs.contains(pd.getName())
- 属性类型不是简单类型,比如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方法:
- public setOrderService(Lcom/zhouyu/service/OrderService;)V
- 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字段进行自动注入,那么现在调用两次
- UserService userService1 = context.getBean(“userService”)
- 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 属性,根据引用类型提取出对象实例,再将这个对象实例转换成可以直接注入的实例。
- 解析对象:valueResolver.resolveValueIfNecessary(pv, originalValue) 将 pv.value 解析成实例对象。
- 类型转换:convertForProperty(resolvedValue, propertyName, bw, converter) 将 resolvedValue 转换成可直接进行类型注入的类型。
- 依赖注入: bw.setPropertyValues(mpvs) 将解析后的属性注入到 bw 实例中
- 结果缓存: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方法赋值。