關於Spring中@Autowired、@Resource和@Inject註解的區別請看:@Autowired、@Resource和@Inject註解的區別(最詳細),本片文章將會帶領你進行源碼分析@Autowired、@Resource註解的不同。
在上面所說的那篇博客中,我們知道:
Spring對於@Autowired、@Resource註解使用不同的後置處理器進行處理
@Autowired、@Resource之間的處理方式不同,@Autowired是根據類型,@Resource是根據名稱
在進行源碼分析之前,你需要了解以下Bean的生命週期:Spring中bean的生命週期(最詳細),其中在第五次調用bean的後置處理器時,完成屬性的依賴注入,第五次調用bean的後置處理器的步驟:拿到Spring容器中所有的實現了BeanPostProcessor接口的類,然後判斷其是否爲InstantiationAwareBeanPostProcessor接口的實現類,如果是調用postProcessProperties方法,完成屬性賦值。
在@Autowired、@Resource和@Inject註解的區別(最詳細)文章中,已經知道了Spring使用AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor類分別處理@Autowired註解和@Resource註解,他們都實現了InstantiationAwareBeanPostProcessor類,所以標註了@Autowired、@Resource會在第六次調用bean的後置處理器的時候完成屬性注入。
從上面兩張類的關係圖可以看到其都間接實現了InstantiationAwareBeanPostProcessor類,下面我們就一起分析一下源碼:
代碼塊1.AbstractAutowireCapableBeanFactory#populateBean方法
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
// state of the bean before properties are set. This can be used, for example,
// to support styles of field injection.
boolean continueWithPropertyPopulation = true;
//1.第五次後置處理器,對應着我之前博客裏面寫的bean生命週期,首先判斷這個bean是否是合成的,這個絕大多數是不是合成的,然後判斷是否有InstantiationAwareBeanPostProcessors的接口
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
//2.拿到所有的BeanPostProcessors處置處理器
for (BeanPostProcessor bp : getBeanPostProcessors()) {
//3.逐一判斷這個後置處理器是否是InstantiationAwareBeanPostProcessor類型的,因爲BeanPostProcessor接口是爲了統一進行管理bean後置處理器的
//BeanPostProcessor還有子接口,用於實現不同的作用,可以參考bean後置處理器那篇博客
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
//4.如果爲true,則說明在第五次調用後置處理的時候返回爲false,這樣就不會進行屬性注入了
//所以當你想bean中不進行屬性注入,可以實現InstantiationAwareBeanPostProcessor的postProcessAfterInstantiation方法
if (!continueWithPropertyPopulation) {
return;
}
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 5.解析自動裝配模式爲AUTOWIRE_BY_NAME和AUTOWIRE_BY_TYPE(現在幾乎不用,現在默認是AUTOWIRE_NO)
/**
* <bean id="fruit" class="com.joonwhee.open.demo.simple.Fruit" autowire="byName">
* <property name="color" value="Red"/>
* </bean>
* id值跟Fruit裏的屬性名一致
* <bean id="apple" class="com.joonwhee.open.demo.simple.Apple"/>
* public class Fruit {
* private Apple apple;//apple 會根據名稱完成自動注入
* private String color;
* }
* */
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
// Add property values based on autowire by name if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
// Add property values based on autowire by type if applicable.
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
//6.檢查是否有InstantiationAwareBeanPostProcessors接口的類
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
//7.執行第六次後置處理器,完成屬性賦值
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
//在Spring5.1之後,使用的是postProcessProperties方法完成屬性注入
PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
pvsToUse = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvsToUse == null) {
return;
}
}
pvs = pvsToUse;
}
}
}
//8.依賴檢查,對應depends-on屬性
if (needsDepCheck) {
checkDependencies(beanName, mbd, filteredPds, pvs);
}
}
//9.將所有PropertyValues中的屬性填充到bean中
if (pvs != null) {
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
AbstractAutowireCapableBeanFactory#populateBean方法是在Spring啓動時,完成非懶加載單實例bean註冊到容器時會執行的方法,可以對着Spring中bean的生命週期(最詳細)來進行分析,populateBean方法會執行bean生命週期的第五、第六次後置處理器,第五次就不做分析了,關鍵進行分析第六次完成屬性注入的生命週期,在populateBean方法中的第7步,會拿到所有的BeanPostProcessors方法,然後判斷是否是InstantiationAwareBeanPostProcessor類型的,如果是則執行postProcessPropertyValues方法完成屬性注入,因爲AutowiredAnnotationBeanPostProcessor和CommonAnnotationBeanPostProcessor類都實現了InstantiationAwareBeanPostProcessor接口,所以會在第7步進行調用各自的方法,我們先看一下getBeanPostProcessors方法,看代碼塊2。
然後看一下AutowiredAnnotationBeanPostProcessor的postProcessProperties方法,看代碼塊3.
CommonAnnotationBeanPostProcessor的postProcessProperties方法,看代碼塊8.
代碼塊2.AbstractBeanFactory#getBeanPostProcessors方法
/**
* Return the list of BeanPostProcessors that will get applied
* to beans created with this factory.
*/
//就是簡單的返回容器中所有的beanPostProcessors
public List<BeanPostProcessor> getBeanPostProcessors() {
return this.beanPostProcessors;
}
代碼塊3. AutowiredAnnotationBeanPostProcessor#postProcessProperties方法
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//1.獲取這個類中所有標註了@Autowired的屬性和方法,並把它們封裝在InjectionMetadata對象中
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
//2.完成bean的屬性注入
metadata.inject(bean, beanName, pvs);
}
catch (BeanCreationException ex) {
throw ex;
}
return pvs;
}
第1步,解析出這個類中所有的標註了@Autowired的屬性和方法,看代碼塊4,第2步,完成對bean屬性的注入,看代碼塊6.
代碼塊4.AutowiredAnnotationBeanPostProcessor#findAutowiringMetadata方法
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
//1.得到bean的名稱
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
//2.先從緩存中獲取已經解析過的類,在完成對一個類的解析之後,會進行緩存,第二次就不用在去解析了
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
//3.判斷是否刷新
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
//4.加鎖
synchronized (this.injectionMetadataCache) {
//6.再次從緩存中獲取解析之後的類
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
//7.完成對類的解析,獲取所有的標註了@Autowired的屬性和方法
metadata = buildAutowiringMetadata(clazz);
//8.放入到緩存中
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
在第7步中會完成對類的解析,解析出所有標註了@Autowired的屬性和方法,看代碼塊5.
代碼塊5.AutowiredAnnotationBeanPostProcessor#buildAutowiringMetadata方法
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
//1.解析類中屬性標註@Autowired註解的情況
ReflectionUtils.doWithLocalFields(targetClass, field -> {
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
//2.如果這個屬性是static修飾的,即使被@Autowired標註也不會進行屬性的自動注入,直接返回
//這裏使用的是lamda表達式,雖然有返回,但是不是退出buildAutowiringMetadata方法,不懂的自行百度
if (Modifier.isStatic(field.getModifiers())) {
return;
}
//3.判斷@Autowired註解裏面的required字段
boolean required = determineRequiredStatus(ann);
//4.封裝成AutowiredFieldElement對象,添加到currElements集合中
currElements.add(new AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
//5.如果這個方法是static修飾的,即使被@Autowired標註也不會進行屬性的自動注入,直接返回
return;
}
boolean required = determineRequiredStatus(ann);
//6.判斷@Autowired註解裏面的required字段
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
//7.解析父類,這個可以看出Spring想的真周到
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
可以看到如果屬性和方法被static修飾的話,是不會完成屬性的自動注入的,在第7步中,還會遞歸解析當前類的父類,這一點我感覺Spring做的真周到,你想到的沒想到的,Spring都會幫你做。
代碼塊6.InjectionMetadata#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);
//1.拿到類中(包括父類)標註了@Autowired註解的屬性和方法
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
//2.遍歷,然後對每一個完成屬性注入,這個是分屬性和方法的,他們都實現了InjectedElement類,重寫了inject方法
//這裏已屬性注入爲例
element.inject(target, beanName, pvs);
}
}
}
第2步遍歷類中所有的標註了@Autowired屬性和方法,具體看代碼塊7
代碼塊7.AutowiredFieldElement#inject方法
@Override
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
//1.記住這裏是調用InjectedElement的方法,標註了@Autowired註解的屬性和方法都會被封裝成InjectedElement類,
//所以這裏使用this.member就是獲取封裝在InjectedElement的屬性
Field field = (Field) this.member;
Object value;
//2.是否已有解析之後的緩存,如果有,則直接從緩存裏面取
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
//3.將屬性和@Autowired註解裏面的@Autowired字段封裝成DependencyDescriptor對象
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
try {
//4.從容器中獲取所依賴的bean,由於該方法過於複雜,我只看懂了一點,所以這個方法就不行解析,我大致說一下過程
//首先會判斷需要注入屬性的類型是否是Array、Collection、Map類型的,如果是,則查找所有屬性的泛型類型進行注入
//例如Map<String,Student> map,然後Spring判斷是Map類型,將就回去查找Value所對應的類型是Student,
//然後就會查找所有的Student類型,以bean的id爲key,以Student的實例爲Value注入到這個map中
//如果不是Array、Collection、Map類型的,就是去查找所有的需要注入屬性的類型,如果只有一個,則直接注入,
//如發現多個就會查找一個最優,會先通過@Primary註解查找最優,如果找不到會通過@Priority註解查找最優,如果該找不到
//就是用基本策略,使用屬性的名稱進行逐個匹配查找到的bean的id,如果屬性的名稱和bean的id相同即爲最優,如果還找打不到
//那麼就不要意思了,直接報錯了
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
}
catch (BeansException ex) {
throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
}
//5.放到緩存中,下次不用進行解析了
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
//步驟如果autowiredBeanNames大於1,說明是Array、Collection、Map類型
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
//6.如果是1個,也需要判斷是不是Array、Collection、Map類型
if (beanFactory.containsBean(autowiredBeanName) &&
beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
this.cachedFieldValue = new ShortcutDependencyDescriptor(
desc, autowiredBeanName, field.getType());
}
}
}
else {
this.cachedFieldValue = null;
}
this.cached = true;
}
}
}
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
}
}
其中第4步是最重點,也是最難得看懂的,如果想要了解這個方法,可以參考大神寫的博客:Spring IoC:createBean 詳解(上),這篇文章從代碼塊9開始講的就是這個方法,反正我是看懵逼了,有興趣的可以看看,到這裏關於@Autowired源碼就介紹完了。
下面我們來看一下CommonAnnotationBeanPostProcessor的postProcessProperties方法。
代碼塊8.CommonAnnotationBeanPostProcessor#postProcessProperties方法
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
//1.獲取這個類中所有標註了@Resource的屬性和方法,並把它們封裝在InjectionMetadata對象中
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
//2.完成bean的屬性注入
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
}
return pvs;
}
CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor的postProcessProperties方法基本一樣。
第1步,解析出所有標註了@Resource的屬性和方法,並把它們封裝在InjectionMetadata對象中,具體看代碼塊9。
第2步,完成bean的屬性注入,具體看代碼塊13.
代碼塊9.CommonAnnotationBeanPostProcessor#findResourceMetadata方法
private InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
// Fall back to class name as cache key, for backwards compatibility with custom callers.
//1.得到bean的名稱
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// Quick check on the concurrent map first, with minimal locking.
//2.先從緩存中獲取已經解析過的類,在完成對一個類的解析之後,會進行緩存,第二次就不用在去解析了
InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
//3.判斷是否刷新
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
//4.加鎖
synchronized (this.injectionMetadataCache) {
//5.再次從緩存中獲取解析之後的類
metadata = this.injectionMetadataCache.get(cacheKey);
if (InjectionMetadata.needsRefresh(metadata, clazz)) {
if (metadata != null) {
metadata.clear(pvs);
}
//6.完成對類的解析,獲取所有的標註了@Resource的屬性和方法
metadata = buildResourceMetadata(clazz);
//7.放入到緩存中
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
這個方法和AutowiredAnnotationBeanPostProcessor的一樣就不多介紹,關鍵看一下第6步,進行解析@Resource註解,解析的時候就不一樣了,具體看代碼塊10。
代碼塊10.CommonAnnotationBeanPostProcessor#buildResourceMetadata方法
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
//1.解析標註了@Resource註解的屬性,
ReflectionUtils.doWithLocalFields(targetClass, field -> {
//2.判斷是否標註了@WebServiceRef註解,這個沒看
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static fields");
}
currElements.add(new WebServiceRefElement(field, field, null));
}
//3.判斷是否標註了@EJB註解,這個沒看
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static fields");
}
currElements.add(new EjbRefElement(field, field, null));
}
//4.判斷是否標註了@Resource註解,
else if (field.isAnnotationPresent(Resource.class)) {
//5.@Resource註解如果標註在static修飾的屬性上,直接報錯,不知道上面你是否記得@Autowired是怎麼處理static修飾的屬性的
//忘記的翻看上文代碼
if (Modifier.isStatic(field.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static fields");
}
//6.判斷是否是需要被忽略的類型
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
//7.解析標註了@Resource註解的方法
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
if (method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (webServiceRefClass != null && bridgedMethod.isAnnotationPresent(webServiceRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@WebServiceRef annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@WebServiceRef annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@EJB annotation is not supported on static methods");
}
if (method.getParameterCount() != 1) {
throw new IllegalStateException("@EJB annotation requires a single-arg method: " + method);
}
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
//8.判斷方法上是否標註了@Resource註解
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
//9.@Resource註解如果標註在static修飾的方法上,直接報錯,
if (Modifier.isStatic(method.getModifiers())) {
throw new IllegalStateException("@Resource annotation is not supported on static methods");
}
//10.獲取其@Resource標註方法的形參列表
Class<?>[] paramTypes = method.getParameterTypes();
//11.如果不是1個就報錯,這Spring對於@Resource要求的真實苛刻啊,兩個爲啥不行呢,我是不知道的
//有知道的可以告訴我一聲,我猜是鼓勵大家用SPring自家的註解
if (paramTypes.length != 1) {
throw new IllegalStateException("@Resource annotation requires a single-arg method: " + method);
}
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
elements.addAll(0, currElements);
//12.遞歸解析父類的@Resource註解
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
到這裏我們已經知道了:
一:使用@Resource時,如果是static則直接報錯,使用@Autowired則不會。
二:使用@Resource標註在方法上面時,方法的參數只能有一個,沒有或多個參數則直接報錯,使用@Autowired則沒有限制。
在第6步,會判斷是否是被忽略的類型,如果不是,則添加到集合中,我們看一下ResourceElement類是如何實現的,看代碼塊11
代碼塊11.CommonAnnotationBeanPostProcessor類的內部類ResourceElement
/**
* Class representing injection information about an annotated field
* or setter method, supporting the @Resource annotation.
*/
private class ResourceElement extends LookupElement {
private final boolean lazyLookup;
public ResourceElement(Member member, AnnotatedElement ae, @Nullable PropertyDescriptor pd) {
super(member, pd);
//1.從屬性中面獲取@Resource註解
Resource resource = ae.getAnnotation(Resource.class);
//2.獲取@Resource註解上面name屬性的值
String resourceName = resource.name();
//3.獲取@Resource註解上面type屬性的值
Class<?> resourceType = resource.type();
//4.如果@Resource註解name屬性值爲空,則isDefaultName爲ture,就會使用默認的名稱
this.isDefaultName = !StringUtils.hasLength(resourceName);
if (this.isDefaultName) {
//5.如果使用了默認名稱的話,就會使用標註了@Resource註解屬性的名稱
resourceName = this.member.getName();
//6.如果標註了@Resource註解的是方法,那麼就是判斷是否是以set開頭的
if (this.member instanceof Method && resourceName.startsWith("set") && resourceName.length() > 3) {
//7.如果是以set開頭長度大於3則將set去除,並把首字母變成小寫
resourceName = Introspector.decapitalize(resourceName.substring(3));
}
}
else if (embeddedValueResolver != null) {
resourceName = embeddedValueResolver.resolveStringValue(resourceName);
}
//8.檢查在@Resource註解中設置的屬性和和標註了@Resource註解的屬性類型是否是一致的
if (Object.class != resourceType) {
checkResourceType(resourceType);
}
else {
// No resource type specified... check field/method.
//9.沒用設置的的話,使用@Resource註解的屬性類型
resourceType = getResourceType();
}
this.name = (resourceName != null ? resourceName : "");
this.lookupType = resourceType;
String lookupValue = resource.lookup();
this.mappedName = (StringUtils.hasLength(lookupValue) ? lookupValue : resource.mappedName());
//10.判斷是否爲懶加載的
Lazy lazy = ae.getAnnotation(Lazy.class);
this.lazyLookup = (lazy != null && lazy.value());
}
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
}
這個類主要是用來解析@Resource註解的,因爲@Resource註解有很多屬性,具體看代碼塊12
代碼塊12.@Resource註解
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
enum AuthenticationType {
CONTAINER,
APPLICATION
}
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
}
代碼塊12是爲了讓你更好的理解代碼塊11,這兩個要結合着看。
代碼塊13.InjectionMetadata#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);
//1.判斷類中標註了@Resource註解的集合是否爲空
if (!elementsToIterate.isEmpty()) {
for (InjectedElement element : elementsToIterate) {
//2.不爲空,則進行處理
element.inject(target, beanName, pvs);
}
}
}
第2步會遍歷類中所有加了@Resource註解的屬性和方法,然後對每個完成依賴注入,具體看代碼14
代碼塊14.InjectionMetadata類的內部類InjectedElement#inject方法
/**
* Either this or {@link #getResourceToInject} needs to be overridden.
*/
protected void inject(Object target, @Nullable String requestingBeanName, @Nullable PropertyValues pvs)
throws Throwable {
//1.判斷是屬性還是方法
if (this.isField) {
Field field = (Field) this.member;
ReflectionUtils.makeAccessible(field);
//2.getResourceToInject方法會依賴項的查找
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();
}
}
}
重點關注屬性的依賴注入,對於方法的和屬性的差不多,這裏不做過多介紹,在第2步會查找並注入依賴項,具體看代碼塊15.
代碼塊15.CommonAnnotationBeanPostProcessor類的內部類ResourceElement#getResourceToInject方法
@Override
protected Object getResourceToInject(Object target, @Nullable String requestingBeanName) {
return (this.lazyLookup ? buildLazyResourceProxy(this, requestingBeanName) :
getResource(this, requestingBeanName));
}
判斷是否爲懶加載,如果是則進行懶加載,懶加載會返回一個代理的類用來替代,只有在使用到這個屬性的時候纔回去加載,如果不是懶加載,則調用getResource方法獲取依賴項,具體看代碼塊16.
代碼塊16.CommonAnnotationBeanPostProcessor#getResource方法
protected Object getResource(LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
//這個mappedName沒有研究
if (StringUtils.hasLength(element.mappedName)) {
return this.jndiFactory.getBean(element.mappedName, element.lookupType);
}
if (this.alwaysUseJndiLookup) {
return this.jndiFactory.getBean(element.name, element.lookupType);
}
//1.完成依賴注入
return autowireResource(this.resourceFactory, element, requestingBeanName);
}
在第1步中會完成依賴注入,看代碼塊17
代碼塊17.CommonAnnotationBeanPostProcessor#autowireResource方法
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set<String> autowiredBeanNames;
//1.獲取名稱,如果在註解內部指定了name屬性,則name就爲執行的name
//如果沒有指定,則會獲取標註了@Resource註解中屬性的名稱
String name = element.name;
if (factory instanceof AutowireCapableBeanFactory) {
AutowireCapableBeanFactory beanFactory = (AutowireCapableBeanFactory) factory;
DependencyDescriptor descriptor = element.getDependencyDescriptor();
//2.fallbackToDefaultTypeMatch:判斷是否回退到默認類型匹配
//isDefaultName:代碼塊11中進行了說明,如果@Resource註解name屬性有值,則isDefaultName爲false,如果@Resource註解name屬性沒有值,則爲true,
//isDefaultName爲true,element.name是標註了@Resource註解中屬性的名稱
//查看工廠中是否包含該名稱的bean
if (this.fallbackToDefaultTypeMatch && element.isDefaultName && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
//3.resolveDependency方法在代碼塊7中介紹了,如果走這個,是和@Autowired註解一樣
resource = beanFactory.resolveDependency(descriptor, requestingBeanName, autowiredBeanNames, null);
if (resource == null) {
throw new NoSuchBeanDefinitionException(element.getLookupType(), "No resolvable resource object");
}
}
else {
//4.根據名稱去查找bean
resource = beanFactory.resolveBeanByName(name, descriptor);
autowiredBeanNames = Collections.singleton(name);
}
}
else {
resource = factory.getBean(name, element.lookupType);
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
for (String autowiredBeanName : autowiredBeanNames) {
if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
在第二步中,比較繞,我們舉例說明:
@Resource
private String student;
//因爲此時@Resource註解中name屬性爲空,
//所以:element.isDefaultName = true
//element.name = student
@Resource(name = "student1")
private String student2;
//因爲此時@Resource註解中name屬性有值,
//所以:element.isDefaultName = false
//element.name = student1,即@Resource內部指定的
根據第二步我們知道,如果@Resource想要像@Autowired一樣,使用類型進行匹配,需要滿足一下條件,是都需要滿足的
1.@Resource註解中name屬性沒有進行設置
2.第一條滿足之後,會查看標註了@Resource屬性的名稱在容器在容器中不存在,什麼意思?比如
@Resource
private String student2;
id爲student2的bean在容器中不存在。
只有上面兩條同時存在,則會和@Autowired走一樣的邏輯。
未完待續......