上篇文章,我在開頭将bean執行個體化過程比喻成寒武紀生命大爆發。如果你同意這個看法的話,那本文解析的bean的依賴注入就是生命的形式生物從兩栖進化到爬行,從爬行進化到哺乳,從哺乳進化到類人猿,從低等進化到高等的過程。
本文撰寫累計時常10小時,建議閱讀時間5小時。去趟衛生間,等你回來我們就開始吧。
目錄
1. applyMergedBeanDefinitionPostProcessors
1.1 CommonAnnotationBeanPostProcessor
1.2 AutowiredAnnotationBeanPostProcessor
2. populateBean
3. postProcessProperties方法
3.1 CommonAnnotationBeanPostProcessor方法的inject
3.1.1 doResolveDependency
3.1.2 String類型的依賴注入
3.1.3 普通類型的依賴注入
3.2 AutowiredAnnotationBeanPostProcessor方法的inject
4. 構造函數注入
5. 附錄:本項目工程檔案
上一篇文章,已經詳細分析了bean的執行個體化過程。也就是doCreatBean方法中instanceWrapper = createBeanInstance(beanName, mbd, args);執行完成,将執行個體化後的bean封裝在了wrapper中。随後再解封出來bean對象和bean對應的類型。接下來調用applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);方法。
1. applyMergedBeanDefinitionPostProcessors
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 從BeanWrapper獲得封裝在它内部的bean和bean類型
final Object bean = instanceWrapper.getWrappedInstance();
Class<?> beanType = instanceWrapper.getWrappedClass();
if (beanType != NullBean.class) {
mbd.resolvedTargetType = beanType;
}
// 調用實作了MergedBeanDefinitionPostProcessor的bean後置處理器的postProcessMergedBeanDefinition方法。
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new xxx;
}
// 标記該bd已經合并處理完成了
mbd.postProcessed = true;
}
}
// 加入到bean工廠的earlySingletonObjects中,這個是Spring用來解決循環依賴的憑據(後續文章單獨介紹循環依賴)
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
}
Object exposedObject = bean;
try {
// 依賴注入填充屬性
populateBean(beanName, mbd, instanceWrapper);
// bean屬性填充完成後,就可以進行bean的初始化工作了。依賴注入初始化工作後續文章再詳細介紹。
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
catch (Throwable ex) {
throw new xxx;
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
if (earlySingletonReference != null) {
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
String[] dependentBeans = getDependentBeans(beanName);
Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
if (!actualDependentBeans.isEmpty()) {
throw new xxx;
}
}
}
}
// 注冊實作了DisposableBean接口的bean,該bean實作了void destroy()接口,在bean的生命周期銷毀前可以觸發回調進行善後工作。
// 需要注意的是,它對原型對象無效。
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new xxx;
}
return exposedObject;
}
調用實作了MergedBeanDefinitionPostProcessor的bean後置處理器的postProcessMergedBeanDefinition方法,其中有用到的後置處理器是CommonAnnotationBeanPostProcessor, AutowiredAnnotationBeanPostProcessor, ApplicationListenerDetector。
1.1 CommonAnnotationBeanPostProcessor
CommonAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法如下:
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);
// 解析bean屬性上@Resource的注解,将其封裝為metadata對象并緩存
InjectionMetadata metadata = findResourceMetadata(beanName, beanType, null);
// 對注入的metadata對象進行檢查,沒有注冊的bd需要進行注冊。最後添加到metadata對象的checkedElements集合中。
metadata.checkConfigMembers(beanDefinition);
}
super.postProcessMergedBeanDefinition(beanDefinition, beanType, beanName);中處理@PostConstruct 和 @PreDestroy方法添加到InitDestroyAnnotationBeanPostProcessor的lifecycleMetadataCache這個CurrentHashMap中,該map中的存放的結果是<Class<?>, LifecycleMetadata>。LifecycleMetadata對象中封裝了initMethods和destroyMethods方法,與之對應的是@PostConstruct 和 @PreDestroy注解的兩類方法。通過class類名就能得到該聲明周期回調對象。
metadata.checkConfigMembers(beanDefinition);對注入的medadata對象進行檢查,沒有注冊的bd需要進行注冊。最後添加到metadata對象的checkedElements集合中。
核心代碼是findResourceMetadata(beanName, beanType, null);
InjectionMetadata findResourceMetadata(String beanName, final Class<?> clazz, @Nullable PropertyValues pvs) {
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 緩存中如果沒有,則建立一個metadata
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 = buildResourceMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
它的核心是buildResourceMetadata(clazz);它會沿着類及其父類解析出添加了@WebServiceRef, @EJB, @Resource注解的屬性和方法,将其加入到elements中。然後将clazz和elements封裝成一個InjectionMetadata對象findResourceMetadata方法。findResourceMetadata會将metadata對象緩存在commonAnnotationBeanPostProcessor後置處理器對象的injectionMetadataCache map中友善後續流程使用。
private InjectionMetadata buildResourceMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
// 沿着class的繼承路徑,按層次尋找加上了@WebServiceRef, @EJB, @Resource注解的屬性和方法,将其加入到currElements中。
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 周遊Class中的所有field,判斷每個field是否需要被注入
// 如果上述注解加在靜态類,靜态方法,會直接報錯!
ReflectionUtils.doWithLocalFields(targetClass, field -> {
if (webServiceRefClass != null && field.isAnnotationPresent(webServiceRefClass)) {
currElements.add(new WebServiceRefElement(field, field, null));
}
else if (ejbRefClass != null && field.isAnnotationPresent(ejbRefClass)) {
currElements.add(new EjbRefElement(field, field, null));
}
else if (field.isAnnotationPresent(Resource.class)) {
if (!this.ignoredResourceTypes.contains(field.getType().getName())) {
currElements.add(new ResourceElement(field, field, null));
}
}
});
// 周遊Class中的所有method,判斷每個method是否需要依賴項
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)) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new WebServiceRefElement(method, bridgedMethod, pd));
}
else if (ejbRefClass != null && bridgedMethod.isAnnotationPresent(ejbRefClass)) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new EjbRefElement(method, bridgedMethod, pd));
}
else if (bridgedMethod.isAnnotationPresent(Resource.class)) {
if (!this.ignoredResourceTypes.contains(paramTypes[0].getName())) {
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
//new的是一個ResourceElement執行個體,它是InjectionMetadata.InjectedElement的子類
currElements.add(new ResourceElement(method, bridgedMethod, pd));
}
}
}
});
// 将上面找到的currElements添加到elements中。
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
1.2 AutowiredAnnotationBeanPostProcessor
AutowiredAnnotationBeanPostProcessor的postProcessMergedBeanDefinition方法如下,核心方法是findAutowiringMetadata。
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
// 緩存中如果沒有,則建立一個metadata
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;
}
與findResourceMetadata中核心方法是是調用buildResourceMetadata類似,在findAutowiringMetadata中核心方法是調用buildAutowiringMetadata。最終也會将需要注入的屬性或方法添加到elements中。并且傳回封裝好的metadata對象。上層也會将其緩存到injectionMetadataCache中。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
// 周遊Class中的所有field,根據注解判斷每個field是否需要被注入
ReflectionUtils.doWithLocalFields(targetClass, field -> {
// 看看field是不是@Autowired 或 @Value
AnnotationAttributes ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
// 不支援靜态類,直接傳回。
return;
}
//确定帶注釋的字段或方法是否需要依賴項。
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
// 周遊Class中的所有method,根據注解判斷每個method是否需要依賴項
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())) {
//不支援靜态方法,直接傳回。
return;
}
//确定帶注釋的字段或方法是否需要依賴項。
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
// new一個AutowiredMethodElement類,它是InjectionMetadata.InjectedElement的子類
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return new InjectionMetadata(clazz, elements);
}
ApplicationListenerDetector很簡單,将beanName和是否是singleton的boolean變量放到ApplicationListenerDetector對象的Map<String, Boolean> singletonNames中。這裡就不再展開分析了。到此applyMergedBeanDefinitionPostProcessors步驟執行完成。接下來在try{}塊之前的boolean earlySingletonExposure....相關代碼是用于處理循環依賴的代碼。本篇文章暫時跳過,後續專門介紹循環依賴再詳細分析。
這樣就到了今天的重頭戲——populateBean(beanName, mbd, instanceWrapper);的分析了。該步驟是Spring進行依賴注入的入口,也就是屬性填充的地方。
2. populateBean
populate是“落戶于...”的意思。Spring的開發者用這個詞拟人化後非常貼切且讓人感慨!下面我們就開始分析依賴注入的流程。
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
// 如果對象為null,bd也沒有屬性值需要注入,則跳過bean初始化環節直接傳回null。
if (bw == null) {
if (mbd.hasPropertyValues()) {
throw xxx;
}
else {
return;
}
}
boolean continueWithPropertyPopulation = true;
// 周遊繼承了InstantiationAwareBeanPostProcessor的僅有:ImportAwareBeanPostProcessor,CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
// 如果使用者自定義的類中postProcessAfterInstantiation方法傳回false,那麼依賴注入流程就提前結束
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
continueWithPropertyPopulation = false;
break;
}
}
}
}
if (!continueWithPropertyPopulation) {
return;
}
// 看看bd中是否有緩存的值,沒有就是null
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
// 預設是AUTOWIRE_NO。 約定優于配置!
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME || mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_NAME) {
autowireByName(beanName, mbd, bw, newPvs);
}
if (mbd.getResolvedAutowireMode() == AUTOWIRE_BY_TYPE) {
autowireByType(beanName, mbd, bw, newPvs);
}
pvs = newPvs;
}
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
// 擷取屬性值
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
// ConfigurationClassPostProcessor$ImportAwareBeanPostProcessor
// CommonAnnotationBeanPostProcessor
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
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;
}
}
}
if (needsDepCheck) {
if (filteredPds == null) {
filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
}
checkDependencies(beanName, mbd, filteredPds, pvs);
}
if (pvs != null) {
//應用給定的屬性值,解析此bean工廠中對其他bean的任何運作時引用。
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
首先,如果傳入的beanWrap對象為null,而bd還有需要注入的屬性值。巧婦難為無米之炊,沒辦法,隻要抛出異常。接着周遊實作了InstantiationAwareBeanPostProcessor接口的後置處理器,調用其postProcessAfterInstantiation方法。該方法會傳回boolean變量,目前Spring内部使用的三個類ImportAwareBeanPostProcessor,CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor都是傳回的false。如果使用者自定義實作了InstantiationAwareBeanPostProcessor類,并将postProcessAfterInstantiation方法的傳回值寫為false。那麼就會導緻continueWithPropertyPopulation的值改為false。bean的依賴注入就提前結束了。
接下來一直到for循環之前的代碼并不重要。核心的代碼是PropertyValues pvsToUse = ibp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);這裡是周遊bean後置處理器,調用它們的postProcessProperties方法執行屬性填充。
3. postProcessProperties方法
在上面循環中,postProcessProperties方法被調用的處理器主要有兩個:CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor。前者處理@Resource注解,後者處理@Autowired注解。
CommonAnnotationBeanPostProcessor和AutowiredAnnotationBeanPostProcessor中的postProcessProperties方法
// CommonAnnotationBeanPostProcessor的postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
// metadata ==null 或者 clazz不等于metadata中存放的目标class,就需要重新建構metadata。
InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (Throwable ex) {
throw 注入失敗!
}
return pvs;
}
// AutowiredAnnotationBeanPostProcessor的postProcessProperties
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
try {
metadata.inject(bean, beanName, pvs);
}
catch (Exception ex) {
throw xxx;
}
return pvs;
}
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);
}
}
}
首先執行findXXXMetadata(beanName, bean.getClass(), pvs);方法獲得metadata對象。這個對象首先從緩存擷取,如果緩存中沒有就立即建立一個新的metadata對象傳回。一般來說在之前的applyMergedBeanDefinitionPostProcessors步驟已經緩存好了metadata對象,是以這裡都能拿到。接下來都是調用的InjectionMetadata的inject方法。該方法會周遊metadata内所有緩存好的InjectedElement對象,即第1節中解析出來的注解屬性或方法。然後調用element.inject(target, beanName, pvs)方法,就會分别調用了各自後置處理器中繼承了InjectionMetadata.InjectedElement私有的内部類的inject方法實作多态。
3.1 CommonAnnotationBeanPostProcessor方法的inject
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);核心反複
//核心方法是調用getResourceToInject方法
method.invoke(target, getResourceToInject(target, requestingBeanName));
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
if分支是通過field注入,else是通過方法注入。它們均是通過getResourceToInject(target, requestingBeanName)尋找依賴項,通過一系列的空殼方法調用後,最終會調用CommonAnnotationBeanPostProcessor的autowireResource方法。
protected Object autowireResource(BeanFactory factory, LookupElement element, @Nullable String requestingBeanName)
throws NoSuchBeanDefinitionException {
Object resource;
Set<String> autowiredBeanNames;
// 屬性名
String name = element.name;
if (this.fallbackToDefaultTypeMatch && element.isDefaultName &&
factory instanceof AutowireCapableBeanFactory && !factory.containsBean(name)) {
autowiredBeanNames = new LinkedHashSet<>();
// 核心是執行resolveDependency中的doResolveDependency方法獲得對象
resource = ((AutowireCapableBeanFactory) factory).resolveDependency(
element.getDependencyDescriptor(), requestingBeanName, autowiredBeanNames, null);
}
else {
// 去bean工廠中擷取名字為name的bean, 類型是element.lookupType類型
resource = factory.getBean(name, element.lookupType);
// 得到bean工廠中的
autowiredBeanNames = Collections.singleton(name);
}
if (factory instanceof ConfigurableBeanFactory) {
ConfigurableBeanFactory beanFactory = (ConfigurableBeanFactory) factory;
for (String autowiredBeanName : autowiredBeanNames) {
// requestingBeanName是正在初始化的bean, autowiredBeanName是requestingBeanName依賴的屬性。
// 比如:requestingBeanName = "gardenofEden" autowiredBeanName = "xiawa"
if (requestingBeanName != null && beanFactory.containsBean(autowiredBeanName)) {
beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName);
}
}
}
return resource;
}
如果走if分支,核心方法是resolveDependency方法中的DefaultListableBeanFactory的doResolveDependency方法。如果是else分支那麼就直接通過factory.getBean拿到需要注入的屬性對象了。最後beanFactory.registerDependentBean(autowiredBeanName, requestingBeanName)梳理好這些bean的依賴關系後就可以一路傳回注入對象,最終在inject方法中執行field.set(target, getResourceToInject(target, requestingBeanName));完成注冊了。
public void registerDependentBean(String beanName, String dependentBeanName) {
String canonicalName = canonicalName(beanName);
// Map<String, Set<String>> dependentBeanMap中存放的是各個bean的依賴關系。 key是bean的名字。value是一個LinkedHashSet,裡面存放的其他bean的名字,這些bean都要依賴key。
// // 向key為canonicalName的Set中添加dependentBeanName
synchronized (this.dependentBeanMap) {
Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
if (!dependentBeans.add(dependentBeanName)) {
return;
}
}
// 向dependentBeanMap添加<dependentBeanName, Set{canonicalName})>
synchronized (this.dependenciesForBeanMap) {
Set<String> dependenciesForBean =
this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8));
dependenciesForBean.add(canonicalName);
}
}
registerDependentBean方法的作用舉例來說,假如有A, B, C三個bean。 A依賴B,B也依賴A,除此之外C還依賴A, D也依賴A。那麼最終dependentBeanMap中存放的資料結構是:
key:A value:{B, C, D}
key:B value:{A}
dependenciesForBeanMap中存放的資料結構是<被依賴bean, 依賴bean>
key:A value:{B}
key:B value:{A}
key:C value:{A}
key:D value:{A}
了解了autowireResource方法中的各個方法的作用後,我們就可以詳細分析依賴注入的過程了。
3.1.1 doResolveDependency
我們主要分析if分支的流程。普通的Spring流程會由resolveDependency方法會調用doResolveDependency來分類處理注入屬性對象類型是String,普通類對象,其他類型對象(數組,集合,map等類型)的場景。本文主要介紹String類型和普通類這兩種場景,剩下的數組等類型注入過程大同小異,就留給讀者們自行分析了。
public Object doResolveDependency(DependencyDescriptor descriptor, @Nullable String beanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
try {
// 看看有沒有緩存過參數值。
Object shortcut = descriptor.resolveShortcut(this);
if (shortcut != null) {
return shortcut;
}
// 參數值類型
Class<?> type = descriptor.getDependencyType();
// 擷取@Value("${xxx}")注解中的注解參數 ${xxx}
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
if (value != null) {
// String類型的依賴注入
if (value instanceof String) {
// 從配置檔案擷取屬性值
String strVal = resolveEmbeddedValue((String) value);
BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);
// 計算bean定義中包含的給定字元串,可能将其解析為表達式。
value = evaluateBeanDefinitionString(strVal, bd);
}
// 進行必要類型轉換
TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
return (descriptor.getField() != null ?
converter.convertIfNecessary(value, type, descriptor.getField()) :
converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
}
// stream,Array,Collection,Map類型的依賴注入。
Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
if (multipleBeans != null) {
return multipleBeans;
}
// 普通類型的依賴注入
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
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) {
// resolveCandidate中調用的就是beanFactory.getBean(beanName);
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
}
finally{
// 緩存起來
ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
}
}
進入doResolveDependency還是老樣子,首先看看有沒有緩存,有的話就傳回。然後拿到依賴項的類型Class<?> type = descriptor.getDependencyType()。接着執行
Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
這行代碼用于解析@Value注解。它能夠擷取@Value("${xxx}")注解中的注解參數 ${xxx}賦給result。如果result != null,并且它是String類型的話,就是從配置檔案讀取值注入到屬性上了。
3.1.2 String類型的依賴注入
String類型的依賴注入主要是通過解析注解,找到配置檔案中的屬性然後替換placeHolder占位符完成的。它通過String strVal = resolveEmbeddedValue((String) value)這一行代碼幹活。它首先找到之前注冊到bean工廠embeddedValueResolvers中的解析器解析該值。注冊的地方就在執行個體化bean的第一個方法中finishBeanFactoryInitialization中的
if (!beanFactory.hasEmbeddedValueResolver()) {
beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
}
而這個方法又是調用的注冊在Environment對象propertyResolver.resolvePlaceholders(text);該解析器是在容器evnironment對象建立的時候就被注冊上的。最終解析value這個值的方法會交給PropertyPlaceholderHelper的parseStringValue方法來操刀執行。
protected String parseStringValue(
String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
StringBuilder result = new StringBuilder(value);
// 确定 ${ 符号的其實位置,如果不存在就壓根兒不用解析
int startIndex = value.indexOf(this.placeholderPrefix);
while (startIndex != -1) {
int endIndex = findPlaceholderEndIndex(result, startIndex);
if (endIndex != -1) {
// 找到${ 和 }的直接的内容作為placeholder并添加到visitedPlaceholders集合中
String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
String originalPlaceholder = placeholder;
// 嵌套調用本方法,以解決傳入的value中有嵌套的 ${} 如果發現解析的結果與集合中的重複,則抛出異常。
if (!visitedPlaceholders.add(originalPlaceholder)) {
throw new IllegalArgumentException(
"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
}
// Recursive invocation, parsing placeholders contained in the placeholder key.
placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
// 遞歸解析獲得完整的placeholder後,最終通過PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class<T>, boolean)方法讀取propertySources
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
if (propVal == null && this.valueSeparator != null) {
int separatorIndex = placeholder.indexOf(this.valueSeparator);
if (separatorIndex != -1) {
String actualPlaceholder = placeholder.substring(0, separatorIndex);
String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
if (propVal == null) {
propVal = defaultValue;
}
}
}
// 看看擷取到的值是否還有可能被解析,再次遞歸調用parseStringValue方法進行解析。
if (propVal != null) {
propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
// 将result從${xxx} 替換為找到的value值。 比如本項目中是${race},替換為properties檔案中的 "yellow"
result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
}
else if (this.ignoreUnresolvablePlaceholders) {
startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
}
else {
throw new IllegalArgumentException("Could not resolve placeholder '" +
placeholder + "'" + " in value \"" + value + "\"");
}
visitedPlaceholders.remove(originalPlaceholder);
}
else {
startIndex = -1;
}
}
return result.toString();
}
以Human.class中的注解@Value("${race}")為例。首先傳入的value值已經是${race}了,然後确定${race}字元串中通過 "${"和"}"中間的内容作為placeholder。然後再次遞歸調用本方法placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders),目的是怕解析後placeholder中還有嵌套的${xxx}。當placeholder遞歸解析完成後,就可以去配置檔案中尋找placeholder對應的值了。
String propVal = placeholderResolver.resolvePlaceholder(placeholder);
它會通過PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class<T>, boolean)方法讀取propertySources,最終将placeholder作為key在以下檔案中去尋找所對應的值。resolvePlaceholder方法也是有可能進行遞歸解析的,因為在配置檔案中有可能存在一些特殊的分隔符或者存放的值本身就是${xxx}這種placeholder,那麼讀取出的配置值propVal也可能需要進行遞歸解析。
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
Object value = propertySource.getProperty(key);
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
// 将得到的值value轉換成上層需要的類型targetValueType傳回
return convertValueIfNecessary(value, targetValueType);
}
}
}
return null;
}
this.propertySources中的值是:
systemProperties
systemEnvironment
class path resource 也就是 [application.properties]
最終,result中的值被從配置檔案中讀取出的值替代,然後一路傳回到上層doResolveDependency中的String strVal = resolveEmbeddedValue((String) value);然後進行bd合并和必要的類型轉換後放回上層。最終傳回到inject方法中,作為set函數的第二個入參完成對目标屬性的注入。
field.set(target, getResourceToInject(target, requestingBeanName));
3.1.3 普通類型的依賴注入
普通類型的依賴注入對象首先根據要注入的屬性類型尋找到一批候選的bean,然後再确定這批bean中最适合的那一個bean然後裝配上。doResolveDependency方法中Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor)就是在尋找符合注入屬性類型的bean。
protected Map<String, Object> findAutowireCandidates(
@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {
// 擷取給定類型的所有bean名
String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this, requiredType, true, descriptor.isEager());
Map<String, Object> result = new LinkedHashMap<>(candidateNames.length);
// 如果實作了這幾個接口的某個,就将其加入到result中。
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;
}
}
}
// 将符合要求的candidate放入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) {
for (String candidate : candidateNames) {
if (isSelfReference(beanName, candidate) &&
(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
isAutowireCandidate(candidate, fallbackDescriptor)) {
addCandidateEntry(result, candidate, descriptor, requiredType);
}
}
}
}
return result;
}
1.首先擷取出所有實作了注入屬性類型的beanName放入String[] candidateNames中。
2.如果注入的類似屬于以下4種中的某一個類型,比如BeanFactory,那麼就将實作了beanFactory的那個對象加入result。
interface org.springframework.context.ApplicationEventPublisher
interface org.springframework.core.io.ResourceLoader
interface org.springframework.context.ApplicationContext
interface org.springframework.beans.factory.BeanFactory
3.将candidateNames中滿足要求的bean加入到result中。如果該bean還未執行個體化,那麼還要通過addCandidateEntry方法中的descriptor.resolveCandidate(candidateName, requiredType, this)方法調用beanFactory.getBean(beanName)或getType(candidateName)
執行個體化對應的bean才行。(代碼很簡單,就不再占用篇幅了)
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) throws BeansException {
return beanFactory.getBean(beanName);
}
4.如果是數組、集合類的候選對象也加入到result。
最後收集完result傳回doResolveDependency的Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);完成該方法的執行。如果沒有找到與注入類型比對的bean,那麼就傳回null。
/* * * * * * * * * * * * * * * * * *
* doResolveDependency方法的代碼片段 *
* * * * * * * * * * * * * * * * * */
Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
if (matchingBeans.isEmpty()) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
return null;
}
String autowiredBeanName;
Object instanceCandidate;
if (matchingBeans.size() > 1) {
autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
if (autowiredBeanName == null) {
if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
return descriptor.resolveNotUnique(descriptor.getResolvableType(), matchingBeans);
}
else {
return null;
}
}
instanceCandidate = matchingBeans.get(autowiredBeanName);
}
else {
// We have exactly one match.
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) {
// resolveCandidate中調用的就是beanFactory.getBean(beanName);
instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
}
Object result = instanceCandidate;
if (result instanceof NullBean) {
if (isRequired(descriptor)) {
raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
}
result = null;
}
if (!ClassUtils.isAssignableValue(type, result)) {
throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
}
return result;
如果找到的matchingBeans不止一個,那還要通過determineAutowireCandidate方法去看看@Primary和@Priority注解,最終确定好優先級順序後傳回優先級最高的作為注入的bean。如果優先級相同(沒有上述2個注解視為優先級相同),那麼再最後通過名稱看看候選名稱是否與此bean定義中存儲的bean名稱或别名比對。如果還沒有找到唯一的候選對象,那麼就抛出NoUniqueBeanDefinitionException異常,構造和處理方法詳情可查閱《關于Spring自動裝配幾個你所不知道的事》。
protected boolean matchesBeanName(String beanName, @Nullable String candidateName) {
return (candidateName != null &&
(candidateName.equals(beanName) || ObjectUtils.containsElement(getAliases(beanName), candidateName)));
}
如果剛好隻有一個那就再好不過了,直接擷取到instanceCandidate然後傳回上層。最後傳回到inject方法field.set(target, getResourceToInject(target, requestingBeanName))完成屬性field的注入。
3.2 AutowiredAnnotationBeanPostProcessor方法的inject
protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
Field field = (Field) this.member;
Object value;
if (this.cached) {
value = resolvedCachedArgument(beanName, this.cachedFieldValue);
}
else {
// 建立一個屬于field的依賴描述器
DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
desc.setContainingClass(bean.getClass());
Set<String> autowiredBeanNames = new LinkedHashSet<>(1);
TypeConverter typeConverter = beanFactory.getTypeConverter();
//獲得依賴值
value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
// 更新全局的dependentBeanMap和dependenciesForBeanMap,該緩存的容器就更新緩存并且緩存過後将this.cached = true, this.cachedFieldValue賦上包裝對象友善後續使用。
synchronized (this) {
if (!this.cached) {
if (value != null || this.required) {
this.cachedFieldValue = desc;
registerDependentBeans(beanName, autowiredBeanNames);
if (autowiredBeanNames.size() == 1) {
String autowiredBeanName = autowiredBeanNames.iterator().next();
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);
}
}
}
首先看看參數是否緩存,如果緩存就傳回緩存在本AutowiredFieldElement中的參數值cachedFieldValue,如果這個Element對象繼承了DependencyDescriptor接口,那麼就通過beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter)方法獲得注入對象。該方法的詳細過程已經在3.1.1 doResolveDependency節講述,這裡不再贅述。
private Object resolvedCachedArgument(@Nullable String beanName, @Nullable Object cachedArgument) {
if (cachedArgument instanceof DependencyDescriptor) {
DependencyDescriptor descriptor = (DependencyDescriptor) cachedArgument;
Assert.state(this.beanFactory != null, "No BeanFactory available");
// 内部還是會調用DefaultListableBeanFactory#doResolveDependency的方法獲得注入的依賴對象
return this.beanFactory.resolveDependency(descriptor, beanName, null, null);
}
else {
// 直接傳回緩存的參數值
return cachedArgument;
}
}
如果沒有緩存對象,在try塊中也通過value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);擷取注入對象。該方法的詳細過程也已經在3.1.1 doResolveDependency節講述,這裡不再贅述。擷取完注入對象後,在synchronized塊中更新全局的dependentBeanMap和dependenciesForBeanMap,該緩存的容器就更新緩存并且緩存過後将this.cached = true, this.cachedFieldValue賦上包裝對象友善後續使用。最後将value注入到bean的對應屬性上。
if (value != null) {
ReflectionUtils.makeAccessible(field);
field.set(bean, value);
}
4. 構造函數注入
上一篇文章留了一點懸念——帶參構造函數在執行個體化bean時,入參的依賴注入是什麼時候發生的呢?我們現在來解答。
在autowireConstructor方法長長的for{...}循環中,有如下一段代碼(有精簡)。構造參數argsHolder是通過createArgumentArray方法得到的。
ArgumentsHolder argsHolder;
if (resolvedValues != null) {
String[] paramNames = ConstructorPropertiesChecker.evaluate(candidate, paramTypes.length);
if (paramNames == null) {
ParameterNameDiscoverer pnd = this.beanFactory.getParameterNameDiscoverer();
if (pnd != null) {
paramNames = pnd.getParameterNames(candidate);
}
}
argsHolder = createArgumentArray(beanName, mbd, resolvedValues, bw, paramTypes, paramNames,
getUserDeclaredConstructor(candidate), autowiring, candidates.length == 1);
}
createArgumentArray方法如下,重要的代碼是Object autowiredArgument = resolveAutowiredArgument(methodParam, beanName, autowiredBeanNames, converter, fallback);方法。在它内部也是調用beanFactory的resolveDependency方法擷取依賴注入對象的(上文已經詳細分析)。
private ArgumentsHolder createArgumentArray(
String beanName, RootBeanDefinition mbd, @Nullable ConstructorArgumentValues resolvedValues,
BeanWrapper bw, Class<?>[] paramTypes, @Nullable String[] paramNames, Executable executable,
boolean autowiring, boolean fallback) throws UnsatisfiedDependencyException {
TypeConverter customConverter = this.beanFactory.getCustomTypeConverter();
TypeConverter converter = (customConverter != null ? customConverter : bw);
ArgumentsHolder args = new ArgumentsHolder(paramTypes.length);
Set<ConstructorArgumentValues.ValueHolder> usedValueHolders = new HashSet<>(paramTypes.length);
Set<String> autowiredBeanNames = new LinkedHashSet<>(4);
// 周遊所有需要注入的入參對象
for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
Class<?> paramType = paramTypes[paramIndex];
// paramName是null的替換為""
String paramName = (paramNames != null ? paramNames[paramIndex] : "");
ConstructorArgumentValues.ValueHolder valueHolder = null;
if (resolvedValues != null) {
// 查找一個參數值,該值要麼對應于構造函數參數清單中的給定索引,要麼按類型進行一般比對。
valueHolder = resolvedValues.getArgumentValue(paramIndex, paramType, paramName, usedValueHolders);
// 如果找不到直接比對且不打算自動連接配接,那麼讓我們嘗試下一個泛型的、無類型的參數值作為回退:它可以在類型轉換之後比對(例如,String -> int)。
if (valueHolder == null && (!autowiring || paramTypes.length == resolvedValues.getArgumentCount())) {
// 查找與給定類型比對的下一個泛型參數值,忽略目前解析過程中已經使用的參數值。
valueHolder = resolvedValues.getGenericArgumentValue(null, null, usedValueHolders);
}
}
if (valueHolder != null) {
// 如果不為null,就作為候選項
usedValueHolders.add(valueHolder);
Object originalValue = valueHolder.getValue();
Object convertedValue;
if (valueHolder.isConverted()) {
convertedValue = valueHolder.getConvertedValue();
args.preparedArguments[paramIndex] = convertedValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
convertedValue = converter.convertIfNecessary(originalValue, paramType, methodParam);
Object sourceHolder = valueHolder.getSource();
if (sourceHolder instanceof ConstructorArgumentValues.ValueHolder) {
Object sourceValue = ((ConstructorArgumentValues.ValueHolder) sourceHolder).getValue();
args.resolveNecessary = true;
args.preparedArguments[paramIndex] = sourceValue;
}
}
args.arguments[paramIndex] = convertedValue;
args.rawArguments[paramIndex] = originalValue;
}
else {
MethodParameter methodParam = MethodParameter.forExecutable(executable, paramIndex);
// 上面沒有找到比對項。那麼就在這裡嘗試做依賴注入
Object autowiredArgument = resolveAutowiredArgument(
methodParam, beanName, autowiredBeanNames, converter, fallback);
args.rawArguments[paramIndex] = autowiredArgument;
args.arguments[paramIndex] = autowiredArgument;
args.preparedArguments[paramIndex] = new AutowiredArgumentMarker();
args.resolveNecessary = true;
}
}
for (String autowiredBeanName : autowiredBeanNames) {
this.beanFactory.registerDependentBean(autowiredBeanName, beanName);
}
return args;
}
綜上所述,Spring的依賴注入方法主要是依靠DefaultListableBeanFactory的resolveDependency方法來完成的。它調用内部的doResolveDependency方法,對String類型,普通類型,數組集合等類型進行了分類處理。Spring類型通過讀取配置檔案完成屬性的注入,普通類型通過bean工廠的getBean方法擷取(建立)緩存在bean工廠中的bean對象完成對應類型屬性的依賴注入。到此Spring正常的IOC流程就幾乎完成了。唯一剩下循環依賴的問題,我們下篇文章再重點分析這個棘手的問題,看看Spring是如何巧妙化解的。
依賴注入完成,标志着bean的建立過程進行了一半。時間也就從上一節的05:00來到06:00。遠方的地平線上,啟明星的光線已經劃破了黑色的幕布,耀眼奪目。也許你不知道,它真正的名字叫做——金星!
5. 附錄:本項目工程檔案
工程目錄和檔案:
@Component("yadang")
public class Adam {
private String name;
@Autowired
private Eve eve;
@PostConstruct
private void init(){
name = "Adam";
}
public void sayHello(){
System.out.println("你好,我是" + name + ". 我愛" + eve.getName());
}
public String getName() {
return name;
}
}
@Component("xiawa")
public class Eve {
private String name;
@Autowired
private Adam adam;
@PostConstruct
private void init(){
name = "Eve";
}
public void sayHello(){
System.out.println("你好,我是" + name + ". 我愛" + adam.getName());
}
public String getName() {
return name;
}
}
@Component
@PropertySource("classpath:application.properties")
@DependsOn("xiawa")
public class Human {
@Value("${race}")
private String race;
private String nationality;
public Human(@Value("${nationality}") String nationality) {
this.nationality = nationality;
}
public void sayHello(){
System.out.println("大家好,歡迎來到伊甸園");
System.out.println("我們的國籍是:" + nationality);
}
}
public class Apple {}
@Component()
public class AppleFactory implements FactoryBean {
@Override
public Object getObject() throws Exception {
return new Apple();
}
@Override
public Class<?> getObjectType() {
return Apple.class;
}
@Override
public boolean isSingleton() { return false; }
}
@Service
public class GardenofEden {
private String gardenName;
@Autowired
private Adam adam;
@Resource(name = "xiawa")
// @Resource //讀者調試看看與上面使用name屬性有何不同
private Eve eve;
@Autowired
private Human human;
public void sayHello(){
adam.sayHello();
eve.sayHello();
human.sayHello();
}
}
@ComponentScan("com.Hodey")
public class CaseApplication {
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx =
new AnnotationConfigApplicationContext(CaseApplication.class);
GardenofEden garden = ctx.getBean(GardenofEden.class);
garden.sayHello();
Apple apple1 = (Apple) ctx.getBean("appleFactory");
System.out.println(apple1);
Apple apple2 = (Apple) ctx.getBean("appleFactory");
System.out.println(apple2);
}
}
application.properties檔案内容:
server.port=8090
nationality=China
race=yellow
項目最終執行結果:
你好,我是Adam. 我愛Eve
你好,我是Eve. 我愛Adam
大家好,歡迎來到伊甸園
我們的國籍是:China
[email protected]
[email protected]