面試中碰到面試官問:”Spring 注解是如果工作的?“,當前我一驚,完了這不觸及到我的知識誤區了嗎?,還好我機智,靈機一動回了句:Spring 注解的工作流程倒還沒有看到,但是我知道@Autowired
注解的工作流程,后面不用說了一頓巴拉,面試官都連連點頭。
面試中要活用轉移話題,要避免回答 ”不知道“,要引導面試官掉入你擅長的技術,然后才有機會教他作人。
@Autowired 注解的主要功能就是完成自動注入,使用也非常簡單(Spring都安排好了),但是要想知道 @Autowired 注解的內部現實,就需要看一下Spring源碼了。接下來一步步的解剖 @Autowired 的實現原理,首先理一下與 @Autowired 注解相關的類,然后一步步的跟蹤源碼,直到理解 @Autowired 的原理。
springmvc注解有哪些、AutowiredAnnotationBeanPostProcessor
是實現 @Autowired 功能的主要類,它有一些方法是會用解析 @Autowired 注解并實現自動注入的功能,下面是它的繼承圖:
從上圖可以發現 AutowiredAnnotationBeanPostProcessor 最上層是 BeanPostProcessor
是一個后處理器,當然除了后處理器外中間還有InstantiationAwareBeanPostProcessor
和MergedBeanDefinitionPostProcessor
:
postProcessBeforeInstantiation方法
Springboot注解,在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
也是一個繼承 BeanPostProcessor
接口的后處理器,它的主要作用就是可以處理操作BeanDefinition
對象,由于Bean的實例化是通過 BeanDefinition 的, 通過操作BeanDefinition ,這樣可以使Bean的實例化時發生一些變化。
MergedBeanDefinitionPostProcessor 只有兩個方法
java注入注解?postProcessMergedBeanDefinition方法
void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
Class<?> beanType, String beanName);
Bean的BeanDefinition 被合并后調用此方法。
resetBeanDefinition
default void resetBeanDefinition(String beanName) {}
當一個BeanDefinition被重置后調用 。
java被注入、AutowireCapableBeanFactory
繼承自BeanFactory
,除了提供基礎的Bean操作外,從接口的名字就可以推斷出的它還有自動注入
的能力。AutowireCapableBeanFactory 提供四種注入模型:
AutowireCapableBeanFactory 接口有不少方法,但大部分都是跟自動注入的相關。@Autowired 的主要功能就是在Bean實例化后,為其設置屬性,所以在 AutowireCapableBeanFactory 接口有一個createBean
方法,用于創建Bean并設置Bean的屬性:
<T> T createBean(Class<T> beanClass) throws BeansException;
createBean
方法,它的調用時機是創建Bean的時候,稍后會說到它的調用時機。
jdbc?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創建的生命周期,才可以將上面與 @Autowired 相關的類串起來,首先這里不會過多的介紹Bean的創建細節,只關注自動注入相關的代碼。
Spring中默認的Bean都是懶加載的,所以一個Bean的創建會從調用getBean
方法開始,如果不考慮緩存、上層容器的情況,Bean的創建會經過以下方法:
以上流程中的getBean
和doGetBean
不多作說明了, 重點關注createBean
前面提到AbstractAutowireCapableBeanFactory.createBean
方法,所以說你在調用getBean
方法獲取Bean的實例時,如果這個Bean實例還沒有被創建,那么createBean
就會被調用。
autowired注解無效、通過簡單的說明Bean創建的生命周期,就能找到 @Autowired 注解實現的入口,接下來再繼續跟蹤createBean
方法。
收集注入元信息的步驟的,其實就是調用AutowiredAnnotationBeanPostProcessor
類方法來實現的。
以下是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 并沒有重寫這個方法,所以什么都不做。
autowired沒有注入?上面說過 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的屬性還是沒有注入的,還需要將執行屬性注入。還是在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
類源碼,相信你也可以自定義注入功能。
本人知識水平有限,如有錯誤,謝謝大家指正。
版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。
工作时间:8:00-18:00
客服电话
电子邮件
admin@qq.com
扫码二维码
获取最新动态