下面会通过源码的方式去分析Spring中的依赖注入过程。
Spring的注入流程大致如下:
Spring注入过程
Spring注入主要分为了上面4个步骤:
- 1. 第一步主要就是不同注入方式的展现,不同的注入方式对应的入口不同,下面会具体讲解
- 2. 第二步主要是对注入对象的包装,比如可以使用
Optional
、ObjectFactory
、ObjectProvider
等对象包装要注入的对象
image-20230325112747597
- 1. 第三步就是从IOC容器通过注入的类型或者名称找到注入的的对象,当然这个过程可以在IOC中找到多个对象,这时候就需要通过注入对象的类型来组装返回结果,如果是集合类型则都返回,如果是单个对象则返回被
@Primary
修饰的对象。 - 2. 第四步就是将组装好的对象通过反射赋值到需要注入的对象身上
首先说明:阅读源码并不需要关注到每一个方法的功能上,所以下面我只展示出重要的方法
依赖处理过程
在上面注入过程中,第一步存在不同的注入方法,各种注入方法的实现也不尽相同,只有二、三步查找的方法都是统一的,所以在这里我们先来分析第二步第三步的过程。
我们知道,在Spring的默认实现中,不管你是使用ClassPathXmlApplicationContext
创建的Spring上下文还是使用AnnotationConfigApplicationContext
创建的上下文,其实最终的Spring中的BeanFactory类型都是DefaultListableBeanFactory
,所以其实Spring中依赖处理过程的代码也是存在于在DefaultListableBeanFactory
对象doResolveDependency
方法上面。
处理入口
doResolveDependency
方法是AutowireCapableBeanFactory
接口中定义的方法,存在两个:
image-20230325114925282
而两个参数的重载方法在AbstractAutowireCapableBeanFactory
中调用了四个参数的重载方法,所以依赖处理过程都是在四个参数的doResolveDependency
中进行的:
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName) throws BeansException {
// 调用了四个参数的重载方法
return resolveDependency(descriptor, requestingBeanName, null, null);
}
在四个参数方法中主要有对象参数:DependencyDescriptor
和TypeConverter
TypeConverter
主要用于类型转换,这里我们可以先不看,我们主要看一下DependencyDescriptor
对象,DependencyDescriptor
主要描述了被注入对象的一些详细信息。他主要包含了以下字段:
public class DependencyDescriptor extends InjectionPoint implements Serializable {
// 被注入的容器
private final Class<?> declaringClass;
// 方法名称 - 方法注入
@Nullable
private String methodName;
// 构造器参数 - 构造器注入
@Nullable
private Class<?>[] parameterTypes;
// 参数索引 - 参数在构造器中的顺序,也就是标注在那个参数来操作
private int parameterIndex;
// 字段名称 - 字段注入
@Nullable
private String fieldName;
// 是否必须 - 如对应 @Autowired 注解中的required
private final boolean required;
// 是否懒加载 - 如对应 @Lazy 注解标注
private final boolean eager;
// 嵌套层次 - 如 @Autowired 标注在嵌套类中
private int nestingLevel = 1;
// 包含的类
@Nullable
private Class<?> containingClass;
@Nullable
private transient volatile ResolvableType resolvableType;
@Nullable
private transient volatile TypeDescriptor typeDescriptor;
// ... 省略其他
}
public class InjectionPoint {
// 方法参数
@Nullable
protected MethodParameter methodParameter;
// 注入对象类型
@Nullable
protected Field field;
// 字段注解
@Nullable
private volatile Annotation[] fieldAnnotations;
}
从中可以看出DependencyDescriptor
核心就是描述了如下几个注入对象的特征:
- • 被注入的容器 - 注入对象所属的外层容器
- • 注入方式 - 方法注入、构造器注入还是字段注入
- • 是否可以为空
- • 是否是懒加载
- • 注入对象的层级
接下来,我们进入resolveDependency
方法一探究竟!
包装注入对象
这个步骤对应的是上面流程中的第二步,主要作用就是判断注入对象是否被
Optional
、ObjectFactory
、ObjectProvider
等对象进行包装,如果被包装过则从包装中取出实际的注入类型进行注入流程。
我们透过代码来看看:
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 判断注入的类型是否是Optional
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
// 判断注入类型是否是ObjectFactory和ObjectProvider
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
// javaxInjectProviderClass在构造器中声明是javax.inject.Provider对象
else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
}
else {
// 判断对象是否被@Lazy修饰,是则返回代理对象
Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
descriptor, requestingBeanName);
if (result == null) {
// 都不是说明本身就是要注入的类型,开始查找并组装对象 最核心
result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
}
return result;
}
}
上面代码其实非常简单,其实就是不同类型走不同的判断,在上面代码中,其实最核心的就是最后的if中执行的方法doResolveDependency
方法,他是DefaultListableBeanFactory
自己的一个方法。其实上面的几个判断最终都要走到改方法中去,只是上面会对改方法进行包装或者代理。
查找组装注入对象
从上面我们看的,注入不同的类型走不同的方法,下面我们就不每种方法就点进去讲解了,我们主要看核心方法注入普通一个对象的方式,也就是doResolveDependency
方法中执行的内容。
- • doResolveDependency:
@Nullable
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// ...
Class<?> type = descriptor.getDependencyType();
// 1、对@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);
value = evaluateBeanDefinitionString(strVal, bd);
}
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()));
}
}
// ...
// 2、判断查找对象的方式是否是数据或集合等多个的形式
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 3、重点 依赖查找 beanName:需要被注入到的Bean名称 type:注入的bean类型
// 返回多个,因为上下文type相同的Bean可能会存在多个 key为bean名称
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
// 4.1、如果是多个Bean的情况下返回被primary标注或者标注为最高优先级的Bean名称
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
// 取出对应bean名称的class
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// 4.2、如果只有一个则直接取出
Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
autowiredBeanName = entry.getKey();
instanceCandidate = entry.getValue();
}
if (autowiredBeanNames != null) {
autowiredBeanNames.add(autowiredBeanName);
}
if (instanceCandidate instanceof Class) {
// 5、从IOC容器中取出对象,实际执行 beanFactory.getBean(beanName);
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
// ...
return result;
}
- • resolveMultipleBeans: 多对象注入处理
该注入方式代码很清晰,其实也是调用的findAutowireCandidates
方法
@Nullable
private Object resolveMultipleBeans(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) {
Class<?> type = descriptor.getDependencyType();
// 1、StreamDependencyDescriptor类型
if (descriptor instanceof StreamDependencyDescriptor) {
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// ...
return stream;
}
// 2、数组类型
else if (type.isArray()) {
// ...
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, componentType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// ...
return result;
}
// 3、集合类型
else if (Collection.class.isAssignableFrom(type) && type.isInterface()) {
// ...
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, elementType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
// ...
return result;
}
// 4、Map类型
else if (Map.class == type) {
// ...
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, valueType,
new MultiElementDescriptor(descriptor));
if (matchingBeans.isEmpty()) {
return null;
}
if (autowiredBeanNames != null) {
autowiredBeanNames.addAll(matchingBeans.keySet());
}
return matchingBeans;
}
else {
// 5、都不是返回null
return null;
}
}
- • findAutowireCandidates: 查找依赖注入的核心
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 1、返回当前上下文对象中类型为requiredType的所有bean名称
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
// 2、resolvableDependencies是未加入容器管理的一种对象,该种对象可以被依赖注入,却不能被getBean()获取(非 Spring 容器管理对象)
for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
Class<?> autowiringType = classObjectEntry.getKey();
if (autowiringType.isAssignableFrom(requiredType)) {
Object autowiringValue = classObjectEntry.getValue();
autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);
if (requiredType.isInstance(autowiringValue)) {
result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
break;
}
}
}
// 3、下面代码都是为了通过名称和类型到上下文中查找到对应的对象并添加到result中
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty()) {
boolean multiple = indicatesMultipleBeans(requiredType);
// Consider fallback matches if the first pass failed to find anything...
DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
for (String candidate : candidateNames) {
if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
if (result.isEmpty() && !multiple) {
// Consider self references as a final pass...
// but in the case of a dependency collection, not the very same bean itself.
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
依赖注入过程中对象查找的简单过程大致就是上面的流程,其中核心的第三步涉及一个注入来源查找,从代码我们也可以简单分析出,在注入过程的查找来源主要有三个部分:
- • @Value的外部化配置;
- • 被Spring容器管理的对象;
- • 没有被Spring容器管理的ResolvableDependencies中的对象。
具体的注入查找来源的具体在后面进行讲解。
筛选注入字段
上面我们讲完了注入对象查找的具体方式和过程,接下来我们回到第一步和第四部,我们看看在
@Autowired
、@Resource
分别是在那些对象中进行查找和处理需要注入的对象的。
原生注解
Spring原生注解注入主要指的就是@Autowired
,当然也不止只有他,下面会详情说,Spring原生注解注入主要是在AutowiredAnnotationBeanPostProcessor
对象中进行处理的,当然,我们也不是一定必须是使用Autowired
注入,因为在AutowiredAnnotationBeanPostProcessor
提供了一个setAutowiredAnnotationType
的方法来进行筛选注解设置。
构造方法:
首先我们看AutowiredAnnotationBeanPostProcessor
对象的构造方法
public AutowiredAnnotationBeanPostProcessor() {
// autowiredAnnotationTypes是个List,存在顺序
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
AutowiredAnnotationBeanPostProcessor
主要处理三个注解:
- 1. @Autowired
- 2. @Value
- 3. JSR330中的
javax.inject.Inject
注解
其中在findAutowiredAnnotation
中描述了三个注解同时出现时会优先使用的方式:
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
// 添加顺序就是实际顺序,所以三个注解同时存在时候会以Autowired为主
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
言归正传,我们回到注入处理流程,在AutowiredAnnotationBeanPostProcessor
中有个方法叫postProcessProperties
,他是一个对象注入的开始位置:
- • 1、AutowiredAnnotationBeanPostProcessor#postProcessProperties():
主要作用:筛选出目标对象的字段中被Autowired标注为需要注入的所有字段
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// 里面执行了findAutowiredAnnotation方法,返回目标对象及其目标对象中被Autowired标注的所有属性等信息
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;
}
- • 2、InjectionMetadata#inject():
主要作用是遍历需要注入的所有字段并对其一一注入。
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection<InjectedElement> checkedElements = this.checkedElements;
// 返回被Autowired标注的所有需要注入的字段
Collection<InjectedElement> elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
// 遍历需要注入的字段一一进行注入
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
- • 3、AutowiredFieldElement#inject()
在IOC容器中筛选出符合条件的对象,并赋值到目标对象中,也就是在此步骤中会执行依赖处理过程的resolveDependency()
方法。
当然,下面列出主要是字段注入的情况,还有另外一种方法注入主要
InjectedElement
实现类不同而已,但是最终都是到resolveDependency
找注入对象,下面我们就只拿属性注入来看。
@Override
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-resolve
value = resolveFieldValue(field, bean, beanName);
}
}
else {
// 里面执行了依赖处理过程中的resolveDependency方法
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
// 反射赋值
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
通用注解
什么是通用注解注入?
通用注解注入主要是指处理一些Java规范中一些如
@Resource
、@PostConstruct
和@PreDestroy
注解的注入。
通用注解的入口是CommonAnnotationBeanPostProcessor
,首先我们也来看一下构造方法,了解他主要处理的注解:
public class CommonAnnotationBeanPostProcessor extends InitDestroyAnnotationBeanPostProcessor
implements InstantiationAwareBeanPostProcessor, BeanFactoryAware, Serializable {
static {
webServiceRefClass = loadAnnotationType("javax.xml.ws.WebServiceRef");
ejbClass = loadAnnotationType("javax.ejb.EJB");
resourceAnnotationTypes.add(Resource.class);
if (webServiceRefClass != null) {
resourceAnnotationTypes.add(webServiceRefClass);
}
if (ejbClass != null) {
resourceAnnotationTypes.add(ejbClass);
}
}
public CommonAnnotationBeanPostProcessor() {
setOrder(Ordered.LOWEST_PRECEDENCE - 3);
setInitAnnotationType(PostConstruct.class);
setDestroyAnnotationType(PreDestroy.class);
ignoreResourceType("javax.xml.ws.WebServiceContext");
}
}
从中我们也可以看出,CommonAnnotationBeanPostProcessor
主要处理注入的三个注解:
- 1. @Resource
- 2. 注解
javax.xml.ws.WebServiceRef
- 3. 注解
javax.ejb.EJB
以及生命周期的两个注解:
- 1. @PostConstruct
- 2. @PreDestroy
但是与AutowiredAnnotationBeanPostProcessor
不同的是,在校验注解存在时在CommonAnnotationBeanPostProcessor
中是采用包含的方式校验的:
// 校验clazz是否在resourceAnnotationTypes中包含
AnnotationUtils.isCandidateClass(clazz, resourceAnnotationTypes)
CommonAnnotationBeanPostProcessor
的处理过程思想和逻辑都和AutowiredAnnotationBeanPostProcessor
有很多相同之处,有一点点区别在功能上我们也能知道。那就是注入的顺序:
- • @Autowired 先根据类型(byType)查找,如果存在多个(Bean)再根据名称(byName)进行查找;
- • @Resource 先根据名称(byName)查找,如果(根据名称)查找不到,再根据类型(byType)进行查找。
而这个存在的区别主要就存在于InjectedElement
对象的实现类上,AutowiredAnnotationBeanPostProcessor
中对InjectedElement
使用的实现类是AutowiredFieldElement
(用于字段注入)和AutowiredMethodElement
(用于方法注入),而CommonAnnotationBeanPostProcessor
使用的是InjectedElement
(里面既包含了字段注入,也包含了方法注入)
CommonAnnotationBeanPostProcessor
对象中注入的前两步和AutowiredAnnotationBeanPostProcessor
几乎一摸一样,这里我们主要看一下InjectedElement
及其之后的逻辑。
- • InjectedElement#inject()
字段注入和方法注入放在一起,而且都是走的getResourceToInject
获得注入对象的值。
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
// 是否是字段
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
field.set(target, getResourceToInject(target, requestingBeanName));
}
else {
if (checkPropertySkipping(pvs)) {
return;
}
try {
// 方法注入
Method method = (Method) this.member;
ReflectionUtils.makeAccessible(method);
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
- • InjectionMetadata.InjectedElement#getResourceToInject()
ResourceElement
是InjectionMetadata.InjectedElement
对象的一个子类,他针对于不同外部注入的方式有不同的现实。
image-20230326120430926
我们还是主要拿Resource
的实现来讲:
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
// 校验注入方式是否是实时注入
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
接下来我们还是以实施注入的代码来讲
- • CommonAnnotationBeanPostProcessor#getResource()
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
// ...
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
- • CommonAnnotationBeanPostProcessor#autowireResource()
下面就是@Resource
区别于Autowired
注入方式的地方
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set<String> autowiredBeanNames;
String name = element.name;
// factory类型判断是否是AutowireCapableBeanFactory类型的对象
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
// !factory.containsBean(name) 通过名称到Spring IOC容器中查找是否存在对应的对象
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
// 如果Spring IOC中不存在使用resolveDependency走依赖查找处理过程
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
else {
// 说明IOC容器中存在对应的对象,则直接从IOC中取
resource = beanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
}
else {
// 直接从IOC中取
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
// ...
return resource;
}