javascript
Spring框架你敢写精通,面试官就敢问@Autowired注解的实现原理
面試官:Spring框架中的@Autowired注解可以標注在哪些地方?
小小白:@Autowired注解可以被標注在構造函數、屬性、setter方法或配置方法上,用于實現依賴自動注入。
面試官:有沒有研究過@Autowired注解的實現原理?
小小白:看過它的實現源碼。
面試官:那你說一下@Autowired注解的工作原理?
小小白:@Autowired注解的作用是由AutowiredAnnotationBeanPostProcessor實現的,查看該類的源碼會發現它實現了MergedBeanDefinitionPostProcessor接口,進而實現了接口中的postProcessMergedBeanDefinition方法,@Autowired注解正是通過這個方法實現注入類型的預解析,將需要依賴注入的屬性信息封裝到InjectionMetadata類中,InjectionMetadata類中包含了哪些需要注入的元素及元素要注入到哪個目標類中,在Spring容器啟動的過程中初始化單例bean的時候通過populateBean方法實現對屬性的注入。
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {if (beanType != null) {InjectionMetadata metadata = this.findAutowiringMetadata(beanName, beanType, (PropertyValues)null);metadata.checkConfigMembers(beanDefinition);}}public class InjectionMetadata {private static final Log logger = LogFactory.getLog(InjectionMetadata.class);private final Class<?> targetClass;private final Collection<InjectedElement> injectedElements;private volatile Set<InjectedElement> checkedElements;面試官:AutowiredAnnotationBeanPostProcessor類的postProcessMergedBeanDefinition方法是在什么時候被調用的?
小小白:Spring容器在啟動的時候會執行AbstractApplicationContext類的refresh方法,在refresh方法執行的過程中先注冊AutowiredAnnotationBeanPostProcessor,然后在對非延遲初始化的單例bean進行初始化時,會間接調用。具體實現細節分析如下。
public void refresh() throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {// Prepare this context for refreshing.prepareRefresh();// Tell the subclass to refresh the internal bean factory.ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();// Prepare the bean factory for use in this context.prepareBeanFactory(beanFactory);try {// Allows post-processing of the bean factory in context subclasses.postProcessBeanFactory(beanFactory);// Invoke factory processors registered as beans in the context.invokeBeanFactoryPostProcessors(beanFactory);// Register bean processors that intercept bean creation.// 重點看這里:在這里對AutowiredAnnotationBeanPostProcessor注冊registerBeanPostProcessors(beanFactory);// Initialize message source for this context.initMessageSource();// Initialize event multicaster for this context.initApplicationEventMulticaster();// Initialize other special beans in specific context subclasses.onRefresh();// Check for listener beans and register them.registerListeners();// Instantiate all remaining (non-lazy-init) singletons.// 重點看這里:對非延遲初始化的單例bean進行初始化finishBeanFactoryInitialization(beanFactory);// Last step: publish corresponding event.finishRefresh();}catch (BeansException ex) {if (logger.isWarnEnabled()) {logger.warn("Exception encountered during context initialization - " + "cancelling refresh attempt: " + ex);}// Destroy already created singletons to avoid dangling resources.destroyBeans();// Reset 'active' flag.cancelRefresh(ex);// Propagate exception to caller.throw ex;}finally {// Reset common introspection caches in Spring's core, since we// might not ever need metadata for singleton beans anymore...resetCommonCaches();}} }refresh方法中registerBeanPostProcessors(beanFactory)完成了對AutowiredAnnotationBeanPostProcessor的注冊,當執行finishBeanFactoryInitialization(beanFactory)方法對非延遲初始化的單例bean進行初始化時,會執行到AbstractAutowireCapableBeanFactory類的doCreateBean方法,在這個方法中有如下這么一段代碼。
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;} }在這段代碼中會執行applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName),深入到這個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);}} }可以看到,if的條件判斷邏輯是否屬于MergedBeanDefinitionPostProcessor,而AutowiredAnnotationBeanPostProcessor正好實現了MergedBeanDefinitionPostProcessor接口,所以在這里調用AutowiredAnnotationBeanPostProcessor類的postProcessMergedBeanDefinition方法。
面試官:你在說一下注入的過程?
小小白:使用AutowiredFieldElement實現對標注在屬性上的注入,使用AutowiredMethodElement對標注在方法上的注入。注入過程:根據需要注入的元素的描述信息,按類型或名稱查找需要的依賴值,如果依賴沒有實例化先實例化依賴,然后使用反射進行賦值。
面試官:@Resource或者@Autowired注解有什么區別?
小小白:雖然@Resource和@Autowired都可以書寫標注在屬性或者該屬性的setter方法之上,但是@Resource默認是按照名稱來裝配注入的,只有當找不到與名稱匹配的bean才會按照類型來裝配注入;@Autowired默認是按照類型裝配注入的,默認情況下它要求依賴對象必須存在如果允許為null,可以設置它required屬性為false,如果想按照名稱來注入,則需要結合@Qualifier一起使用;@Resource注解是由JDK提供,而@Autowired是由Spring提供。
總結
以上是生活随笔為你收集整理的Spring框架你敢写精通,面试官就敢问@Autowired注解的实现原理的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 这 8 篇文章告诉你:未来的软件研发是怎
- 下一篇: 病毒与故障:漫谈计算机软件的故障应对