Spring 中@Autowired,@Resource,@Inject 注解实现原理
笔记哥 /
04-24 /
2点赞 /
0评论 /
846阅读
## 使用案例
**前置条件:** 现在有一个 `Vehicle` 接口,它有两个实现类 `Bus` 和 `Car` ,现在还有一个类 `VehicleService` 需要注入一个 `Vehicle` 类型的 Bean:
```java
public interface Vehicle {}
@Component
public class Car implements Vehicle {}
@Component
public class Bus implements Vehicle {}
```
**使用** `@Autowired` **注解注入 Bean**:
`@Autowired` 注解可以和 `@Qualifier` 注解一起使用,在有多个符合条件的 Bean 的情况下限制注入特定名称的 Bean:
```java
@Component
public class VehicleService {
@Autowired
@Qualifier("car") //假设这里是想要注入Bean名称为car的这个Bean
private Vehicle vehicle;
}
```
**使用** `@Inject` **注解注入 Bean**:
`@Inject` 注解可以和 `@Qualifier`或者 `@Named` 注解一起使用,在有多个符合条件的 Bean 的情况下限制注入特定名称的 Bean:
```java
@Component
public class VehicleService {
@Inject
@Qualifier("car") //假设这里是想要注入Bean名称为car的这个Bean
private Vehicle vehicle;
@Inject
@Named("bus") //假设这里是想要注入Bean名称为bus的这个Bean
private Vehicle anotherVehicle;
}
```
**使用** `@Resource` **注解注入 Bean:**
```java
@Component
public class VehicleService {
@Resource(name = "car")
private Vehicle vehicle;
}
```
虽然以上三种使用方法都能够实现注入 Bean 的需求,但是它们在底层实现上有什么区别呢?
## 注解体系
在 Java EE 和 Spring 体系中定义了几套注解:
**JSR 250:**定义了 `@PostConstruct`,`@PreDestroy`,`@Resource` 注解,其中 `@Resource` 注解**默认是按照名称进行注入**。
**JSR 330:**定义了 `@Inject`,`@Qualifier`, `@Named` 注解,其中 `@Inject` 注解**默认是按照类型进行注入**,可以搭配 `@Qualifier` 或者`@Named` 注解实现按照名称注入。
**Spring:**定义了 `@Autowired`,`@Qualifier`注解,其中 `@Autowired` 注解**默认是按照类型进行注入**,可以搭配 `@Qualifier` 注解实现按照名称注入。
当前 JSR 250 定义的注解属于 `jakarta.annotation-api`,而 JSR 330 定义的注解属于 `jakarta.inject-api`。
## 实现原理
### InstantiationAwareBeanPostProcessor 方法调用触发的位置:
Spring 中提供了 `InstantiationAwareBeanPostProcessor` 接口,它有一个 `postProcessProperties()` 负责实现对 Bean 的属性进行处理。
Spring 中提供了实现类 `CommonAnnotationBeanPostProcessor` 负责处理 `@Resource` 注解;提供了实现类 `AutowiredAnnotationBeanPostProcessor` 负责处理 `@Autowired` 注解和 `@Inject` 注解。
`InstantiationAwareBeanPostProcessor`的 `postProcessProperties()` 方法是在 `AbstractAutowireCapableBeanFactory` 中的 `doCreateBean()` 创建 Bean 的方法中触发调用的,在这个方法中的主要实现逻辑是**实例化 Bean -> 填充 Bean 属性 -> 初始化 Bean。** 代码如下:
```java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {BeanWrapper instanceWrapper = null;if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);}if (instanceWrapper == null) {
//实例化Bean对象 instanceWrapper = createBeanInstance(beanName, mbd, args);}Object bean = instanceWrapper.getWrappedInstance();
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName));if (earlySingletonExposure) { addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));}
Object exposedObject = bean;try {
//填充Bean属性 populateBean(beanName, mbd, instanceWrapper); //初始化Bean exposedObject = initializeBean(beanName, exposedObject, mbd);}
}
```
在填充 Bean 属性的方法 `populateBean()` 中实现了对 `postProcessProperties()` 方法的调用,**在该方法实现对注解修饰的需要注入的字段进行赋值,即自动注入。** 代码如下:
```java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//省略部分代码
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (hasInstantiationAwareBeanPostProcessors()) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
//这里获取所有InstantiationAwareBeanPostProcessor接口的实现类
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) { //调用postProcessProperties()方法
PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}
}
```
### InstantiationAwareBeanPostProcessor 注册的时机:
既然 `InstantiationAwareBeanPostProcessor` 是负责处理 Bean 的属性的自动注入的,那么它一定是在业务 Bean 创建之前就已经完成初始化了,这样在业务 Bean 创建的时候才能调用它的实例方法。它的初始化是在 Spring 上下文的基类 `AbstractApplicationContext` 的 `refresh()` 方法中完成的。代码如下:
```java
public void refresh() throws BeansException, IllegalStateException {
//省略其它代码//这里注册了InstantiationAwareBeanPostProcessorregisterBeanPostProcessors(beanFactory);
//省略其它代码
//这里创建所有的单例BeanfinishBeanFactoryInitialization(beanFactory);
finishRefresh();
}
```
而在 `registerBeanPostProcessors()` 方法中又调用了 `PostProcessorRegistrationDelegate` 的 `registerBeanPostProcessors()` 方法来完成注册的。代码如下:
```java
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
```
在`PostProcessorRegistrationDelegate` 的 `registerBeanPostProcessors()` 方法真正实现注册逻辑。代码如下:
```java
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory,
AbstractApplicationContext applicationContext) {
//这里获取到所有实现了BeanPostProcessor接口的Bean名称
//InstantiationAwareBeanPostProcessor接口继承了BeanPostProcessor接口
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//遍历Bean名称调用BeanFactory.getBean()方法触发BeanPostProcessor Bean的创建
//然后根据是否实现了PriorityOrdered接口、Ordered接口和其它分为三大类
//分别将这三大类的BeanPostProcessor实例进行注册
List priorityOrderedPostProcessors = new ArrayList<>();
List internalPostProcessors = new ArrayList<>();
List orderedPostProcessorNames = new ArrayList<>();
List nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//这里调用BeanFactory.getBean()方法触发BeanPostProcessor Bean的创建
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
//首先注册实现了PriorityOrdered接口的BeanPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
//然后触发实现了Ordered接口的BeanPostProcessor Bean的创建并注册
List orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
//最后触发其它BeanPostProcessor Bean的创建并注册
List nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
}
```
### CommonAnnotationBeanPostProcessor 实现逻辑(以修饰字段为例)
首先在 `CommonAnnotationBeanPostProcessor` 的静态初始化块中初始化了它要处理的注解。代码如下:
```java
static {
//这里是为了适配不同版本@Resource注解在不同的包路径下
jakartaResourceType = loadAnnotationType("jakarta.annotation.Resource");
if (jakartaResourceType != null) {
resourceAnnotationTypes.add(jakartaResourceType);
}
//这里是为了适配不同版本@Resource注解在不同的包路径下
javaxResourceType = loadAnnotationType("javax.annotation.Resource");
if (javaxResourceType != null) {
resourceAnnotationTypes.add(javaxResourceType);
}
}
```
在它的 `postProcessProperties()` 方法中主要实现逻辑为**找到 `@Resource` 注解修饰的字段 -> 通过反射给字段赋值**。代码如下:
```java
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//找@Resource注解修饰的字段
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//给字段赋值
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
```
找 `@Resource` 注解修饰的字段是在 `findResourceMetadata()` 方法中实现的,在该方法中又调用了 `buildResourceMetadata()` 来进行实际的查找,在这个方法中通过反射的方式遍历字段看它是否有 `@Resource` 注解修饰,如果是的话把它包装为一个 `ResourceElement` 对象放到列表中。最后基于列表构造一个 `InjectionMetadata` 对象返回。代码如下:
```java
private InjectionMetadata findResourceMetadata(String beanName, Class> clazz, @Nullable PropertyValues pvs) {
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
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);
}
//这里调用buildResourceMetadata()方法
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
private InjectionMetadata buildResourceMetadata(Class> clazz) {
List elements = new ArrayList<>();
Class> targetClass = clazz;
//省略部分代码
do {
final List currElements = new ArrayList<>();
//这里就会遍历每个字段看字段是否有@Resource注解修饰有的话就加入到列表中
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//省略部分代码
if (jakartaResourceType != null && field.isAnnotationPresent(jakartaResourceType)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
else if (javaxResourceType != null && field.isAnnotationPresent(javaxResourceType)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new LegacyResourceElement(field, field, null));
}
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
```
实际触发赋值的操作是在 `InjectionMetadata` 的 `inject()` 方法中实现的,在它的方法中又会循环调用 `InjectedElement` 的 `inject()` 方法。代码如下:
```java
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection checkedElements = this.checkedElements;
Collection elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
```
在 `InjectedElement` 的 `inject()` 方法中通过反射的方式将找到的 Bean 赋值给字段。代码如下:
```java
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)throws Throwable {
if (!shouldInject(pvs)) {
return;
}
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
//这里通过反射的方式设置值,设置的值就是根据Bean名称获取到的Bean
field.set(target, getResourceToInject(target, requestingBeanName));
} else {
//省略其它代码
}
}
```
在 `ResourceElement` 的 `getResourceToInject()` 方法中实现了查找逻辑:**如果 `BeanFactory` 中包含这个 Bean 名称对应的 Bean 则直接根据名称查找,否则会根据类型进行匹配,这个就是常说的 `@Resource` 注解默认是按照名称进行匹配的,名称匹配不到的情况下再按照类型进行匹配**。代码如下:
```java
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
//省略代码
// Regular resource autowiring
if (this.resourceFactory == null) {
throw new NoSuchBeanDefinitionException(element.lookupType,
"No resource factory configured - specify the 'resourceFactory' property");
}
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)throws NoSuchBeanDefinitionException {
Object resource;
Set autowiredBeanNames;
String name = element.name;
if (factory instanceof AutowireCapableBeanFactory autowireCapableBeanFactory) {
//如果根据Bean名称找不到Bean且允许按照类型匹配的情况下走第一个分支
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
resource = autowireCapableBeanFactory.resolveDependency(
element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
} else { //如果根据名称找得到Bean则直接根据名称获取Bean
resource = autowireCapableBeanFactory.resolveBeanByName(name, element.getDependencyDescriptor());
autowiredBeanNames = Collections.singleton(name);
}
} else {
//省略代码
}
//省略代码
return resource;
}
```
按照类型匹配的逻辑是在 `DefaultListableBeanFactory` 的 `doResolveDependency()` 方法中实现的,**在该方法中会根据类型找到所有是当前类型的 Bean,然后构造一个 Map,key 是 Bean 的名称,value 是对应的 Bean 对象,如果找到的 Bean 个数大于 1 则会选择一个最符合条件的返回(选择的依据后面会讲到),如果等于 1 则直接返回这个 Bean**。代码如下:
```java
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try { //省略代码 //这里根据类型找到所有的Bean,然后Bean的名称作为key,Bean作为Value Map matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { // Step 4c (fallback): custom Collection / Map declarations for collecting multiple beans multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // Raise exception if nothing found for required injection point if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; }String autowiredBeanName; Object instanceCandidate;//如果根据类型找到多个Bean则需要选择一个合适的Bean返回 if (matchingBeans.size() > 1) { autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesArrayCollectionOrMap(type)) { // Raise exception if no clear match found for required injection point 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 { //如果只有一个Bean则直接返回这个Bean Map.Entry entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); }// Step 6: validate single result if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } return resolveInstance(instanceCandidate, descriptor, type, autowiredBeanName);}finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);}
}
```
### AutowiredAnnotationBeanPostProcessor 实现逻辑(以修饰字段为例)
首先在构造函数中初始化了需要处理的注解包括 `@Autowired` 和 `@Inject` 注解。代码如下:
```java
public AutowiredAnnotationBeanPostProcessor() {
//添加要处理@Autowired注解
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
ClassLoader classLoader = AutowiredAnnotationBeanPostProcessor.class.getClassLoader();
try {
//这里是为了适配不同版本@Inject注解在不同的包路径下
this.autowiredAnnotationTypes.add((Class extends Annotation>)
ClassUtils.forName("jakarta.inject.Inject", classLoader));
} catch (ClassNotFoundException ex) {
// jakarta.inject API not available - simply skip.
}
try {
//这里是为了适配不同版本@Inject注解在不同的包路径下
this.autowiredAnnotationTypes.add((Class extends Annotation>)
ClassUtils.forName("javax.inject.Inject", classLoader));
} catch (ClassNotFoundException ex) {
// javax.inject API not available - simply skip.
}
}
```
在它的 `postProcessProperties()` 方法中主要实现逻辑为**找到 `@Autowired` 或者 `@Inject` 注解修饰的字段 -> 通过反射给字段赋值**。代码如下:
```java
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
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;
}
```
找`@Autowired` 或者 `@Inject` 注解修饰的字段是在 `findAutowiringMetadata()` 方法中实现的,在该方法中又调用了 `buildAutowiringMetadata()` 来进行实际的查找,在这个方法中通过反射的方式遍历字段看它是否有 `@Autowired` 或者 `@Inject` 注解修饰,如果是的话把它包装为一个`AutowiredFieldElement` 对象放到列表中。最后基于列表构造一个 `InjectionMetadata` 对象返回。代码如下:
```java
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.
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);
}
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
private InjectionMetadata buildAutowiringMetadata(Class> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
final List elements = new ArrayList<>();
Class> targetClass = clazz;
do {
final List fieldElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//这里找到是否有@Autowired或者@Inject注解修饰
MergedAnnotation> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
return;
}
boolean required = determineRequiredStatus(ann);
fieldElements.add(new AutowiredFieldElement(field, required));
}
});
}
}
```
实际触发赋值的操作是在 `InjectionMetadata` 的 `inject()` 方法中实现的,在它的方法中又会循环调用 `AutowiredFieldElement` 的 `inject()` 方法。代码如下:
```java
public void inject(Object target, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Collection checkedElements = this.checkedElements;
Collection elementsToIterate =
(checkedElements != null ? checkedElements : this.injectedElements);
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
element.inject(target, beanName, pvs);
}
}
}
```
在 `InjectedElement` 的 `inject()` 方法中通过反射的方式将找到的 Bean 赋值给字段。代码如下:
```java
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
//省略代码
} else {
//找到对应的Bean
value = resolveFieldValue(field, bean, beanName);
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
//通过反射的方式赋值
field.set(bean, value);
}
}
@Nullable
private Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set autowiredBeanNames = new LinkedHashSet<>(2);
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
try {
//调用beanFactory的resolveDependency()方法
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
return value;
}
```
然后会调用到 `DefaultListableBeanFactory` 的 `doResolveDependency()` 方法,和上面 `@Resource` 注解根据名称找不到 Bean 需要根据类型进行匹配的调用的是一个方法,只是它会多一个分支。**在这个分支里面判断 Bean 名称对应的 Bean 是否存在,如果存在则直接返回,如果不存在才会按照类型去匹配,这里实际上还是先按照名称匹配的,名称匹配不上再走的类型匹配的逻辑**。代码如下:
```java
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,@Nullable Set autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);try { //省略代码
//如果是@Autowired注解或者@Inject注解会先走到下面这个分支
//在这个分支里面也会先判断对应Bean名称的Bean是否存在,如果存在
//则直接获取返回,如果不存在才会按照类型去匹配
if (descriptor.usesStandardBeanLookup()) {
String dependencyName = descriptor.getDependencyName();
if (dependencyName == null || !containsBean(dependencyName)) {
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
dependencyName = (suggestedName != null && containsBean(suggestedName) ? suggestedName : null);
}
if (dependencyName != null) {
dependencyName = canonicalName(dependencyName); // dependency name can be alias of target name
if (isTypeMatch(dependencyName, type) && isAutowireCandidate(dependencyName, descriptor) &&
!isFallback(dependencyName) && !hasPrimaryConflict(dependencyName, type) &&
!isSelfReference(beanName, dependencyName)) {
if (autowiredBeanNames != null) {
autowiredBeanNames.add(dependencyName);
}
Object dependencyBean = getBean(dependencyName);
return resolveInstance(dependencyBean, descriptor, type, dependencyName);
}
}
}
//这里根据类型找到所有的Bean,然后Bean的名称作为key,Bean作为Value Map matchingBeans = findAutowireCandidates(beanName, type, descriptor); if (matchingBeans.isEmpty()) { // Step 4c (fallback): custom Collection / Map declarations for collecting multiple beans multipleBeans = resolveMultipleBeansFallback(descriptor, beanName, autowiredBeanNames, typeConverter); if (multipleBeans != null) { return multipleBeans; } // Raise exception if nothing found for required injection point if (isRequired(descriptor)) { raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor); } return null; }String autowiredBeanName; Object instanceCandidate;//如果根据类型找到多个Bean则需要选择一个合适的Bean返回 if (matchingBeans.size() > 1) { autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor); if (autowiredBeanName == null) { if (isRequired(descriptor) || !indicatesArrayCollectionOrMap(type)) { // Raise exception if no clear match found for required injection point 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 { //如果只有一个Bean则直接返回这个Bean Map.Entry entry = matchingBeans.entrySet().iterator().next(); autowiredBeanName = entry.getKey(); instanceCandidate = entry.getValue(); }// Step 6: validate single result if (autowiredBeanNames != null) { autowiredBeanNames.add(autowiredBeanName); } if (instanceCandidate instanceof Class) { instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this); } return resolveInstance(instanceCandidate, descriptor, type, autowiredBeanName);}finally { ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);}
}
```
### 当有多个类型匹配的 Bean 选择返回一个 Bean 的原则
当根据类型找到多个 Bean 时需要根据一些规则返回一个Bean。常见的可以通过 `@Qualifer` 限定名称或者通过 `@Primary` 来表示优先注入。在`DefaultListableBeanFactor` 的 `determineAutowireCandidate()` 方法中就实现了这些逻辑:
首先遍历找到的所有符合类型的 Bean,然后看是否有 `@Primary` 注解修饰,如果有的话,则优先返回有该 Bean;
否则再次尝试根据字段的名称匹配看是否有匹配的 Bean,如果有则返回;
否则尝试获取 `@Qualifier`注解定义的名称(**对于 `@Named` 注解来说它本身上面也有 `@Qualifer` 注解修饰**),然后看是否有名称匹配的 Bean,如果有则返回;
否则遍历 Bean 看是否有 `@Priority` 注解修饰,如果有则找最高优先级的 Bean 返回,值越小优先级越高;
否则看 `resolvableDependencies` 是否有注册对应的实例,如果有则返回,它的使用场景一般是有用户自己的 new 的对象可以注册到这里面,然后在一个 Spring 管理的 Bean 中可以把它注入进来。代码如下:
```java
protected String determineAutowireCandidate(Map candidates, DependencyDescriptor descriptor) {
Class> requiredType = descriptor.getDependencyType();
//首先处理@Primary注解,如果某个Bean有@Primary注解修饰则优先返回它
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
//否则再次根据字段的名称进行匹配,看找到的Bean里面有没有和字段名称相同的Bean,有的话则优先返回
String dependencyName = descriptor.getDependencyName();
if (dependencyName != null) {
for (String beanName : candidates.keySet()) {
if (matchesBeanName(beanName, dependencyName)) {
return beanName;
}
}
}
//否则尝试获取@Qualifier注解定义的名称,看找打的Bean里面有没有和该名称相同的Bean,有的话则优先返回
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
if (suggestedName != null) {
for (String beanName : candidates.keySet()) {
if (matchesBeanName(beanName, suggestedName)) {
return beanName;
}
}
}
//否则看找到的Bean是否有@Priority注解修饰,有的话取优先级最高的返回即值最小的
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
//否则自定义注册的非Spring管理生命周期的对象中是否有匹配,resolvableDependencies里面可以放
//一些对象,这些对象不是由Spring创建的而是用户自己创建放入的且需要在一个Spring的Bean中注入它
for (Map.Entry entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if (beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) {
return candidateName;
}
}
return null;
}
```
`@Named` 注解定义中使用了 `@Qualifer` 注解修饰。代码如下:
```java
@Qualifier // 这里使用了@Qualifer注解修饰
@Documented
@Retention(RUNTIME)
public @interface Named {
String value() default "";
}
```
本文来自投稿,不代表本站立场,如若转载,请注明出处:http//www.knowhub.vip/share/2/2551
- 热门的技术博文分享
- 1 . ESP实现Web服务器
- 2 . 从零到一:打造高效的金仓社区 API 集成到 MCP 服务方案
- 3 . 使用C#构建一个同时问多个LLM并总结的小工具
- 4 . .NET 原生驾驭 AI 新基建实战系列Milvus ── 大规模 AI 应用的向量数据库首选
- 5 . 在Avalonia/C#中使用依赖注入过程记录
- 6 . [设计模式/Java] 设计模式之工厂方法模式
- 7 . 5. RabbitMQ 消息队列中 Exchanges(交换机) 的详细说明
- 8 . SQL 中的各种连接 JOIN 的区别总结!
- 9 . JavaScript 中防抖和节流的多种实现方式及应用场景
- 10 . SaltStack 远程命令执行中文乱码问题
- 11 . 推荐10个 DeepSeek 神级提示词,建议搜藏起来使用
- 12 . C#基础:枚举、数组、类型、函数等解析
- 13 . VMware平台的Ubuntu部署完全分布式Hadoop环境
- 14 . C# 多项目打包时如何将项目引用转为包依赖
- 15 . Chrome 135 版本开发者工具(DevTools)更新内容
- 16 . 从零创建npm依赖,只需执行一条命令
- 17 . 关于 Newtonsoft.Json 和 System.Text.Json 混用导致的的序列化不识别的问题
- 18 . 大模型微调实战之训练数据集准备的艺术与科学
- 19 . Windows快速安装MongoDB之Mongo实战
- 20 . 探索 C# 14 新功能:实用特性为编程带来便利
- 相关联分享
- [设计模式/Java] 设计模式之工厂方法模式
- 【对称加密】DES与AES算法详解及Java实现
- 历数Java虚拟机垃圾回收GC收集器的缺点剖析
- Java虚拟机代码是如何一步一步变复杂且难以理解的?
- 产品中不同客户端请求下的 IP 归属地分析方法
- 在java中为什么重写equals一定也要重写hashCode方法?
- 设计模式之门面模式(外观模式)的原理、组成
- Java中如何优雅的处理日期
- 启用 Java AOT 编译打包 Solon 项目(Solon AOT)
- YtyMark-java 富文本编辑器分享(以开源)
- Java 21新特性有哪些?
- Excel 高性能导出方案推荐(JAVA)
- Java AI(智能体)编排开发就用 Solon Flow
- Spring 中@Autowired,@Resource,@Inject 注解实现原理
- JAVA 24 环境安装与配置教程
- File与IO流之字节流