文章目录
- 前言
- 一、applyMergedBeanDefinitionPostProcessors
- 1.1、findAutowiringMetadata
- 二、postProcessProperties
- 2.1、postProcessProperties
- 2.2.1、AutowiredFieldElement
- 2.2.2、AutowiredMethodElement
- 总结
前言
在Spring中,进行依赖注入最常见的方式是@AutoWired
和@Resource
。其中@Autowired
默认按类型(byType)查找,如果找到多个匹配的Bean,则按名称(byName)查找。而@Resource
是先根据名称查找,如果(根据名称)查找不到,再根据类型进行查找。
@AutoWired
在源码中的体现,主要在于:
在实例化后,依赖注入前预先寻找注入点
在实例化后,初始化前,进行注入
一、applyMergedBeanDefinitionPostProcessors
applyMergedBeanDefinitionPostProcessors
方法的主要作用是寻找注入点,即哪些方法或者字段上加入了@AutoWired
、@Resource
等注解:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {//getBeanPostProcessorCache().mergedDefinition 主要有//1.CommonAnnotationBeanPostProcessor 寻找@Resource的注入点//2.AutowiredAnnotationBeanPostProcess 寻找@AutoWired的注入点for (MergedBeanDefinitionPostProcessor processor : getBeanPostProcessorCache().mergedDefinition) {processor.postProcessMergedBeanDefinition(mbd, beanType, beanName);}}@Overridepublic void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {//1.1、findAutowiringMetadata 找@AutoWired注入点InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);//判断成员是否已经注册,从而避免重复注册同一个成员metadata.checkConfigMembers(beanDefinition);}
1.1、findAutowiringMetadata
在findAutowiringMetadata
方法中,主要是根据当前bean的字节码文件,去找到注入点。而buildAutowiringMetadata
是核心方法。主要是收集当前bean中所有加上了@AutoWired
注解的属性或者方法,如果存在继承的关系,会从子类一直找到父类
同时,@AutoWired
不支持在静态属性或者方法上进行注入。因为被static关键字修饰的属性或方法,是属于类而不是某个对象的。如果进行注入,在多例bean获取注入的属性的值的时候可能会存在问题。
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {//首先得到bean的名称 作为缓存主键String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());//去缓存池中查找,第一次肯定查找不到InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);//这里运用了双检锁模式,用于检查目标bean是否发生改变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;}private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {// 检查类是否是一个候选类,是否包含@Autowired等注解,如果不包含,则直接返回空的InjectionMetadataif (!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<>();//扫描当前类的所有字段,查找是否有@Autowired注解ReflectionUtils.doWithLocalFields(targetClass, field -> {MergedAnnotation<?> ann = findAutowiredAnnotation(field);if (ann != null) {//如果是静态字段,跳过(不支持在静态字段上使用@Autowired注解)if (Modifier.isStatic(field.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static fields: " + field);}return;}//获取@Autowired注解的required属性值boolean required = determineRequiredStatus(ann);//创建AutowireFieldElement对象并加入到当前元素集合currElements.add(new AutowiredFieldElement(field, required));}});//扫描当前类的所有方法,查找是否有@Autowired注解ReflectionUtils.doWithLocalMethods(targetClass, method -> {//查找方法的桥接方法(处理Java泛型问题)Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {return;}//查找方法上的@Autowired注解MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);//如果是静态方法,跳过(不支持在静态方法上使用@Autowired注解)if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {if (Modifier.isStatic(method.getModifiers())) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation is not supported on static methods: " + method);}return;}//如果方法没有参数,跳过(@Autowired只能用于带参数的方法)if (method.getParameterCount() == 0) {if (logger.isInfoEnabled()) {logger.info("Autowired annotation should only be used on methods with parameters: " +method);}}// 获取@Autowired注解的required属性值boolean required = determineRequiredStatus(ann);// 获取当前方法对应的属性描述符(用于方法的反射操作)PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);//创建AutowireMethodElement对象并加入到当前元素集合currElements.add(new AutowiredMethodElement(method, required, pd));}});//将当前类的所有注入元素添加到总集合中(按继承顺序,从子类到父类依次添加)elements.addAll(0, currElements);//向上遍历类的继承体系targetClass = targetClass.getSuperclass();}//遍历到Object类时结束while (targetClass != null && targetClass != Object.class);//返回包含所有注入元素的注入元数据return InjectionMetadata.forElements(elements, clazz);}
最终找到的注入点,会被缓存到
injectionMetadataCache
中。
二、postProcessProperties
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);PropertyDescriptor[] filteredPds = null;if (hasInstAwareBpps) {if (pvs == null) {pvs = mbd.getPropertyValues();}//遍历所有的 InstantiationAwareBeanPostProcessor 后处理器for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {//让每个后处理器处理属性值 这里看的是AutowiredAnnotationBeanPostProcess //2.1、postProcessPropertiesPropertyValues 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);}
2.1、postProcessProperties
本篇中调用的是AutowiredAnnotationBeanPostProcess
处理器中的postProcessProperties,专门用于处理@AutoWired
注解
@Overridepublic PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {//找到1.1、findAutowiringMetadata 中,bean实例化之前存入injectionMetadataCache缓存的注入点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;}/*** 对于每一个属性/方法进行注入操作**/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);}}}
inject方法有字段和属性注入的实现
2.2.1、AutowiredFieldElement
AutowiredFieldElement
是@AutoWired
属性注入的实现:
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {//得到对应的属性Field field = (Field) this.member;Object value;if (this.cached) {try {value = resolvedCachedArgument(beanName, this.cachedFieldValue);}catch (NoSuchBeanDefinitionException ex) {// Unexpected removal of target bean for cached argument -> re-resolvevalue = resolveFieldValue(field, bean, beanName);}}else {value = resolveFieldValue(field, bean, beanName);}if (value != null) {ReflectionUtils.makeAccessible(field);//通过反射给属性赋值// @Autowired// private OrderService orderService;field.set(bean, value);}}
在resolveFieldValue
方法中,主要是解析属性,尝试从 Spring 容器中查找合适的 bean,并返回该字段的依赖对象(value):
- 如果依赖解析成功且该字段是必需的(或解析结果不为空),则将依赖值 value 缓存起来,避免后续重复解析。
- 如果自动注入的 Bean 只有一个且其类型与字段类型匹配,Spring 会为这个字段创建一个 ShortcutDependencyDescriptor,这个描述符会优化依赖注入的过程,减少重复的依赖解析。
@Nullableprivate Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {//创建一个 DependencyDescriptor 实例,描述该字段的依赖信息DependencyDescriptor desc = new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());Set<String> autowiredBeanNames = new LinkedHashSet<>(1);Assert.state(beanFactory != null, "No BeanFactory available");// 获取 TypeConverter 实例,用于后续的类型转换TypeConverter typeConverter = beanFactory.getTypeConverter();Object value;try {//解析该字段的依赖,并将解析出来的值赋给 valuevalue = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);}catch (BeansException ex) {throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);}synchronized (this) {//如果字段值尚未被缓存,则进行缓存操作if (!this.cached) {Object cachedFieldValue = null;//如果解析到的值不为空,或者@AutoWired的require属性为true,则进行缓存if (value != null || this.required) {cachedFieldValue = desc;//注册字段的依赖关系registerDependentBeans(beanName, autowiredBeanNames);//如果只找到一个自动注入的 Bean 且类型匹配,则进行快捷缓存//如果 autowiredBeanNames 中只包含一个 Bean 且类型匹配,则认为可以直接通过该 Bean 快捷获取依赖。if (autowiredBeanNames.size() == 1) {String autowiredBeanName = autowiredBeanNames.iterator().next();//创建一个 ShortcutDependencyDescriptor 来存储该依赖的简化描述if (beanFactory.containsBean(autowiredBeanName) &&beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {cachedFieldValue = new ShortcutDependencyDescriptor(desc, autowiredBeanName, field.getType());}}}this.cachedFieldValue = cachedFieldValue;this.cached = true;}}//返回解析到的字段值return value;}
}
2.2.2、AutowiredMethodElement
AutowiredMethodElement
是@AutoWired
方法注入的实现:
和属性注入类似,但是区别在于判断了
checkPropertySkipping
,如果PropertyValues 中包含了即将被注入的属性或者方法,就会跳过,因为最终会按照PropertyValues中定义的属性为准,在这一步注入的会被覆盖。
@Overrideprotected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {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-resolvearguments = 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();}}}
而在resolveMethodArguments
方法中:
@Nullable
private Object[] resolveMethodArguments(Method method, Object bean, @Nullable String beanName) {// 获取方法的参数数量int argumentCount = method.getParameterCount();// 创建一个 Object 数组用于存放方法参数的实际值Object[] arguments = new Object[argumentCount];// 创建一个 DependencyDescriptor 数组,用于存放每个参数的依赖描述符DependencyDescriptor[] descriptors = new DependencyDescriptor[argumentCount];// 创建一个 Set 用于存放所有自动注入的 Bean 名称Set<String> autowiredBeans = new LinkedHashSet<>(argumentCount);Assert.state(beanFactory != null, "No BeanFactory available");// 获取 TypeConverter,用于转换参数类型TypeConverter typeConverter = beanFactory.getTypeConverter();// 遍历方法的所有参数for (int i = 0; i < arguments.length; i++) {// 创建一个 MethodParameter 对象,代表当前方法的参数MethodParameter methodParam = new MethodParameter(method, i);// 创建当前参数的 DependencyDescriptor,表示当前参数的依赖信息DependencyDescriptor currDesc = new DependencyDescriptor(methodParam, this.required);// 设置包含类为当前 bean 的类,以便在依赖解析时知道在哪个类中查找依赖currDesc.setContainingClass(bean.getClass());// 将 DependencyDescriptor 存入 descriptors 数组descriptors[i] = currDesc;try {// 使用 beanFactory 来解析当前参数的依赖Object arg = beanFactory.resolveDependency(currDesc, beanName, autowiredBeans, typeConverter);// 如果参数为空且不是必需的,则跳过该参数if (arg == null && !this.required) {arguments = null; // 将 arguments 设置为 nullbreak; // 退出循环,表示参数注入失败}// 将解析得到的参数值存入 arguments 数组arguments[i] = arg;}catch (BeansException ex) {// 如果解析依赖失败,抛出 UnsatisfiedDependencyException 异常throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(methodParam), ex);}}// 对方法参数进行缓存,确保重复调用时不再重复解析synchronized (this) {// 如果参数还没有被缓存if (!this.cached) {// 如果有解析得到的参数,则开始缓存if (arguments != null) {// 将 DependencyDescriptor 数组复制到缓存数组中DependencyDescriptor[] cachedMethodArguments = Arrays.copyOf(descriptors, arguments.length);// 注册所有依赖的 BeanregisterDependentBeans(beanName, autowiredBeans);// 如果所有参数都有对应的 Bean,进一步进行优化if (autowiredBeans.size() == argumentCount) {// 遍历所有自动注入的 BeanIterator<String> it = autowiredBeans.iterator();Class<?>[] paramTypes = method.getParameterTypes(); // 获取方法的参数类型// 为每个参数匹配一个自动注入的 Beanfor (int i = 0; i < paramTypes.length; i++) {String autowiredBeanName = it.next();// 检查容器中是否包含该 Bean 并且类型匹配if (beanFactory.containsBean(autowiredBeanName) &&beanFactory.isTypeMatch(autowiredBeanName, paramTypes[i])) {// 为参数创建一个缓存的依赖描述符,避免重复解析cachedMethodArguments[i] = new ShortcutDependencyDescriptor(descriptors[i], autowiredBeanName, paramTypes[i]);}}}// 将缓存的参数描述符存储在字段中this.cachedMethodArguments = cachedMethodArguments;}else {// 如果没有解析到任何参数值,则将缓存设置为 nullthis.cachedMethodArguments = null;}// 标记参数已被缓存this.cached = true;}}// 返回解析后的参数值return arguments;
}
无论是AutowiredMethodElement
还是AutowiredFieldElement
,或者前篇中的autowiredbyName
、autowiredbyType
方法,最终都会去调用doResolveDependency
方法。该方法的逻辑较为复杂,单独开一篇说明。
总结
@Autowired:
- Spring 在实例化后,初始化前,扫描标记了该注解的属性或者方法,作为注入点缓存。
- Spring 在实例化后,初始化前,遍历缓存,根据 @Autowired 注解去查找合适的依赖,使用反射将依赖注入到被注解的字段、方法或构造器上。
- 如果是字段注入,Spring 会在实例化过程中使用 AutowiredFieldElement 来处理;如果是方法注入,则使用 AutowiredMethodElement 来处理。
而@Bean(autowired = BY_TYPE) 或 @Bean(autowired = BY_NAME):
- 在属性填充时,根据Name或者Type去容器中找对应的bean,并将其记录
- 最终通过
applyPropertyValues
方法将这些依赖注入到 bean 的属性中。