乐趣区

关于spring:聊聊Autowired的常考面试题

金三银四,很快又到了招聘淡季了,最近常常须要去做各种面试,发现很多几年工作教训的候选人,对 Spring 理解也是知之甚少,更多的只是会用,比方一个 @Autowired 原理都能够问倒一大片。

为此,趁着女朋友狗泽明天加班,长话短说的聊聊这个话题吧!

@Autowired 注解是如何实现主动拆卸的

@Autowired 注解之所以能够实现主动拆卸,次要是依赖 Spring 提供的处理器 AutowiredAnnotationBeanPostProcessor,该处理器在初始化的时候便退出了对 @Autowired、@Inject、@Value 三个注解的解决;

该处理器实现了接口 InstantiationAwareBeanPostProcessor,因而能够在 bean 对象实例化的时候,对其应用了 @Autowired 的成员进行主动拆卸。

源码参考如下:

public AutowiredAnnotationBeanPostProcessor() {
// 退出了对 @Autowired、@Inject、@Value 三个注解的解决
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName(“javax.inject.Inject”, AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.info(“JSR-330 ‘javax.inject.Inject’ annotation found and supported for autowiring”);
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available – simply skip.
}
}

该处理器何时被退出的

当结构 Spring 容器的时候,Spring 会向容器注册几个内置的处理器对象,其中就包含了 AutowiredAnnotationBeanPostProcessor。

源码能够间接看 AnnotationConfigUtils.registerAnnotationConfigProcessors 办法。

源码参考如下:

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(
BeanDefinitionRegistry registry, @Nullable Object source) {

// 省略代码 …

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
def.setSource(source);
beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}

// 省略代码 …

return beanDefs;
}

该处理器是什么时候被调用的

Spring 在创立 bean 的时候会调用 doCreateBean 办法,在 doCreateBean 办法中会调用 populateBean 办法,该办法的作用便是先判断是否该 bean 对象须要进行主动拆卸,如果是的话再一一遍历调用 Spring 容器曾经注入的处理器。

源码参考如下:

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
if (hasInstAwareBpps || needsDepCheck) {
if (pvs == null) {
pvs = mbd.getPropertyValues();
}
PropertyDescriptor[] filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
if (hasInstAwareBpps) {
for (BeanPostProcessor bp : getBeanPostProcessors()) {
if (bp instanceof InstantiationAwareBeanPostProcessor) {
InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
// 执行后置处理器,填充属性,实现主动拆卸
pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
if (pvs == null) {
return;
}
}
}
}
}
}

主动拆卸有几种形式

没有应用过 xml 配置进行注入的可能都无法回答这个问题,然而凡是看过 Spring 实战类书籍的都应该晓得这个知识点。

Spring 目前反对三种形式,别离是

  • AUTOWIRE_BY_NAME 按名称主动拆卸 bean 属性
  • AUTOWIRE_BY_TYPE 按类型主动拆卸 bean 属性
  • AUTOWIRE_CONSTRUCTOR 按结构器主动拆卸

在 xml 配置注入的时候指定下类型即可进行切换,比方:

拓展:我司这边不举荐应用在 xml 里边指定主动拆卸类型,因为开发者无奈对 Spring 利用中的所有 Bean 的状况都一目了然,而通过这种形式指定会导致注入的对象也存在不确定性。

那么应用 @Autowired 指定的是哪种主动拆卸

答案是 AUTOWIRE_NO,也就是没有指定。

然而实际上看源码的实现其实率先通过类型来拆卸,如果匹配到的实现是多个的,才会额定采纳其余策略。

如果 @Autowried 注解的接口有多个实现,Spring 是如何解决的

大部分人遇见这种状况都是间接答复报错,其实不是的。

如果接口有多个实现,Spring 有本人的一套策略:

  • 会看看有没有应用了 @Primary 注解的 bean
  • 依据 @Priority 注解优先级抉择优先级高的。
  • 依据属性的名称和 Spring 中 beanName 来进行判断。

再找不到才会报错,也就是 NoUniqueBeanDefinitionException 异样。

具体实现源码如下:

@Autowired 注入反对哪几种类型

码龄较短的或者没有看过源码的都无法回答这个问题,基本上都只晓得 @Autowired 注入一个对象。

而实际上 @Autowired 除了注册单个对象外,还额定反对注入三种类型,别离是数组、汇合以及 map 类型。

具体参考 DefaultListableBeanFactory.resolveMultipleBeans 办法

总结

这几个问题并非必考点,只是说如果考查 @Autowired 的话基本上问题就是这几个了,好了,狗泽上班了,就先这样吧。

晓得大家须要,就整顿了一份学 Spring 必备的电子书,有须要关注公众号自取,公众号回复:Spring

有趣味的关注我一波,Java 面试官带你们跨过一个个的面试坑,保障不亏。

原文链接:https://mp.weixin.qq.com/s/yAFMGOh5WODueLVet-YUUA

谢谢点赞反对????????????!

退出移动版