(-----------------以下为幻想场景-----------------)
面试官:“你知道@EnableAutoConfiguration这个注解原理吗?”
我:“通过读取配置文件然后进入IOC啊。”
面试官:“不是。就是你知道springboot的特点之一就是依赖包引用方便,那是怎么自动装配的呢?”
我:“??????不就是读取配置文件然后进入IOC容器注入嘛???”
面试官:“算了,我觉得你能力还不够。你还是多看看源码吧。”
我????????内心暗想难道我听错了????还是说的@Autowired??? 这两不一回儿事嘛?什么鬼????难道是要??
一、@EnableAutoConfiguration
面试官大爷:“你来说说@EnableAutoConfiguration这个注解。”
我:“好的,这个注解首先在springboot的启动类的@SpringBootApplication里。@EnableAutoConfiguration负责了自动装配。”
(下图为该注解源码)
其中@AutoConfigurationPackge为自动扫描包的注解,@EnableAutoConfiguration就是通过这个注解去获取对象所在的路径。
@import负责导入,进入@import里面的参数类:看这个方法
同样是一看名字就懂意思的方法,好的,让我们继续深入再点进去:
喜迎类加载。仔细看看代码,我们发现华点。
很好有了重点,接着往里点
然后面试官打断:“那为什么要强转list呢?”
我:“等下等下。”
我们再看进去(第一个方法)
一般来说总是有不一样的颜色引起我们的注意。于是破案了。
Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories");
他第一个对象方法就是让对象加载了“META-INF/spring.factories”这个路径的东西。然后为啥要转list等我再研究一阵子,呸。
然后再进入IOC,然后IOC对象开始BLABLABLA。
回答完毕
(-------------------再假设---------------------------)
二、@Autowired
面试官大佬:“我问的是@Autowired的自动装配。”
我:“行吧。让我们继续来读源码(保持微笑)”
等一下,仿佛没有找到华点。等会,这玩意怎么和@EnableAutoConfiguration不一样呢,敢不敢给我个突破点。行吧,你不敢我只有到包里找了。于是喜迎实现类——AutowiredAnnotationBeanPostProcessor
public class AutowiredAnnotationBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware
光看这一圈继承和接口。噫,仿佛有点复杂。没关系嘛。我菜鸡我看不懂,慢慢找(超愤怒)
映入眼帘就是静态,问题是这是空啊????干嘛啊???再找找,于是:
截图放不下就丢代码了
private InjectionMetadata buildAutowiringMetadata(Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
} else {
List<InjectedElement> elements = new ArrayList();
Class targetClass = clazz;
//有点东西,开始循环准备工作了
do {
List<InjectedElement> currElements = new ArrayList();
//这个我知道,这个是反射
ReflectionUtils.doWithLocalFields(targetClass, (field) -> {
MergedAnnotation<?> ann = this.findAutowiredAnnotation(field);
//看输出是不准用在静态字段上面
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = this.determineRequiredStatus(ann);
currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, (method) -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
MergedAnnotation<?> ann = this.findAutowiredAnnotation(bridgedMethod);
//也不准用在静态方法上
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0 && this.logger.isInfoEnabled()) {
this.logger.info("Autowired annotation should only be used on methods with parameters: " + method);
}
boolean required = this.determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredAnnotationBeanPostProcessor.AutowiredMethodElement(method, required, pd));
}
}
});
//相关注解通通加进来我可以!(C++/C:“呸,垃圾运行速度”)
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
//循环
} while(targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
}
循环期间我们来到这个方法:
不为空就接着嗨
山不转水转,该类对象终于有内容了,起身!鼓掌!
哦,等会接下来下一步呢,为啥只给我个对象内容???根据静态方法再看看,仿佛inject()有点意思。管他三七二十一点进去看看,点不动,尴尬= =搜搜看= =于是
注入完成。等下,仔细看看代码,仿佛有什么不对,光记录日志了,这是哪门子的注入啊????再仔细看看。哦,在for里面。
反射暴力注入。告辞!(对不起我真的是菜鸡)
回答完毕。