Spring源码流程——@EnableAutoConfiguration和@Autowired源码过程分析

(-----------------以下为幻想场景-----------------)

面试官:“你知道@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里面。

反射暴力注入。告辞!(对不起我真的是菜鸡)

回答完毕。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值