Spring?中@Autowired、@Resource、@Inject?注解實(shí)現(xiàn)原理使用案例詳解
使用案例
前置條件: 現(xiàn)在有一個(gè) Vehicle 接口,它有兩個(gè)實(shí)現(xiàn)類 Bus 和 Car ,現(xiàn)在還有一個(gè)類 VehicleService 需要注入一個(gè) Vehicle 類型的 Bean:
public interface Vehicle {}
@Component
public class Car implements Vehicle {}
@Component
public class Bus implements Vehicle {}使用 @Autowired 注解注入 Bean:
@Autowired 注解可以和 @Qualifier 注解一起使用,在有多個(gè)符合條件的 Bean 的情況下限制注入特定名稱的 Bean:
@Component
public class VehicleService {
@Autowired
@Qualifier("car") //假設(shè)這里是想要注入Bean名稱為car的這個(gè)Bean
private Vehicle vehicle;
}使用 @Inject 注解注入 Bean:
@Inject 注解可以和 @Qualifier或者 @Named 注解一起使用,在有多個(gè)符合條件的 Bean 的情況下限制注入特定名稱的 Bean:
@Component
public class VehicleService {
@Inject
@Qualifier("car") //假設(shè)這里是想要注入Bean名稱為car的這個(gè)Bean
private Vehicle vehicle;
@Inject
@Named("bus") //假設(shè)這里是想要注入Bean名稱為bus的這個(gè)Bean
private Vehicle anotherVehicle;
}使用 @Resource 注解注入 Bean:
@Component
public class VehicleService {
@Resource(name = "car")
private Vehicle vehicle;
}雖然以上三種使用方法都能夠?qū)崿F(xiàn)注入 Bean 的需求,但是它們在底層實(shí)現(xiàn)上有什么區(qū)別呢?
注解體系
在 Java EE 和 Spring 體系中定義了幾套注解:
JSR 250:定義了 @PostConstruct,@PreDestroy,@Resource 注解,其中 @Resource 注解默認(rèn)是按照名稱進(jìn)行注入。
JSR 330:定義了 @Inject,@Qualifier, @Named 注解,其中 @Inject 注解默認(rèn)是按照類型進(jìn)行注入,可以搭配 @Qualifier 或者@Named 注解實(shí)現(xiàn)按照名稱注入。
Spring:定義了 @Autowired,@Qualifier注解,其中 @Autowired 注解默認(rèn)是按照類型進(jìn)行注入,可以搭配 @Qualifier 注解實(shí)現(xiàn)按照名稱注入。
當(dāng)前 JSR 250 定義的注解屬于 jakarta.annotation-api,而 JSR 330 定義的注解屬于 jakarta.inject-api。
實(shí)現(xiàn)原理
InstantiationAwareBeanPostProcessor 方法調(diào)用觸發(fā)的位置:
Spring 中提供了 InstantiationAwareBeanPostProcessor 接口,它有一個(gè) postProcessProperties() 負(fù)責(zé)實(shí)現(xiàn)對 Bean 的屬性進(jìn)行處理。
Spring 中提供了實(shí)現(xiàn)類 CommonAnnotationBeanPostProcessor 負(fù)責(zé)處理 @Resource 注解;提供了實(shí)現(xiàn)類 AutowiredAnnotationBeanPostProcessor 負(fù)責(zé)處理 @Autowired 注解和 @Inject 注解。
InstantiationAwareBeanPostProcessor的 postProcessProperties() 方法是在 AbstractAutowireCapableBeanFactory 中的 doCreateBean() 創(chuàng)建 Bean 的方法中觸發(fā)調(diào)用的,在這個(gè)方法中的主要實(shí)現(xiàn)邏輯是實(shí)例化 Bean -> 填充 Bean 屬性 -> 初始化 Bean。 代碼如下:
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) {
//實(shí)例化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() 中實(shí)現(xiàn)了對 postProcessProperties() 方法的調(diào)用,在該方法實(shí)現(xiàn)對注解修飾的需要注入的字段進(jìn)行賦值,即自動注入。 代碼如下:
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接口的實(shí)現(xiàn)類
for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
//調(diào)用postProcessProperties()方法
PropertyValues pvsToUse = bp.postProcessProperties(pvs,
bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
pvs = pvsToUse;
}
}
}InstantiationAwareBeanPostProcessor 注冊的時(shí)機(jī):
既然 InstantiationAwareBeanPostProcessor 是負(fù)責(zé)處理 Bean 的屬性的自動注入的,那么它一定是在業(yè)務(wù) Bean 創(chuàng)建之前就已經(jīng)完成初始化了,這樣在業(yè)務(wù) Bean 創(chuàng)建的時(shí)候才能調(diào)用它的實(shí)例方法。它的初始化是在 Spring 上下文的基類 AbstractApplicationContext 的 refresh() 方法中完成的。代碼如下:
public void refresh() throws BeansException, IllegalStateException {
//省略其它代碼
//這里注冊了InstantiationAwareBeanPostProcessor
registerBeanPostProcessors(beanFactory);
//省略其它代碼
//這里創(chuàng)建所有的單例Bean
finishBeanFactoryInitialization(beanFactory);
finishRefresh();
}而在 registerBeanPostProcessors() 方法中又調(diào)用了 PostProcessorRegistrationDelegate 的 registerBeanPostProcessors() 方法來完成注冊的。代碼如下:
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}在PostProcessorRegistrationDelegate 的 registerBeanPostProcessors() 方法真正實(shí)現(xiàn)注冊邏輯。代碼如下:
public static void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory,
AbstractApplicationContext applicationContext) {
//這里獲取到所有實(shí)現(xiàn)了BeanPostProcessor接口的Bean名稱
//InstantiationAwareBeanPostProcessor接口繼承了BeanPostProcessor接口
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//遍歷Bean名稱調(diào)用BeanFactory.getBean()方法觸發(fā)BeanPostProcessor Bean的創(chuàng)建
//然后根據(jù)是否實(shí)現(xiàn)了PriorityOrdered接口、Ordered接口和其它分為三大類
//分別將這三大類的BeanPostProcessor實(shí)例進(jìn)行注冊
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//這里調(diào)用BeanFactory.getBean()方法觸發(fā)BeanPostProcessor Bean的創(chuàng)建
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);
}
}
//首先注冊實(shí)現(xiàn)了PriorityOrdered接口的BeanPostProcessor
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
//然后觸發(fā)實(shí)現(xiàn)了Ordered接口的BeanPostProcessor Bean的創(chuàng)建并注冊
List<BeanPostProcessor> 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);
//最后觸發(fā)其它BeanPostProcessor Bean的創(chuàng)建并注冊
List<BeanPostProcessor> 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 實(shí)現(xiàn)邏輯(以修飾字段為例)
首先在 CommonAnnotationBeanPostProcessor 的靜態(tài)初始化塊中初始化了它要處理的注解。代碼如下:
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() 方法中主要實(shí)現(xiàn)邏輯為找到 @Resource 注解修飾的字段 -> 通過反射給字段賦值。代碼如下:
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() 方法中實(shí)現(xiàn)的,在該方法中又調(diào)用了 buildResourceMetadata() 來進(jìn)行實(shí)際的查找,在這個(gè)方法中通過反射的方式遍歷字段看它是否有 @Resource 注解修飾,如果是的話把它包裝為一個(gè) ResourceElement 對象放到列表中。最后基于列表構(gòu)造一個(gè) InjectionMetadata 對象返回。代碼如下:
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);
}
//這里調(diào)用buildResourceMetadata()方法
metadata = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
private InjectionMetadata buildResourceMetadata(Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
//省略部分代碼
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
//這里就會遍歷每個(gè)字段看字段是否有@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);
}實(shí)際觸發(fā)賦值的操作是在 InjectionMetadata 的 inject() 方法中實(shí)現(xiàn)的,在它的方法中又會循環(huán)調(diào)用 InjectedElement 的 inject() 方法。代碼如下:
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);
}
}
}在 InjectedElement 的 inject() 方法中通過反射的方式將找到的 Bean 賦值給字段。代碼如下:
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);
//這里通過反射的方式設(shè)置值,設(shè)置的值就是根據(jù)Bean名稱獲取到的Bean
field.set(target, getResourceToInject(target, requestingBeanName));
} else {
//省略其它代碼
}
}在 ResourceElement 的 getResourceToInject() 方法中實(shí)現(xiàn)了查找邏輯:如果 BeanFactory 中包含這個(gè) Bean 名稱對應(yīng)的 Bean 則直接根據(jù)名稱查找,否則會根據(jù)類型進(jìn)行匹配,這個(gè)就是常說的 @Resource 注解默認(rèn)是按照名稱進(jìn)行匹配的,名稱匹配不到的情況下再按照類型進(jìn)行匹配。代碼如下:
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<String> autowiredBeanNames;
String name = element.name;
if (factory instanceof AutowireCapableBeanFactory autowireCapableBeanFactory) {
//如果根據(jù)Bean名稱找不到Bean且允許按照類型匹配的情況下走第一個(gè)分支
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 { //如果根據(jù)名稱找得到Bean則直接根據(jù)名稱獲取Bean
resource = autowireCapableBeanFactory.resolveBeanByName(name, element.getDependencyDescriptor());
autowiredBeanNames = Collections.singleton(name);
}
} else {
//省略代碼
}
//省略代碼
return resource;
}按照類型匹配的邏輯是在 DefaultListableBeanFactory 的 doResolveDependency() 方法中實(shí)現(xiàn)的,在該方法中會根據(jù)類型找到所有是當(dāng)前類型的 Bean,然后構(gòu)造一個(gè) Map,key 是 Bean 的名稱,value 是對應(yīng)的 Bean 對象,如果找到的 Bean 個(gè)數(shù)大于 1 則會選擇一個(gè)最符合條件的返回(選擇的依據(jù)后面會講到),如果等于 1 則直接返回這個(gè) Bean。代碼如下:
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
//省略代碼
//這里根據(jù)類型找到所有的Bean,然后Bean的名稱作為key,Bean作為Value
Map<String, Object> 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;
//如果根據(jù)類型找到多個(gè)Bean則需要選擇一個(gè)合適的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 {
//如果只有一個(gè)Bean則直接返回這個(gè)Bean
Map.Entry<String, Object> 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 實(shí)現(xiàn)邏輯(以修飾字段為例)
首先在構(gòu)造函數(shù)中初始化了需要處理的注解包括 @Autowired 和 @Inject 注解。代碼如下:
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() 方法中主要實(shí)現(xiàn)邏輯為找到 @Autowired 或者 @Inject 注解修飾的字段 -> 通過反射給字段賦值。代碼如下:
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() 方法中實(shí)現(xiàn)的,在該方法中又調(diào)用了 buildAutowiringMetadata() 來進(jìn)行實(shí)際的查找,在這個(gè)方法中通過反射的方式遍歷字段看它是否有 @Autowired 或者 @Inject 注解修飾,如果是的話把它包裝為一個(gè)AutowiredFieldElement 對象放到列表中。最后基于列表構(gòu)造一個(gè) InjectionMetadata 對象返回。代碼如下:
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<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> 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));
}
});
}
}實(shí)際觸發(fā)賦值的操作是在 InjectionMetadata 的 inject() 方法中實(shí)現(xiàn)的,在它的方法中又會循環(huán)調(diào)用 AutowiredFieldElement 的 inject() 方法。代碼如下:
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);
}
}
}在 InjectedElement 的 inject() 方法中通過反射的方式將找到的 Bean 賦值給字段。代碼如下:
@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 {
//找到對應(yīng)的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<String> autowiredBeanNames = new LinkedHashSet<>(2);
TypeConverter typeConverter = beanFactory.getTypeConverter();
Object value;
try {
//調(diào)用beanFactory的resolveDependency()方法
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
} catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
return value;
}然后會調(diào)用到 DefaultListableBeanFactory 的 doResolveDependency() 方法,和上面 @Resource 注解根據(jù)名稱找不到 Bean 需要根據(jù)類型進(jìn)行匹配的調(diào)用的是一個(gè)方法,只是它會多一個(gè)分支。在這個(gè)分支里面判斷 Bean 名稱對應(yīng)的 Bean 是否存在,如果存在則直接返回,如果不存在才會按照類型去匹配,這里實(shí)際上還是先按照名稱匹配的,名稱匹配不上再走的類型匹配的邏輯。代碼如下:
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
//省略代碼
//如果是@Autowired注解或者@Inject注解會先走到下面這個(gè)分支
//在這個(gè)分支里面也會先判斷對應(yīng)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);
}
}
}
//這里根據(jù)類型找到所有的Bean,然后Bean的名稱作為key,Bean作為Value
Map<String, Object> 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;
//如果根據(jù)類型找到多個(gè)Bean則需要選擇一個(gè)合適的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 {
//如果只有一個(gè)Bean則直接返回這個(gè)Bean
Map.Entry<String, Object> 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);
}
}當(dāng)有多個(gè)類型匹配的 Bean 選擇返回一個(gè) Bean 的原則
當(dāng)根據(jù)類型找到多個(gè) Bean 時(shí)需要根據(jù)一些規(guī)則返回一個(gè)Bean。常見的可以通過 @Qualifer 限定名稱或者通過 @Primary 來表示優(yōu)先注入。在DefaultListableBeanFactor 的 determineAutowireCandidate() 方法中就實(shí)現(xiàn)了這些邏輯:
首先遍歷找到的所有符合類型的 Bean,然后看是否有 @Primary 注解修飾,如果有的話,則優(yōu)先返回有該 Bean;
否則再次嘗試根據(jù)字段的名稱匹配看是否有匹配的 Bean,如果有則返回;
否則嘗試獲取 @Qualifier注解定義的名稱(對于 @Named 注解來說它本身上面也有 @Qualifer 注解修飾),然后看是否有名稱匹配的 Bean,如果有則返回;
否則遍歷 Bean 看是否有 @Priority 注解修飾,如果有則找最高優(yōu)先級的 Bean 返回,值越小優(yōu)先級越高;
否則看 resolvableDependencies 是否有注冊對應(yīng)的實(shí)例,如果有則返回,它的使用場景一般是有用戶自己的 new 的對象可以注冊到這里面,然后在一個(gè) Spring 管理的 Bean 中可以把它注入進(jìn)來。代碼如下:
protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
Class<?> requiredType = descriptor.getDependencyType();
//首先處理@Primary注解,如果某個(gè)Bean有@Primary注解修飾則優(yōu)先返回它
String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
if (primaryCandidate != null) {
return primaryCandidate;
}
//否則再次根據(jù)字段的名稱進(jìn)行匹配,看找到的Bean里面有沒有和字段名稱相同的Bean,有的話則優(yōu)先返回
String dependencyName = descriptor.getDependencyName();
if (dependencyName != null) {
for (String beanName : candidates.keySet()) {
if (matchesBeanName(beanName, dependencyName)) {
return beanName;
}
}
}
//否則嘗試獲取@Qualifier注解定義的名稱,看找打的Bean里面有沒有和該名稱相同的Bean,有的話則優(yōu)先返回
String suggestedName = getAutowireCandidateResolver().getSuggestedName(descriptor);
if (suggestedName != null) {
for (String beanName : candidates.keySet()) {
if (matchesBeanName(beanName, suggestedName)) {
return beanName;
}
}
}
//否則看找到的Bean是否有@Priority注解修飾,有的話取優(yōu)先級最高的返回即值最小的
String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
if (priorityCandidate != null) {
return priorityCandidate;
}
//否則自定義注冊的非Spring管理生命周期的對象中是否有匹配,resolvableDependencies里面可以放
//一些對象,這些對象不是由Spring創(chuàng)建的而是用戶自己創(chuàng)建放入的且需要在一個(gè)Spring的Bean中注入它
for (Map.Entry<String, Object> entry : candidates.entrySet()) {
String candidateName = entry.getKey();
Object beanInstance = entry.getValue();
if (beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) {
return candidateName;
}
}
return null;
}@Named 注解定義中使用了 @Qualifer 注解修飾。代碼如下:
@Qualifier // 這里使用了@Qualifer注解修飾
@Documented
@Retention(RUNTIME)
public @interface Named {
String value() default "";
}到此這篇關(guān)于Spring 中@Autowired,@Resource,@Inject 注解實(shí)現(xiàn)原理的文章就介紹到這了,更多相關(guān)Spring 中@Autowired,@Resource,@Inject 注解實(shí)現(xiàn)原理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Spring?中@Autowired、@Resource、@Inject?注解實(shí)現(xiàn)原理使用案例詳解
- Spring中@Autowired @Resource @Inject三個(gè)注解有什么區(qū)別
- 詳解Spring依賴注入:@Autowired,@Resource和@Inject區(qū)別與實(shí)現(xiàn)原理
- SpringBoot注解篇之@Resource與@Autowired的使用區(qū)別
- Spring注解@Autowired和@Resource的區(qū)別詳解
- 一文搞懂Spring中@Autowired和@Resource的區(qū)別
- Spring注解@Resource和@Autowired區(qū)別對比詳解
相關(guān)文章
以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼
這篇文章主要介紹了以Spring Boot的方式顯示圖片或下載文件到瀏覽器的示例代碼,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-01-01
java8 集合 多字段 分組 統(tǒng)計(jì)個(gè)數(shù)代碼
這篇文章主要介紹了java8 集合 多字段 分組 統(tǒng)計(jì)個(gè)數(shù)代碼,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08
IDEA導(dǎo)入Springboot項(xiàng)目,注解和pom文件不識別的解決
這篇文章主要介紹了IDEA導(dǎo)入Springboot項(xiàng)目,注解和pom文件不識別的解決方案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
Java實(shí)現(xiàn)LeetCode(報(bào)數(shù))
這篇文章主要介紹了Java實(shí)現(xiàn)LeetCode(報(bào)數(shù)),本文通過使用java實(shí)現(xiàn)leetcode的報(bào)數(shù)題目和實(shí)現(xiàn)思路分析,需要的朋友可以參考下2021-06-06
ssm 使用token校驗(yàn)登錄的實(shí)現(xiàn)
這篇文章主要介紹了ssm 使用token校驗(yàn)登錄的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
SpringMVC?HttpMessageConverter報(bào)文信息轉(zhuǎn)換器
這篇文章主要為大家介紹了SpringMVC?HttpMessageConverter報(bào)文信息轉(zhuǎn)換器,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-05-05
Java實(shí)現(xiàn)八種排序算法詳細(xì)代碼舉例
排序問題一直是程序員工作與面試的重點(diǎn),今天特意整理研究下與大家共勉!這篇文章主要介紹了Java實(shí)現(xiàn)八種排序算法的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-10-10
Java Agent 動態(tài)修改字節(jié)碼詳情
這篇文章主要介紹了Java Agent動態(tài)修改字節(jié)碼的相關(guān)資料,需要的朋友可以參考下面文章具體的內(nèi)容2021-09-09

