面試中碰到面試官問:”Spring 註解是如果工作的?“,當前我一驚,完了這不觸及到我的知識誤區了嗎?,還好我機智,靈機一動回了句:Spring 註解的工作流程倒還沒有看到,但是我知道@Autowired
註解的工作流程,後面不用說了一頓巴拉,面試官都連連點頭。
面試中要活用轉移話題,要避免回答 ”不知道“,要引導面試官掉入你擅長的技術,然後才有機會教他作人。
@Autowired 相關的類
@Autowired 註解的主要功能就是完成自動注入,使用也非常簡單(Spring都安排好了),但是要想知道 @Autowired 註解的內部現實,就需要看一下Spring原始碼了。接下來一步步的解剖 @Autowired 的實現原理,首先理一下與 @Autowired 註解相關的類,然後一步步的跟蹤原始碼,直到理解 @Autowired 的原理。
AutowiredAnnotationBeanPostProcessor 類
AutowiredAnnotationBeanPostProcessor
是實現 @Autowired 功能的主要類,它有一些方法是會用解析 @Autowired 註解並實現自動注入的功能,下面是它的繼承圖:
從上圖可以發現 AutowiredAnnotationBeanPostProcessor 最上層是 BeanPostProcessor
是一個後處理器,當然除了後處理器外中間還有InstantiationAwareBeanPostProcessor
和MergedBeanDefinitionPostProcessor
:
InstantiationAwareBeanPostProcessor 介面
postProcessBeforeInstantiation方法
在Bean例項化之前呼叫,可以返回一個Bean例項,預設返回null
。
@Nullabledefault Object postProcessBeforeInstantiation(Class<?> beanClass, String
beanName) throws BeansException { return null;}
postProcessAfterInstantiation方法
在Bean建立完成後,設定屬性之前呼叫。
default boolean postProcessAfterInstantiation(Object bean, String
beanName) throws BeansException { return true;}
postProcessProperties方法
@Nullable default PropertyValues postProcessProperties(PropertyValues pvs, Object
bean, String beanName) throws BeansException { return null;}
Bean建立完後,設定屬性之前呼叫
先記住 InstantiationAwareBeanPostProcessor 介面,後面會跟蹤呼叫它的地方,就很容易理解了。
MergedBeanDefinitionPostProcessor
MergedBeanDefinitionPostProcessor
也是一個繼承 BeanPostProcessor
介面的後處理器,它的主要作用就是可以處理操作BeanDefinition
物件,由於Bean的例項化是通過 BeanDefinition 的, 通過操作BeanDefinition ,這樣可以使Bean的例項化時發生一些變化。
MergedBeanDefinitionPostProcessor 只有兩個方法
postProcessMergedBeanDefinition方法
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
Class<?> beanType, String beanName);
Bean的BeanDefinition 被合併後呼叫此方法。
resetBeanDefinition
default void resetBeanDefinition(String beanName) {}
當一個BeanDefinition被重置後呼叫 。
AutowireCapableBeanFactory 介面
AutowireCapableBeanFactory
繼承自BeanFactory
,除了提供基礎的Bean操作外,從介面的名字就可以推斷出的它還有自動注入
的能力。AutowireCapableBeanFactory 提供四種注入模型:
- AUTOWIRE_NO: 沒有顯示的定義注入模型
- AUTOWIRE_BY_NAME: 通過Bean名稱注入
- AUTOWIRE_BY_TYPE: 通過Bean的型別注入
- AUTOWIRE_CONSTRUCTOR:通過Bean的構造方法注入
AutowireCapableBeanFactory 介面有不少方法,但大部分都是跟自動注入的相關。@Autowired 的主要功能就是在Bean例項化後,為其設定屬性,所以在 AutowireCapableBeanFactory 介面有一個 createBean
方法,用於建立Bean並設定Bean的屬性:
<T> T createBean(Class<T> beanClass) throws BeansException;
createBean
方法,它的呼叫時機是建立Bean的時候,稍後會說到它的呼叫時機。
AbstractAutowireCapableBeanFactory
AbstractAutowireCapableBeanFactory 繼承 AbstractBeanFactory
並實現了AutowireCapableBeanFactory
介面,所以它也實現了AutowireCapableBeanFactory
中的createBean
方法。
public <T> T createBean(Class<T> beanClass) throws BeansException {
// Use prototype bean definition, to avoid registering bean as dependent bean.
RootBeanDefinition bd = new RootBeanDefinition(beanClass);
bd.setScope(SCOPE_PROTOTYPE);
bd.allowCaching = ClassUtils.isCacheSafe(beanClass, getBeanClassLoader());
return (T) createBean(beanClass.getName(), bd, null);}
Bean建立的生命週期
通過了解Bean建立的生命週期,才可以將上面與 @Autowired 相關的類串起來,首先這裡不會過多的介紹Bean的建立細節,只關注自動注入相關的程式碼。
Bean的建立過程
Spring中預設的Bean都是懶載入的,所以一個Bean的建立會從呼叫getBean
方法開始,如果不考慮快取、上層容器的情況,Bean的建立會經過以下方法:
- getBean:BeanFactory的方法,獲取Bean例項
- doGetBean:獲取Bean的例項,獲取順序依次為:單例池、父容器,如果從以上2種途徑都沒獲取到Bean例項就會建立新的
- createBean:建立 Bean,這裡的createBean,跟上面介紹的是一回事
- doCreateBean:建立Bean例項
- populateBean:設定Bean屬性
以上流程中的getBean
和doGetBean
不多作說明了, 重點關注createBean
前面提到AbstractAutowireCapableBeanFactory.createBean
方法,所以說你在呼叫getBean
方法獲取Bean的例項時,如果這個Bean例項還沒有被建立,那麼createBean
就會被呼叫。
通過簡單的說明Bean建立的生命週期,就能找到 @Autowired 註解實現的入口,接下來再繼續跟蹤createBean
方法。
收集註入元資訊
收集註入元資訊的步驟的,其實就是呼叫AutowiredAnnotationBeanPostProcessor
類方法來實現的。
Bean 建立之前
以下是createBean
方法,在Bean建立之前呼叫postProcessBeforeInstantiation
的地方。為是閱讀方便省略了一些程式碼,大致的流程就是:
- 首先呼叫
resolveBeforeInstantiation
方法,執行InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation
方法 - 如果
postProcessBeforeInstantiation
返回Bean例項那麼直接返回這個例項,如果返回nul 繼續呼叫doCreateBean
@Override
protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
...
try {
// Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
...
}
...
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
...
...
}
@Nullable
protected Object resolveBeforeInstantiation(String beanName, RootBeanDefinition mbd) {
Object bean = null;
if (!Boolean.FALSE.equals(mbd.beforeInstantiationResolved)) {
// Make sure bean class is actually resolved at this point.
if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
Class<?> targetType = determineTargetType(beanName, mbd);
if (targetType != null) {
bean = applyBeanPostProcessorsBeforeInstantiation(targetType, beanName);
if (bean != null) {
bean = applyBeanPostProcessorsAfterInitialization(bean, beanName);
}
}
}
mbd.beforeInstantiationResolved = (bean != null);
}
return bean;
}
這裡 AutowiredAnnotationBeanPostProcessor 的 postProcessBeforeInstantiation 的方法會被呼叫,由於AutowiredAnnotationBeanPostProcessor 並沒有重寫這個方法,所以什麼都不做。
操作 BeanDefinition
上面說過 postProcessBeforeInstantiation 方法返回 null 的話會繼續執行doCreateBean
方法:
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
throws BeanCreationException {
// Allow post-processors to modify the merged bean definition.
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
...
populateBean(beanName, mbd, instanceWrapper);
...
在 doCreateBean 方法中,會呼叫呼叫applyMergedBeanDefinitionPostProcessors
方法:
protected void applyMergedBeanDefinitionPostProcessors(RootBeanDefinition mbd, Class<?> beanType, String beanName) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof MergedBeanDefinitionPostProcessor) {
MergedBeanDefinitionPostProcessor bdp = (MergedBeanDefinitionPostProcessor) bp;
bdp.postProcessMergedBeanDefinition(mbd, beanType, beanName);
}
}
MergedBeanDefinitionPostProcessor
介面上面提到到的,AutowiredAnnotationBeanPostProcessor 實現了這個介面所以直接進入到 AutowiredAnnotationBeanPostProcessor 中的 postProcessMergedBeanDefinition
方法:
@Override
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
metadata.checkConfigMembers(beanDefinition);
}
查詢注入後設資料
接著繼續進入到findAutowiringMetadata
,findAutowiringMetadata 會呼叫buildAutowiringMetadata
方法建立注入後設資料,然後將後設資料快取到injectionMetadataCache
屬性中:
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)) {
...
metadata = buildAutowiringMetadata(clazz);
this.injectionMetadataCache.put(cacheKey, metadata);
}
}
}
return metadata;
}
建立注入後設資料
仔細檢視buildAutowiringMetadata
方法的實現,它會反射類的方法和屬性,同時還會向上查詢父類,然後生成InjectionMetadata
。
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
小結
收集註入後設資料過程,首先呼叫AutowiredAnnotationBeanPostProcessor.postProcessMergedBeanDefinition
方法,然後呼叫findAutowiringMetadata
方法查詢後設資料,如果找到相應類的注入後設資料 ,就會呼叫buildAutowiringMetadata
方法建立InjectionMetadata
,最後將新建立的注入後設資料儲存在injectionMetadataCache
快取起來。
設定Bean屬性
收信完注入後設資料後,Bean的屬性還是沒有注入的,還需要將執行屬性注入。還是在doCreateBean
方法中,收集完注入後設資料後,緊接著會呼叫populateBean
:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
PropertyDescriptor[] filteredPds = null;
if (hasInstAwareBpps) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
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;
}
}
}
}
可以看到在populateBean
中會呼叫InstantiationAwareBeanPostProcessor.postProcessProperties
方法,由於已經知道 AutowiredAnnotationBeanPostProcessor 是實現 InstantiationAwareBeanPostProcessor 的,所以可以直接檢視實現方法:
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
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;
}
postProcessProperties
就很簡單的,查詢 InjectMetadata,然後呼叫 InjectMetadata.inject
方法。到這裡其實就已經知道@Autowire
的實現機制了,接下來就是根據InjectionMetadata
中的資訊實現屬性注入了。
如果需要深入研究的話,有興趣的還可以繼續往下看。
總結
本文大致講解了 @Autowire 相關的類與實現的機制,@Autowire 註解的實現主要是理解AutowiredAnnotationBeanPostProcessor
類,還有收集註入後設資料、設定注入屬性的呼叫時機。
通過檢視AutowiredAnnotationBeanPostProcessor
類原始碼,相信你也可以自定義注入功能。
本人知識水平有限,如有錯誤,謝謝大家指正。
歡迎關注我的公眾號:架構文摘,獲得獨家整理120G的免費學習資源助力你的架構師學習之路!
公眾號後臺回覆
arch028
獲取資料: