一、前言
这是我Spring专栏的第十篇文章: Spring源码分析之依赖注入(二), 主要讲解了在依赖注入过程中, @Autowired等注解方法注入的源码解析 在看本篇文章之前建议先从本系列的第一篇文章看起 Spring之手写模拟bean的创建流程
二、方法的注入
我们上一篇文章最后讲到了方法的注入, 保留了一个重要方法没有进行讲解, 具体如下图所示
网络异常,图片无法展示
|
网络异常,图片无法展示
|
网络异常,图片无法展示
|
网络异常,图片无法展示
|
网络异常,图片无法展示
|
网络异常,图片无法展示
|
该方法简单流程说明:
- 获取方法入参名字
- 通过java反射获取的, 该方法只做了这一件事
- 判断参数的类型(大多数情况下直接进入 else中)
- else
- 判断方法或属性上有没有使用 @Lazy注解
三、如果有 @Lazy注解
如果有 @Lazy注解则会进入以下方法
网络异常,图片无法展示
|
网络异常,图片无法展示
|
网络异常,图片无法展示
|
假设存在 @Lazy注解, 那么通过三元运算符会进入到 buildLazyResolutionProxy方法中, 这个方法内部主要是和 AOP相关, 后续我们会出专门的文章进行讲解, 目前暂时知道它会产生一个代理对象就可以了
网络异常,图片无法展示
|
简单流程说明:
- 最开始为属性赋值, 但是因为属性是被 @Lazy注解修饰的, 所以被赋的值是一个 代理对象
- 当真正的去执行这个 代理对象的某个方法的时候
- 才会根据 这个代理对象字段的信息去 BeanFactory中找对应的 bean对象
- 再去执行 bean对象对应的方法
四、如果没有 @Lazy注解
我们回到之前的方法中, 如果没有 @Lazy注解, 那么就会进入到下面的这个方法中
网络异常,图片无法展示
|
doResolveDependency方法是非常核心的
@Nullable public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor); try { // 如果当前descriptor之前做过依赖注入了,则可以直接取shortcut了,相当于缓存 Object shortcut = descriptor.resolveShortcut(this); if (shortcut != null) { return shortcut; } Class<?> type = descriptor.getDependencyType(); // 获取@Value所指定的值 Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor); if (value != null) { if (value instanceof String) { // 占位符填充(${}) String strVal = resolveEmbeddedValue((String) value); BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null); // 解析Spring表达式(#{}) value = evaluateBeanDefinitionString(strVal, bd); } // 将value转化为descriptor所对应的类型 TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter()); try { return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor()); } catch (UnsupportedOperationException ex) { // A custom TypeConverter which does not support TypeDescriptor resolution... return (descriptor.getField() != null ? converter.convertIfNecessary(value, type, descriptor.getField()) : converter.convertIfNecessary(value, type, descriptor.getMethodParameter())); } } // 如果descriptor所对应的类型是数组、Map这些,就将descriptor对应的类型所匹配的所有bean方法,不用进一步做筛选了 Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // 找到所有Bean,key是beanName, value有可能是bean对象,有可能是beanClass Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { // required为true,抛异常 if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; } String autowiredBeanName; Object instanceCandidate; if (matchingBeans.size() > 1) { // 根据类型找到了多个Bean,进一步筛选出某一个, @Primary-->优先级最高--->name autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesMultipleBeans(type)) { return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans); } else { // In case of an optional Collection/Map, silently ignore a non-unique case: // possibly it was meant to be an empty collection of multiple regular beans // (before 4.3 in particular when we didn't even look for collection beans). return null; } } instanceCandidate = matchingBeans.get(autowiredBeanName); } else { // We have exactly one match. Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); } // 记录匹配过的beanName if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } // 有可能筛选出来的是某个bean的类型,此处就进行实例化,调用getBean if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } Object result = instanceCandidate; if (result instanceof NullBean) { if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } result = null; } if (!ClassUtils.isAssignableValue(type, result)) { throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass()); } return result; } finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint); } } 复制代码
resolveMultipleBeans方法
我们看一下 resolveMultipleBeans详情
网络异常,图片无法展示
|
可以看到, 他会根据你属性注入的类型不同来进行不同的操作, 会去直接匹配对应的 bean方法,不在进行进一步的筛选了
网络异常,图片无法展示
|
网络异常,图片无法展示
|
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType, new MultiElementDescriptor(descriptor)); 复制代码
然后去判断 如果没有找到 Bean则抛出异常
核心的findAutowireCandidates方法
流程信息
- 找出BeanFactory中类型为type的所有的Bean的名字,注意是名字,而不是Bean对象,因为我们可以根据BeanDefinition就能判断和当前type是不是匹配,不用生成Bean对象
- 把resolvableDependencies中key为type的对象找出来并添加到result中
- 遍历根据type找出的beanName,判断当前beanName对应的Bean是不是能够被自动注入
- 先判断beanName对应的BeanDefinition中的autowireCandidate属性,如果为false,表示不能用来进行自动注入,如果为true则继续进行判断
- 判断当前type是不是泛型,如果是泛型是会把容器中所有的beanName找出来的,如果是这种情况,那么在这一步中就要获取到泛型的真正类型,然后进行匹配,如果当前beanName和当前泛型对应的真实类型匹配,那么则继续判断
- 如果当前DependencyDescriptor上存在@Qualifier注解,那么则要判断当前beanName上是否定义了Qualifier,并且是否和当前DependencyDescriptor上的Qualifier相等,相等则匹配
- 经过上述验证之后,当前beanName才能成为一个可注入的,添加到result中
源码讲解
我们进入这个方法, 里面的注释是比较清楚的, 接下来主要是针对一些方法的讲解
网络异常,图片无法展示
|
网络异常,图片无法展示
|
beanNamesForTypeIncludingAncestors方法
- 先根据自己的类型去 BeanFactory中找 bean的名字
- 如果有 父BeanFactory, 就去 父BeanFactory中找
- 然后将两个集合合并起来返回
网络异常,图片无法展示
|