主要讲解了在依赖注入过程中, @Autowired等注解方法注入的源码解析
我们上一篇文章最后讲到了方法的注入, 保留了一个重要方法没有进行讲解, 具体如下图所示
我们点进这个方法, 具体如下图所示, 接下来我就开始为大家讲解这个方法具体的内容
下图红框部分是获取当前注入方法的入参, 因为一个方法可能有多个入参, 所以用数组接收,
然后去遍历这个数组, 分别的根据这几个参数的信息分别去 BeanFactory中找到对应的 bean
在这个遍历循环的过程当中有一个方法是很重要的, 接下来我带大家看一下这个方法的内部实现
在上图这个方法中, 入参的 DependencyDescriptor descriptor需要注意一下, 因为这个参数可以是字段或者方法参数, 但是我们去获取这个参数的信息, 只会获取其名字和类型
该方法简单流程说明:
如果有 @Lazy注解则会进入以下方法
在 IsLazy方法中, 他会先去判断你的属性有没有 @Lazy注解, 再去判断方法的参数有没有使用 @Lazy注解
假设存在 @Lazy注解, 那么通过三元运算符会进入到 buildLazyResolutionProxy方法中, 这个方法内部主要是和 AOP相关, 后续我们会出专门的文章进行讲解, 目前暂时知道它会产生一个代理对象就可以了
简单流程说明:
我们回到之前的方法中, 如果没有 @Lazy注解, 那么就会进入到下面的这个方法中
doResolveDependency方法是非常核心的
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set 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 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 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详情
可以看到, 他会根据你属性注入的类型不同来进行不同的操作, 会去直接匹配对应的 bean方法,不在进行进一步地筛选了
例如当我们属性注入的类型为 Map的时候, 它会强制要求key为String类型, 并去寻找相应的 bean
具体的如下所示, 他会根据 bean的类型去找 bean的名字
Map matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor)); 然后去判断 如果没有找到 Bean则抛出异常
我们进入这个方法, 里面的注释是比较清楚的, 接下来主要是针对一些方法的讲解
我们进入 getBeanNamesForType方法, 具体如下图所示
这个方法太长了, 而且我看着真的蒙, 简单讲一下流程, 感兴趣的话大家自己看一下:
我们回到本方法的开头, 只要知道这个方法是从 BeanFactory中找出和 requiredType所匹配的 beanName, 仅仅是 beanName, 这些 bean不一定经过了实例化, 只有到最终确定某个 Bean了, 如果这个Bean还没有实例化才会进行实例化
在 Spring启动的时候就会忘这个 map中存东西,
这个 map具体的存储过程如下图所示: 后续讲Spring启动源码的时候会讲
然后去遍历这个 map, 获取到 key也就是 Bean类型, 判断有没有相同的 Bean类型, 如果有就把对应的对象加入到我们的返回数组中
然后去判断 如果没有找到 Bean则抛出异常
如图所示, 如果根据 beanName找到了多个 Bean那么该 if判断则为 true
在这个方法中, 我们先去获取他的类型, 获取类型之后执行 determinePrimaryCandidate方法, 下图是这个方法的详情
上图中的方法经历了以下几个步骤:
方法结束, 返回上一层 determineAutowireCandidate方法
途中红框部分的方法讲解完毕, 接下来它去寻找了我们的返回值, 如果都没有实现 @Primary注解, 那么继续往下走
方法流程如下:
@Priority 该注解不能使用在方法上, 只能使用在类上面
@Order在依赖注入中是没有去使用判断的
方法结束, 返回上一层 determineAutowireCandidate方法
如上图所示, 我们继续往下走, 最后才是根据名字去判断 bean对象的
通过源码可以看到 @Resource 和 @Autowired的区别 如果有多个同名beanName, 那么@Autowired 会先去寻找有没有哪个 bean是有 @Primary注解的, 如果都没有, 则去寻找有没有哪个类上是有 @Priority优先级注解的, 如果都没有则会去按照名称查找 这个面试题在刚毕业的时候也是经常被问到的, 以前只知道答案, 这次通过源码对其的解答也更加清晰明了了
接下来返回到下面红框的位置, 继续玩下走
如果没有找到对象, required == true抛出异常, 如果不为 true则返回 null, 然后赋值
那么直接为之前定义的 autowiredBeanName 和 instanceCandidate进行赋值
如果找到了Bean , 则进行记录
如果是一个类, 那么获取这个类的 bean
NullBean的定义代码如下所示, 当以下面的方式定义一个 bean的时候, 这个bean存在 map中的 key为 JuejinService, value为 NullBean
@Bean
public JuejinService juejinService(){
return null;
}相关判断代码如下所示
最后红框判断的是期望类型和实际获取到的类型是否一致问题, 就不详细解释了
| 留言与评论(共有 0 条评论) “” |