Spring框架你敢写精通,面试官就敢问@Autowired注解的实现原理

129 篇文章 8 订阅

面试官: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提供。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值