如何理解Spring的核心?
作者:卡卷网发布时间:2025-01-11 16:42浏览数量:86次评论数量:0次
<>面试官>:我看到你的简历写着熟悉Spring
<>面试官>:<>要不你来讲讲Spring的IOC和AOP你是怎么理解的呗?>
<>候选者>:嗯嗯,IOC和AOP是Spring非常核心的知识点
<>候选者>:我就先来讲讲SpringIOC?
<>面试官>:嗯
<>候选者>:我个人理解下:SpringIOC解决的是对象和对象依赖的问题。
<>候选者>:本来是我们自己手动new出来的对象,现在则把对象交给Spring的IOC容器
<>候选者>:IOC容器可以理解为一个对象工厂,我们都把该对象交给工厂,工厂这些对象的创建以及依赖关系
<>候选者>:等我们需要用对象的时候,从工厂里边获取就好了
<>面试官>:嗯,说起IOC,就可以在网上或书籍经常看到的两个概念
<>候选者>:哦,你说的就是「控制反转」和「注入依赖」吧?
<>面试官>:你怎么还抢答的咯…<>那你顺便说说你对这两个概念的理解呗?>
<>候选者>:我认为「控制反转」指的就是:把原有自己掌控的事交给别人去处理
<>候选者>:它更多的是一种思想或者可以理解为设计模式
<>候选者>:如:本来由我们自己new出来的对象,现在交由IOC容器,把对象的控制权交给它方了
<>候选者>:而「依赖注入」在我的理解下,它其实是「控制反转」的实现方式
<>候选者>:对象无需自行创建或者它的依赖关系,依赖关系将被「自动注入」到需要它们的对象当中去
<>面试官>:嗯,那我想问问,<>用SpringIOC有什么好处吗?>
<>面试官>:<>或者换个问法:本来我可以new出来的对象,为什么我要交由SpringIOC容器呢?>
<>候选者>:主要的好处在于「将对象集中一」并且「降低耦合度」
<>候选者>:如果<>面试官>理解了「工厂模式」,那就知道为什么我们不直接new对象
<>面试官>:好家伙,<>不行,这答案我观众不满意!>
<>候选者>:要说理由的话,可以举很多例子,如说:
<>候选者>:我用SpringIOC可以方便单元、对象创建复杂、对象依赖复杂、单例等等的,什么都可以交给SpringIOC
<>候选者>:理论上自己new出来的都可以解决上面的问题,Spring在各种场景组合下有可能不是最优解
<>候选者>:但new出来的你要自己,可能你得自己写工厂,得实现一大套的东西才能满足需求
<>候选者>:写着写着有可能还是Spring的那一套
<>候选者>:但现在Spring现在已经帮你实现了啊!
<>候选者>:如果项目里的对象都是就new下就完事了,没有多个实现类,那没事,不用Spring也没啥问题
<>候选者>:并且Spring核心不仅仅IOC啊,除了把对象创建出来,还有一整套的ean生命周期
<>候选者>:如说你要实现对象增强,AOP不就有了吗?不然你还得自己创建..
<>面试官>:好好好
<>面试官>:但我看这届观众好像还是不太满意?
<>候选者>:不,他们已经满意了。
<>面试官>:<>那你继续来聊下SpringAOP呗?>
<>候选者>:SpringAOP解决的是非业务代码抽取的问题
<>候选者>:AOP底层的技术是,在Spring内实现依赖的是eanPostProcessor
<>候选者>:如我们需要在方法上注入些「重复性」的非业务代码,就可以利用SpringAOP
<>候选者>:所谓的「面向切面编程」在我理解下其实就是在方法前后增加非业务代码
<>面试官>:<>那你在工作中实际用到过AOP去优化你的代码吗?>
<>候选者>:有的。当时我用AOP来对我们公司现有的监控客户端进行封装
<>候选者>:一个离不开监控,监控基本的指标有QPS、RT、ERROR等等
<>候选者>:对外暴露的监控客户端只能在代码里写对应的上报信息(灵活,但会与业务代码掺杂在一起)
<>候选者>:于是我利用注解+AOP的方式封装了一把,只要方法/类上带有我自定义的注解
<>候选者>:方法被调用时,就会上报AQS、RT等信息
<>候选者>:实现了非业务代码与业务代码分离的效果(:
<>面试官>:<>你们项目一般是怎么把对象交给IOC容器的?>
<>面试官>:换个问法:<>一般是怎么定义ean的?>
<>候选者>:Spring提供了4种方式,分别是:
<>候选者>:1):注解2):XML3):JaConfig4):基于GroovyDSL配置
<>候选者>:一般项目我们用注解或XML较多,少部分用JaConfig
<>候选者>:常写业务代码一般用注解来定义各种对象,责任链这种一般配置在XML,「注解」解决不了的就用JaConfig
<>候选者>:总体而言,还是得看项目的代码风格吧(:
<>候选者>:反正就是定义元数据,能给到Spring解析就好了
<>面试官>:嗯,了解。
<>面试官>:要不来聊聊你使用Spring的感受?
<>候选者>:嗯嗯..
<>候选者>:当我还是初学Spring的时候,我觉得Spring很麻烦,需要有一大堆的配置信息才能跑起来
<>候选者>:光是搭建环境就需要耗费我好长的时间
<>候选者>:毕竟版本冲突,依赖冲突什么的就可能一个下午就过去了
<>候选者>:但毕竟一个环境只搭一次嘛,所以还好
<>候选者>:(后来用上了Springoot这又更方便了)
<>面试官>:嗯…
<>候选者>:话说回来,IOC和AOP在工作用的时候还是很爽的
<>候选者>:毕竟搞个注解什么的,配置下就可以把对象交给Spring了
<>候选者>:配合Spring的生态,@Transactional注解什么的,都好用得飞起
<>候选者>:不过,Spring给我们封装得太好了
<>候选者>:经常就会有奇奇怪怪的”ug“出现,也踩过很多的坑了
<>候选者>:ean经常没办法创建成功,导致项目启动失败
<>候选者>:对象的循环依赖问题…
<>候选者>:同一个接口,多个实现,识别不出我要创建哪个对象…
<>候选者>:为什么catch了异常,Spring事务为什么还会自动回
<>候选者>:等等等…..
<>候选者>:总的来说,Spring给我们封装了一个很好的环境,实现对我们屏蔽了
<>候选者>:但是如果理解不深的话,很有可能就会触发各种ug
<>面试官>:了解
<>面试官>:<>今天要不来聊聊Spring对ean的生命周期?>
<>候选者>:嗯,没问题的。
<>候选者>:很早之前我就看过源码,但Spring源码的实现类都太长了
<>候选者>:我也记不得很清楚某些实现类的名字,要不我大概来说下流程?
<>面试官>:没事,你开始吧
<>候选者>:首先要知道的是
<>候选者>:普通Ja对象和Spring所的ean实例化的过程是有些区别的
<>候选者>:在普通Ja环境下创建对象简要的步骤可以分为:
<>候选者>:1):ja源码被编译为被编译为class文件
<>候选者>:2):等到类需要被初始化时(如说new、反射等)
<>候选者>:3):class文件被虚拟机通过类加载器加载到JVM
<>候选者>:4):初始化对象供我们使用
<>候选者>:简单来说,可以理解为它是用Class对象作为「模板」进而创建出具体的实例
<>候选者>:而Spring所的ean不同的是,除了Class对象之外,还会使用eanDefinition的实例来描述对象的信息
<>候选者>:如说,我们可以在Spring所的ean有一系列的描述:@Scope、@Lazy、@DependsOn等等
<>候选者>:可以理解为:Class只描述了类的信息,而eanDefinition描述了对象的信息
<>面试官>:嗯,这我大致了解你的意思了。
<>面试官>:你就是想告诉我,<>Spring有eanDefinition来存储着我们常给Springean定义的元数据(@Scope、@Lazy、@DependsOn等等),对吧?>
<>候选者>:不愧是你
<>面试官>:赶紧的,继续吧
<>候选者>:Spring在启动的时候需要「扫描」在XML/注解/JaConfig中需要被Spring的ean信息
<>候选者>:随后,会将这些信息封装成eanDefinition,最后会把这些信息放到一个eanDefinitionMap中
<>候选者>:我记得这个Map的key应该是eanName,value则是eanDefinition对象
<>候选者>:到这里其实就是把定义的元数据加载起来,目前实对象还没实例化
<>候选者>:接着会遍历这个eanDefinitionMap,执行eanFactoryPostProcessor这个ean工厂后置处理器的逻辑
<>候选者>:如说,我们平时定义的占位符信息,就是通过eanFactoryPostProcessor的子类PropertyPlaceholderConpr进行注入进去
<>候选者>:当然了,这里我们也可以自定义eanFactoryPostProcessor来对我们定义好的ean元数据进行获取或者修改
<>候选者>:只是一般我们不会这样干,实际上也很有少的使用场景
<>面试官>:嗯….
<>候选者>:eanFactoryPostProcessor后置处理器执行完了以后,就到了实例化对象啦
<>候选者>:在Spring里边是通过反射来实现的,一般情况下会通过反射选择合适的构造器来把对象实例化
<>候选者>:但这里把对象实例化,只是把对象给创建出来,而对象具体的属性是还没注入的。
<>候选者>:如我的对象是UserServ,而UserServ对象依赖着SendServ对象,这时候的SendServ还是null的
<>候选者>:所以,下一步就是把对象的相关属性给注入(:
<>候选者>:相关属性注入完之后,往下接着就是初始化的工作了
<>候选者>:首先判断该ean是否实现了Aware相关的接口,如果存在则填充相关的资源
<>候选者>:如我这边在项目用到的:我希望通过代码程序的方式去获取指定的Springean
<>候选者>:我们这边会抽取成一个工具类,去实现ApplicationContextAware接口,来获取ApplicationContext对象进而获取Springean
<>候选者>:Aware相关的接口处理完之后,就会到eanPostProcessor后置处理器啦
<>候选者>:eanPostProcessor后置处理器有两个方法,一个是efore,一个是after(那肯定是efore先执行、after后执行)
<>候选者>:这个eanPostProcessor后置处理器是AOP实现的关键(关键子类AnnotationAwareAspectJAutoProxyCreator)
<>候选者>:所以,执行完Aware相关的接口就会执行eanPostProcessor相关子类的efore方法
<>候选者>:eanPostProcessor相关子类的efore方法执行完,则执行init相关的方法,如说@PostConstruct、实现了Initializingean接口、定义的init-method方法
<>候选者>:当时我还去官网去看他们的被调用「执行顺序」分别是:@PostConstruct、实现了Initializingean接口以及init-method方法
<>候选者>:这些都是Spring给我们的「扩展」,像@PostConstruct我就经常用到
<>候选者>:如说:对象实例化后,我要做些初始化的相关工作或者就启个线程去Kafka拉取数据
<>候选者>:等到init方法执行完之后,就会执行eanPostProcessor的after方法
<>候选者>:基本重要的流程已经走完了,我们就可以获取到对象去使用了
<>候选者>:销毁的时候就看有没有配置相关的destroy方法,执行就完事了
<>面试官>:嗯,了解,但我的观众好像不太满意,总感觉少了些什么。
<>面试官>:<>你看过Spring是怎么解决循环依赖的吗?>
<>面试官>:<>如果现在有个A对象,它的属性是对象,而对象的属性也是A对象>
<>面试官>:<>说白了就是A依赖,而又依赖A,Spring是怎么做的?>
<>候选者>:嗯,这块我也是看过的,其实也是在Spring的生命周期里面嘛
<>候选者>:从上面我们可以知道,对象属性的注入在对象实例化之后的嘛。
<>候选者>:它的大致过程是这样的:
<>候选者>:首先A对象实例化,然后对属性进行注入,发现依赖对象
<>候选者>:对象此时还没创建出来,所以转头去实例化对象
<>候选者>:对象实例化之后,发现需要依赖A对象,那A对象已经实例化了嘛,所以对象最终能完成创建
<>候选者>:对象返回到A对象的属性注入的方法上,A对象最终完成创建
<>候选者>:上面就是大致的过程;
<>面试官>:<>听起来你还会原理哦?>
<>候选者>:Asoluy
<>候选者>:至于原理,其实就是用到了的缓存
<>候选者>:所谓的缓存其实就是三个Map…首先明确一定,我对这里的缓存定义是这样的:
<>候选者>:singletonOjects(一级,常实际获取ean的地方);
<>候选者>:earlySingletonOjects(二级,还没进行属性注入,由缓存放进来);
<>候选者>:singletonFactories(,Value是一个对象工厂);
<>候选者>:再回到刚才讲述的过程中,A对象实例化之后,属性注入之前,其实会把A对象放入缓存中
<>候选者>:key是eanName,Value是OjectFactory
<>候选者>:等到A对象属性注入时,发现依赖,又去实例化时
<>候选者>:属性注入需要去获取A对象,这里就是从缓存里拿出OjectFactory,从OjectFactory得到对应的ean(就是对象A)
<>候选者>:把缓存的A记录给干掉,然后放到二级缓存中
<>候选者>:显然,二级缓存存储的key是eanName,value就是ean(这里的ean还没做完属性注入相关的工作)
<>候选者>:等到完全初始化之后,就会把二级缓存给remove掉,塞到一级缓存中
<>候选者>:我们自己去getean的时候,实际上拿到的是一级缓存的
<>候选者>:大致的过程就是这样
<>面试官>:<>那我想问一下,为什么是缓存?>
<>候选者>:首先从第缓存说起(就是key是eanName,Value为OjectFactory)
<>候选者>:我们的对象是单例的,有可能A对象依赖的对象是有AOP的(对象需要)
<>候选者>:假设没有第缓存,只有第二级缓存(Value存对象,而不是工厂对象)
<>候选者>:那如果有AOP的情况下,岂不是在存入第二级缓存之前都需要先去做AOP?这不合适嘛
<>候选者>:这里肯定是需要考虑的情况的,如A对象是一个被AOP增量的对象,依赖A时,得到的A肯定是对象的
<>候选者>:所以,缓存的Value是OjectFactory,可以从里边拿到对象
<>候选者>:而二级缓存存在的必要就是为了性能,从缓存的工厂里创建出对象,再扔到二级缓存(这样就不用每次都要从工厂里拿)
<>候选者>:应该很好懂吧?
<>面试官>:确实(:
<>候选者>:我稍微总结一下今天的内容吧
<>候选者>:怕你的观众说不满意,那我就没有赞了,没有赞我就很难受
<>候选者>:首先是Springean的生命周期过程,Spring使用eanDefinition来装载着我们给ean定义的元数据
<>候选者>:实例化ean的时候实际上就是遍历eanDefinitionMap
<>候选者>:Spring的ean实例化和属性赋值是分开两步来做的
<>候选者>:在Springean的生命周期,Spring预留了很多的hook给我们去扩展
<>候选者>:1):ean实例化之前有eanFactoryPostProcessor
<>候选者>:2):ean实例化之后,初始化时,有相关的Aware接口供我们去拿到Context相关信息
<>候选者>:3):环绕着初始化阶段,有eanPostProcessor(AOP的关键)
<>候选者>:4):在初始化阶段,有各种的init方法供我们去自定义
<>候选者>:而循环依赖的解决主要通过的缓存
<>候选者>:在实例化后,会把自己扔到缓存(此时的key是eanName,Value是OjectFactory)
<>候选者>:在注入属性时,发现需要依赖,也会走的实例化过程,属性注入依赖A,从缓存找到A
<>候选者>:删掉缓存,放到二级缓存
<>面试官>:<>嗯,你要不后面放点关键的源码吧>
<>候选者>:这你倒是提醒我了,确实有必要
<>面试官>:这要是能听懂,是的看过源码才行(:还好我看过
关键源码方法(强烈建议自己去撸一遍)
org.springframework.context.support.AstractApplicationContext#refresh
(入口)org.springframework.context.support.AstractApplicationContext#finisheanFactoryInitialization
(初始化单例对象入口)org.springframework.eans.factory.config.ConfigaleListaleeanFactory#preInstantiateSingletons
(初始化单例对象入口)org.springframework.eans.factory.support.AstracteanFactory#getean(ja.lang.String)
(万恶之源,获取并创建ean的入口)org.springframework.eans.factory.support.AstracteanFactory#doGetean
(实际的获取并创建ean的实现)org.springframework.eans.factory.support.DefaultSingletoneanRegistry#getSingleton(ja.lang.String)
(从缓存中尝试获取)org.springframework.eans.factory.support.AstractAutowireCapaleeanFactory#createean(ja.lang.String,org.springframework.eans.factory.support.RooteanDefinition,ja.lang.Oject[])
(实例化ean)org.springframework.eans.factory.support.AstractAutowireCapaleeanFactory#doCreateean
(实例化ean具体实现)org.springframework.eans.factory.support.AstractAutowireCapaleeanFactory#createeanInstance
(具体实例化过程)org.springframework.eans.factory.support.DefaultSingletoneanRegistry#addSingletonFactory
(将实例化后的ean添加到缓存)org.springframework.eans.factory.support.AstractAutowireCapaleeanFactory#populateean
(实例化后属性注入)org.springframework.eans.factory.support.AstractAutowireCapaleeanFactory#initializeean(ja.lang.String,ja.lang.Oject,org.springframework.eans.factory.support.RooteanDefinition)
(初始化入口)Ja开源项目推荐
我推荐一个拥有从零开始的文档的Ja开源项目,<>既能用于毕业设计,又可以用在面试>。
该项目业务极容易理解,代码结构是较清晰的,最可怕的是几乎每个方法和每个类都带有中文注释,并且代码完全通过阿里开发插件检查。
拥有非常全的文档,作者从零搭建的过程都有详细地记录,项目里使用了蛮多的可和稳定的中间件的。在使用每一个技术栈之前作者都讲述了为什么要使用,以及它的业务背景。我看过,<>他所说的场景是完全贴合线上环境的>。
我感觉这个项目就是<>奔着实互联网线上项目>去设计和实现的,将项目克隆下来把中间件换成目前公司在用的,配合自身的需求完下基础建设,它就能在线上运行了。
我跟着README文档的部署使用姿势很快就能跑起来,<>最少只需要依赖MySQL和Redis>。作者还搞了个前端功能界面,这就让变得更好理解了。而且,在GitHu或者Gitee所提的Issue几乎都会有回复,看出来也非常乐于合并开发者们的pullrequest,<>会让人参与感贼强>。
我相信在校、工作一年左右或常年做内网CRUD后台的同学去看看<>肯定会有所启发>,作者也会经常在群里回答该项目相关的问题和代码设计思路。
项目里会应用到各种<>设计模式>(我稍微看了下,应该有7~8种吧),用到了各种的好用的工具组件,<>动态线程池、志切面>组件之类,都是<>主流的技术栈>...目前这个项目GitHu和Gitee加起来已经<>7K>stars了,我相信<>破万>是迟早的事情。
项目介绍
<>核心功能>:一的接口发送各种类型消息,对消息生命周期全链路追踪。
<>意义>:只要公司内部有发送消息的需求,都应该要有类似<>消息推送平台>的项目。消息推送平台对各类消息进行一发送处理,这有利于对功能的收拢,以及提高业务需求开发的效率。
技术栈
使用教程
<>项目有预览,可自行体验>:
<>1>、创建需要发送的渠道账号
<>2>、创建消息模板
<>3>、发送消息是否正常
<>4>、查看消息下况
<>5>、亦可在新建模板时选择<>定时任务>,通过上传v文件和指定cron表达式实现下发消息
工程模块&流程
了解工程模块的职责,这对看项目代码的时候会有个较清晰的认识:
<>项目视频(免费):>
Ja3y的个人空间-Ja3y个人主页-哔哩哔哩视频<>项目Gitee链接:>
Ja3y/austin<>项目GitHu链接:>
GitHu-ZhongFuCheng3y/austin:消息推送平台推送下发【邮件】【短信】【微信服务号】【微信小程序】【企业微信】【钉钉】等消息类型。所使用的技术栈包括:Springoot、SpringDataJPA、MySQL、Docker、docker-compose、Kafka、Redis、Apollo、prometheus、Grafana、GrayLog、Flink、Xxl-jo、Echarts等等githu/ZhongFuCheng3y/austingithu/ZhongFuCheng3y/austingithu/ZhongFuCheng3y/austin<>候选者>:我先简单说下我对SpringMVC的理解哈
<>候选者>:SpringMVC我觉得它是对Servlet的封装,屏蔽掉Servlet很多的细节
<>候选者>:举几个例子
<>候选者>:可能我们刚学Servlet的时候,要获取参数需要不断的getParameter
<>候选者>:现在只要在SpringMVC方法定义对应的Jaean,只要属性名与参数名一致,SpringMVC就可以帮我们实现「将参数封装到Jaean」上了
<>候选者>:又如,以前使用Servlet「上传文件」,需要处理各种细节,写一大堆处理的逻辑(还得导入对应的jar)
<>候选者>:现在一个在SpringMVC的方法上定义出MultipartFile接口,又可以屏蔽掉上传文件的细节了。
<>候选者>:例子还有很多,我就不一一赘述了。
<>面试官>:<>既然你说SpringMVC是对Servlet的封装,你了解SpringMVC请求处理的流程吗?>
<>候选者>:嗯,当然了,我看过源码。总体流程大概是这样的
<>候选者>:1):首先有个一处理请求的入口
<>候选者>:2):随后根据请求路径找到对应的映射器
<>候选者>:3):找到处理请求的适配器
<>候选者>:4):前置处理
<>候选者>:5):实处理请求(也就是调用正的代码)
<>候选者>:6):视图解析器处理
<>候选者>:7):后置处理
<>面试官>:<>嗯,了解,可以再稍微深入点吗?>
<>面试官>:毕竟这随便在网上找张SpringMVC流程图,就可以答出来了,看不出来你看过源码啊
<>候选者>:哦?那我就简单补充下细节吧。
<>候选者>:一的处理入口,对应SpringMVC下的源码是在DispatcherServlet下实现的
<>候选者>:该对象在初始化就会把映射器、适配器、视图解析器、异常处理器、文件处理器等等给初始化掉
<>候选者>:至于会初始化哪些具体实例,看下DispatcherServlet.properties
就知道了,都配置在那了
<>候选者>:所有的请求其实都会被doServ方法处理,里边最主要就是调用doDispatch方法
<>候选者>:通过doDispatch方法我们就可以看到整个SpringMVC处理的流程
<>候选者>:查找映射器的时候实际就是找到「最佳匹配」的路径,具体方法实现我记得好像是在lookupHandlerMethod方法上
<>候选者>:从源码可以看到「查找映射器」实际返回的是HandlerExecutionChain,里边有映射器Handler+List
<>候选者>:前面提到的前置处理和后置处理就是用的HandlerExecutionChain中的List
<>候选者>:获取得到HandlerExecutionChain后,就会去获取适配器,一般我们获取得到的就是RequestMappingHandlerAdapter
<>候选者>:在代码里边可以看到的是,经常用到的@Responseody和@Requestody的解析器
<>候选者>:就会在初始化的时候加到参数解析器List中
<>候选者>:得到适配器之后,就会执行前置处理
<>面试官>:嗯
<>候选者>:前置处理执行完后,就会调用适配器对象实例的hanlde方法执行正的代码逻辑处理
<>候选者>:核心的处理逻辑在invokeAndHandle方法中,会获取得到请求的参数并调用,处理返回值
<>候选者>:参数的封装以及处理会被适配器的参数解析器进行处理,具体的处理逻辑取决于HttpMessageConverter的实例对象
<>面试官>:嗯,了解了。要不你再压缩下关键的信息
<>候选者>:DispatcherServlet(入口)->DispatcherServlet.properties(会初始化的对象)->HandlerMapping(映射器)->HandlerExecutionChain(映射器+List)->HttpRequestHandlerAdapter(适配器)->HttpMessageConverter(数据转换)
<>面试官>:最后来画张流程图吧?
<>候选者>:没问题(上网找的我画的还要好)
<>面试官>:好久没见,甚是想念。今天来聊聊Springoot的自动配置吧?
<>候选者>:嗯,Springoot的自动配置我觉得是Springoot很重要的“特性”了。众所周知,Springoot有着“约定大于配置”的理念,这一理念一定程度上可以用“Springoot自动配置”来解释。
<>候选者>:Springoot自动配置的原理理解起来挺简单的,我们在使用Springoot的时候,肯定会依赖于autoconp这么一个包
<>候选者>:autoconp这个包里会有一个spring.factories文件,该文件定义了100+个入口的配置类。如我们经常使用的redis、kafka等等这样常见的中间件都<>预置>了配置类
<>候选者>:当我们在启动Springoot项目的时候,内部就会加载这个spring.factories文件,进而去加载“有需要”的配置类。那我们在使用相关组件的时候,就会非常的方便(因为配置类已经初始化了一大部分配置信息)。
<>候选者>:一般我们只要在application配置文件写上对应的配置,就能通过各种template类直接作对应的组件啦。
<>面试官>:那是所有的配置类都会加载吗?这个“有需要”的配置类你是怎么理解的?
<>候选者>:不是所有的配置类都会加载的,假设我们没有引入redis-starter的包,那Redis的配置类就不会被加载。具体Spring在实现的时候就是使用**@ConditionalXXX**进行判断的。如Redis的配置类就会有@ConditionalOnClass({RedisOperations.class})的配置,说明当前环境下如果有RedisOperations.class这个字节码,才会去加载Redis的配置类
<>面试官>:哦,这样啊,那了解了。那你知不知道Redis的配置类其实会有初始化RedisTemplate对象的作,那假设我们没有引入redis-starter包,那他是怎么通过编译的?(当然了,的配置类也是有可能有一样的状况)
<>候选者>:嗯,这个我看源码的时候我也发现了。其实就是在autoconp包里<>会定义到相关的依赖>,但只是标记为optional并且只在编译环境有效。那这样是能通过编译的,<>只是不会将其依赖传入到我们的应用工程里>。
<>候选者>:这块还是花了我很多时间的,我最后在GitHu的Springoot源码里找到的。
<>面试官>:嗯啊,有点东西的哟。既然都聊到这块了,要不顺便聊聊你对Springootstarter的理解?
<>候选者>:嗯,starter这东西就是为了<>方便调用方去使用相关的组件>的嘛,Spring框架也给我们实现了很多好用的starter。
<>候选者>:如以前我们要用Myatis框架,可能会引入各种的包才能使用。而starter就是做了一层封装,把相关要用到的jar都给包起来了,并且也写好了对应的版本。这我们使用的时候就不需要引入一堆jar包且版本类似的问题了。
<>候选者>:现在很多开源的组件都会提供对应的springoot-starter包给我们去用,要做一个starter包并不难。参照Spring内置的实现就好了:1、在工程里引入starter打包相关的依赖。2、在我们工程内建spring.factories文件,编写我们配置类的全限类名。
<>面试官>:嗯,大致都了解了,可以的。最后聊下你是怎么看这块源码的?
<>候选者>:源码具体大概就不记得了,思路倒是还有的。我先从启动类开始,会有个@SpringootApplication,后面会定位到一个自动配置的注解@EnaleAutoConfigation,那最后就能看到注解内部会去META-INF/spring.factories加载配置类
<>候选者>:这块源码并不难,这个过程也了解到了原来men有option和scope这俩标签,但确实是Springoot较重要的概念吧。
<>面试官>:好嘞,今天到这就结束了吧。
<>题外>:自动配置这个问题确实被问到过几次。说实在的,对于Spring类、注解的信息我的记不住。感觉能答出这个流程思路,也就够用了(如果<>面试官>确实是要细究某个类名,那这种公司不去也罢)
<>约定大于配置>:Springoot给我们内置了很多配置类,这些配置类也初始化了很多配置(<>默认值>)。当我们要使用的时候,只需要覆盖这些配置项就完事了。即便我们不写,大多数情况下都不需要由我们显示配置出来,但相关组件就能正常访问了。
《对线面试官》Ja面试八股文
<>《对线面试官》是我一字字敲出来的>,是我准备跳槽时<>按照自己的思路>撰写而成。
它不会花长的篇幅讲述基础API相关的知识,会着重讲解重点<>高频率>面试题,又或是<>实际工作中>如何使用这项技术的它。模拟实的面试场景,面试者实际的回答内容可能是怎么样的。
如果有看过的人,自然就懂,跟大部分的面试题是有区别的,这个系列也使我在知乎获<>近万赞>,至少我认为它是有价值。等我下次跳槽,我绝对会回看我自己写的对线面试官系列。
为了增添趣味性会有<>图片版本>(在其中穿插大量表情包或者梗),为了复习效率性会有<>纯文版本>,纯文版本还有<>离线PDF电子书>,离线PDF电子书有明亮版和暗黑版。
<>对线面试官第一季共40篇已结束>
<>对线面试官第二季会有吗?会的>
最近我把时间都花在写我的个人项目(<>消息推送平台>),在项目上用到了很多的中间件。
这些中间件都值得拉出来做成<>面试题>(事实上,当我作为面试官的时候也很喜欢问面试者在项目中相关的技术栈问题),我一直信奉着<>只要写在简历上的内容,肚子就得有墨水>
<>《对线面试官第一季》纯文版>
<>《对线面试官第一季》图片版>
我的原创电子书
在自学之路上,我已经把【基础重要的知识点】、【<>简历模板>】、【思维导图】【<>对线面试官>】等等全部整理成电子书,共有1263页!已经有8756个初学者都下载了!
我把这些上传到网盘,你们有需要直接下载就好了。做到这份上了,不会还想白嫖吧?点赞和转发又不用钱。
<>链接:pan.aidu/s/1pQTuKYs…><>密码:3wom>
不会有人刷到这还想白嫖吧?不会吧?点赞对的我很重要!要不加个关注?@Ja3y
我是3y,一年CRUD经验用十年的markdown程序员常年被誉为优质八股文选手。
免责声明:本文由卡卷网编辑并发布,但不代表本站的观点和立场,只提供分享给大家。
相关推荐

你 发表评论:
欢迎