目录
1、说说你对Spring的IOC机制和AOP机制的理解可以吗?
1.1、spring IOC
1.2、Spring IOC框架,控制反转,依赖注⼊
1.3、说说你对Spring的AOP机制的理解可以吗?
3、了解过cglib动态代理吗?他跟jdk动态代理的区别是什么?
4、能说说Spring中的Bean是线程安全的吗?
5、Spring的事务实现原理是什么?能聊聊你对事务传播机制的理解吗?
6、能画⼀张图说说Spring Boot的核⼼架构吗?
7、能画⼀张图说说Spring的核⼼架构吗?
8、能说说Spring中都使⽤了哪些设计模式吗?
9、能画⼀张图说说Spring Web MVC的核⼼架构吗?
10、能画⼀张图说说Spring Cloud的核⼼架构吗?》
1、说说你对Spring的IOC机制和AOP机制的理解可以吗?
spring这块的⾯试题,spring boot,spring cloud,spring web mvc
1.1、spring IOC
写⼀套系统,web
服务器,
tomcat
,⼀旦启动之后,他就可以监听⼀个端⼝号的
http
请求,然后可以把请求转交给你的
servlet
,
jsp
,配合起来使⽤的,servlet
处理请求。
Tomcat会监听一个端口号,接收浏览器发的请求转发到SpringMVC(Servlet)
1.2、Spring IOC框架,控制反转,依赖注⼊
xml
⽂件来进⾏⼀个配置,进化到了基于注解来进⾏⾃动依赖注⼊
1.2、Spring IOC框架,控制反转,依赖注⼊ xml ⽂件来进⾏⼀个配置,进化到了基于注解来进⾏⾃动依赖注⼊
我们只要在这个⼯程⾥通过maven引⼊⼀些spring框架的依赖,ioc功能 。Tomcat在启动的时候,直接会启动spring容器,spring容器根据xml配置或注解去实例化你的⼀些bean对象,然后根据xml配置或者注解,去对bean对象之间的引⽤关系,去进⾏依赖注⼊,某个bean依赖了另外⼀个bean。
底层的核⼼技术 反射 , 他会通过反射的技术,直接根据你的类去⾃⼰构建对应的对象出来,⽤的就是反射技术,系统的类与类之间彻底的解耦合。 现在这套⽐较⾼⼤上的⼀点系统⾥,有⼏⼗个类都使⽤了 @Resource 这个注解去标注 MyService myService ,⼏⼗个地⽅都依赖了这个 类,如果要修改实现类为 NewServiceManagerImpl。1.3、说说你对Spring的AOP机制的理解可以吗?
Spring已经管理了我们代码⾥所有的这个类的对象实例,bean 我们有⼏⼗个Service组件,类似的⼀样的代码,重复的代码,必须在⼏⼗个地⽅都去写⼀模⼀样的东西 ,spring aop机制出马了 。
做⼀个切⾯,如何定义呢? MyServiceXX 的这种类,在这些类的所有⽅法中,都去织⼊⼀些代码,在所有这些⽅法刚开始运⾏的时候,都先去开启⼀个事务,在所有这些⽅法运⾏完毕之后,去根据是否抛出异常来判断⼀下,如果抛出异常,就回滚事务,如果没有异常,就提交事务 => AOP。 Spring在运⾏的时候,动态代理技术, AOP的核⼼技术,就是动态代理,他会给你的那些类⽣成动态代理 。事务:mysql数据库⾥都提供⼀个事务机制,我们如果开启⼀个事务,在这个事务⾥执⾏多条增删改的sql语句,这个过程中,如果任何⼀个sql语句失败了,会导致这个事务的回滚,把其他sql做的数据更改都恢复回去,在⼀个事务⾥的所有sql,要么⼀起成功,要么⼀起失败,事务功能可以保证我们的数据的⼀致性,在业务逻辑组件⾥去加⼊这个事。
流程总结:controller类引用service类,而service类会有多个并且有重复代码,此时使用AOP写一个针对所有service写一个切面,将重复代码放到切面里。当Spring再运行时会更加切面使用动态代理机制,将service生成对应的动态代理类(代理类里实现被代理类相同的接口、注入被代理类、调用被代理类的方法)此时controller调用的service就是对应的代理类。
3、了解过cglib动态代理吗?他跟jdk动态代理的区别是什么?
优先是jdk动态代理,其次是cglib动态代理
原理: 其实就是动态的创建⼀个代理类出来,创建这个代理类的实例对象,在这个⾥⾯引⽤你真正⾃⼰写的类,所有的⽅法的调⽤,都是先⾛代理类的对象,他负责做⼀些代码上的增强,再去调⽤你写的那个类 。 Spring⾥使⽤AOP ,⽐如说你对⼀批类和他们的⽅法做了⼀个切⾯,定义好了要在这些类的⽅法⾥增强的代码,S pring 必然要对那些类⽣成动态代理,在动态代理中去执⾏你定义的⼀些增强代码。如果你的类是实现了某个接⼝的,Spring AOP 会使⽤ JDK 动态代理,⽣成⼀个跟你实现同样接⼝的⼀个代理类,构造⼀个实例对象出来。- jdk动态代理:他其实是在你的类有接⼝的时候,就会来使⽤。
- cglib动态代理:很多时候我们可能某个类是没有实现接⼝的,Spring aop会改⽤cglib来⽣成动态代理,他是⽣成你的类的⼀个⼦类,他可以动态⽣成字节码,覆盖你的⼀些⽅法,在⽅法⾥加⼊增强的代码。
4、能说说Spring中的Bean是线程安全的吗?
Spring
容器中的
bean
可以分为
5
个范围:
- singleton:默认,每个容器中只有⼀个bean的实例。
- prototype:为每⼀个bean请求提供⼀个实例。
⼀般来说下⾯⼏种作⽤域,在开发的时候⼀般都不会⽤,99.99%的时候都是⽤singleton单例作⽤域。
- request:为每⼀个⽹络请求创建⼀个实例,在请求完成以后,bean会失效并被垃圾回收器回收。
- session:与request范围类似,确保每个session中有⼀个bean的实例,在session过期后,bean会随之失效。
- global-session。
@Service
public class MyServiceImpl implement Service{
private int data;
public void doService(){
data++;
}
}
答案是否定的,绝对不可能是线程安全的,spring bean默认来说是singleton,都是线程不安全的,java web系统⼀般来说很少在 spring bean⾥放⼀些实例变量,⼀般来说他们都是多个组件互相调⽤,最终去访问数据库的,故bean中基本都不放实例变量。因为Tomcat会通过多个线程接收多个请求,并发访问Spring容器的单例bean。
当设置singleton时Spring容器只会创建一个实例对象,MyController和MyServiceImpl都是一个实例对象。实际上Spring容器bean是单实例,只是多线程会并发访问数据库。
5、Spring的事务实现原理是什么?能聊聊你对事务传播机制的理解吗?
Spring IOC和AOP,动态代理技术,bean的线程安全问题,事务机制。
事务的实现原理,如果说你加了⼀个@Transactional注解 ,此时就 spring会使⽤AOP思想,对你的这个⽅法在执⾏之前,先去开启事务,执⾏完毕之后,根据你⽅法是否报错,来决定回滚还是提交事务。 事务传播机制: 在多个方法上添加@Transactional,并相互调用设计事务的传播机制。1、PROPAGATION_required:如果当前没有事务,就创建⼀个新事务,如果当前存在事务,就加⼊该事务,该设置是最常⽤的设置。对于method1和method2都是用Requeest事务时,只会开启一个事务。
// 开启⼀个事务
// 执⾏⽅法A的代码,接着执⾏⽅法B的代码
// 提交或者回滚事务
2、PROPAGATION_SUPPORTS:⽀持当前事务,如果当前存在事务,就加⼊该事务,如果当前不存在事务,就以⾮事务执⾏。如果单独调用方法B时不会使用事务。
@Transaction(propagation=Propagation.supports)
public void methodB(){
...
}
3、PROPAGATION_mandatory:⽀持当前事务,如果当前存在事务,就加⼊该事务,如果当前不存在事务,就抛出异常。如果单独调用方法B时会抛出异常。
@Transaction(propagation=Propagation.supports)
public void methodB(){
...
}
4、 PROPAGATION_requires_new:创建新事务,⽆论当前存不存在事务,都创建新事务。
@Transaction(propagation=Propagation.requried)
public void methodA(){
doSomethingPre();
method2();
doSomethingPost();
...
}
@Transaction(propagation=Propagation.requries_new)
public void methodB(){
...
}
// 开启⼀个事务 1 // 执⾏⽅法 A ⾥的⼀些代码, doSomethingPre() // 开启⼀个事务 2 // 执⾏⽅法 B ⾥的⼀些代码 // 提交或者回滚事务 2 // 执⾏⽅法 A ⾥的⼀些代码, doSomethingPost() // 提交或者回滚事务 15、 PROPAGATION_NOT_SUPPORTED :以⾮事务⽅式执⾏操作,如果当前存在事务,就把当前事务挂起。 6、PROPAGATION_NEVER :以⾮事务⽅式执⾏,如果当前存在事务,则抛出异常。 7、 PROPAGATION_NESTED: 如果当前存在事务,则在嵌套事务内执⾏。如果当前没有事务,则按 REQUIRED 属性执⾏。
// 开启⼀个事务 // 执⾏⽅法 A ⾥的⼀些代码, doSomethingPre() // 设置⼀个回滚点, savepoint // 执⾏⽅法 B ⾥的⼀些代码 // 如果⽅法 B ⾥抛出了异常,此时进⾏回滚,回滚到之前的 savepoint // 执⾏⽅法 A ⾥的⼀些代码, doSomethingPost() // 提交或者回滚事务嵌套事务,外层的事务如果回滚,会导致内层的事务也回滚;但是内层的事务如果回滚,仅仅是回滚⾃⼰的代码。
面试:事务传播机制
⽐如说,我们现在有⼀段业务逻辑, ⽅法A调⽤⽅法B,我希望的是如果说⽅法A出错了,此时仅仅回滚⽅法A,不能回滚⽅法B,必须得⽤REQUIRES_NEW,传播机制 ,让他们俩的事务是不同的。 ⽅法A调⽤⽅法B,如果B出错⽅法B只能回滚他⾃⼰,⽅法A可以带着⽅法B⼀起回滚,NESTED嵌套事务 。6、能画⼀张图说说Spring Boot的核⼼架构吗?
Spring boot启动的时候⼀个流程图,他是spring这个项⽬发展到⼀定阶段之后的⼀个产物。
Spring框架, mybatis,spring mvc去做⼀些开发,打包部署到线上的tomcat⾥去,tomcat启动了,他就会接收http请求,转发给spring mvc框架,调⽤controller -> service -> dao -> mybatis(sql语句)。java web开发的时候,在这⾥整合进来redis、elasticsearch、还有很多其他的⼀些东西,rabbitmq、zookeeper等等,诸如此类东西 。 国外的spring 开源社区,就发起了⼀个项⽬S pring boot ,我们基于 spring boot 直接进⾏开发,⾥⾯还是使⽤ spring + spring mvc + mybatis⼀些框架,我们可以⼀定程度上来简化我们之前的开发流程做很多的配置,⾃⼰去定义⼀些bean ,流程⽐较繁琐。 Spring boot内嵌⼀个tomcat去直接让我们⼀下⼦就可以把写好的java web系统给启动起来,直接运⾏⼀个main⽅法,spring boot就直接把tomcat服务器给跑起 来,把我们的代码运⾏起来。. ⾃动装配: ⽐如说我 们可以引⼊mybatis,我其实主要引⼊⼀个starter依赖,他会⼀定程度上个⾃动完成mybatis的⼀些配置和定义,不需要我们⼿⼯去做⼤量的配置了,⼀定程度上简化我们搭建⼀个⼯ 程的成本。引⼊⼀些mybatis 的 jar 包,还有 mybatis 依赖的⼀些其他的 jar 包,然后动⼿编写⼀些 xml 配置⽂件,然后定义⼀些 bean ,写⼀些 sql 语句,写⼀些dao 代码,此时就可以使⽤ mybatis 去执⾏ sql 语句了。 只要引⼊⼀个starter,他会⾃动给你引⼊需要的⼀些jar包,做⾮常简单的、必须的⼀些配置 ,⽐如数据库的地址,⼏乎就不⽤你做太多的其他额外的配置了,他会⾃动帮你去进⾏⼀些配置,定义和⽣成对应的bean。 ⽣成的bean⾃动注⼊⽐如你的 dao ⾥去,让你免去⼀些⼿⼯配置 + 定义 bean 的⼀些⼯作 spring boot + spring + spirng mvc + mybatis + XXX之类的技术去进⾏开发,后续很多配置和定义的⼀些繁琐的重复性的⼯作就免去了,⾃动装配的⼀些功能,⾃动给你把⼀些事情⼲完了,不需要你去做了 。 基于 spring boot开发的时候,他⼤致的⼀个⼯作流程是什么样⼦的? 直接执行main方法,他⾃动启动⼀个内嵌的tomcat(web服务器),Springboot程序会使用各种框架(SpringMVC+Spring+Mybatis+各种框架),其中Spring容器会扫描所有代码,根据注解实例化bean, 并进行依赖注入。tomcat开启端口接收请求,开启多个线程处理多个请求并发处理。 Springboot会自动完成bean的装配和定义,使用mybatis框架时,自动将bean注入,调用数据库等 。7、能画⼀张图说说Spring的核⼼架构吗?
Spring核⼼源码,spring核⼼架构图,⾥⾯包含了各种类和API之间的调⽤,引⼊⼀个别的点,把Spring的核⼼的东西再梳理⼀下。
Spring容器维护bean的引用关系,Spring还会 使用动态代理。
spring bean⽣命周期 从创建 -> 使⽤ -> 销毁,你在系统⾥⽤xml 或者注解,定义⼀⼤堆的 bean。 ( 1 )实例化 Bean :如果要使⽤⼀个 bean 的话。 ( 2 )设置对象属性(依赖注⼊):他需要去看看,你的这个 bean 依赖了谁,把你依赖的 bean 也创建出来,给你进⾏⼀个注⼊,⽐如说通过构造函数,setter。 ( 3 )处理Aware接⼝: 如果这个Bean已经实现了ApplicationContextAware接⼝,spring容器 就会调⽤我们的 bean 的 setApplicationContext(ApplicationContext) ⽅法, 传⼊Spring上下⽂,把spring容器给传递给这个bean 。 ( 4 ) BeanPostProcessor 如果我们想在bean实例构建好了之后,此时在这个时间点,我们想 要对Bean进⾏⼀些⾃定义的处理,那么可以让Bean实现了BeanPostProcessor接 ⼝,那将会调⽤ postProcessBeforeInitialization(Object obj, String s) ⽅法。 ( 5 ) InitializingBean 与 init-method 如果Bean在 Spring 配置⽂件中配置了 init-method 属性,则会⾃动调⽤其配置的初始化⽅法。 ( 6 )如果 Bean 实现了 BeanPostProcessor 接⼝,将会调⽤ postProcessAfterInitialization(Object obj, String s) ⽅法。(7)DisposableBean 当Bean不再需要时,会经过清理阶段,如果Bean实现了DisposableBean这个接⼝,会调⽤其实现的destroy()⽅法;
( 8 ) destroy-method 最后,如果这个Bean 的 Spring 配置中配置了 destroy-method 属性,会⾃动调⽤其配置的销毁⽅法。 创建+初始化⼀个bean -> spring容器管理的bean长期存活 -> 销毁bean(两个回调函数)8、能说说Spring中都使⽤了哪些设计模式吗?
⼯⼚,单例,代理。
Sprin g 源码底层去看,很多种设计模式的⼀个运用。 ⼯⼚模式: spring ioc核⼼的设计模式的思想提现,他⾃⼰就是⼀个⼤的⼯⼚,把所有的bean实例都给放在了spring容器⾥(⼤⼯⼚),如果你要使⽤bean,就找spring容器就可以了,你⾃⼰不⽤创建对象了。单例模式:Spring默认对每个bean⾛的都是⼀个单例模式,确保说你的⼀个类在系统运⾏期间只有⼀个实例对象,只有⼀个bean,⽤到了⼀ 个单例模式的思想,保证了每个bean都是单例的。
代理模式: 对⼀ 些类的⽅法切⼊⼀些增强的代码,会创建⼀些动态代理的对象,让你对那些⽬标对象的访问,先经过动态代理对象,动态代理对象先做⼀些增强的代码,调⽤你的⽬标对象 。在设计模式⾥,就是⼀个代理模式的体现和运⽤,让动态代理的对象,去代理了你的⽬标对象,在这个过程中做⼀些增强的访问。9、能画⼀张图说说Spring Web MVC的核⼼架构吗?
- Tomcat的⼯作线程将请求转交给Spring mvc框架的DispatcherServlet。
- DispatcherServlet查找@Controller注解的controller,我们⼀般会给controller加上你@RequestMapping的注解,标注说哪些 controller⽤来处理哪些请求,此时根据请求的uri,去定位到哪个controller来进⾏处理。
- 根据@RequestMapping去查找,使⽤这个controller内的哪个⽅法来进⾏请求的处理,对每个⽅法⼀般也会加@RequestMapping 的注解。
- 他会直接调⽤我们的controller⾥⾯的某个⽅法来进⾏请求的处理。
- 我们的controller的⽅法会有⼀个返回值,以前的时候,⼀般来说还是⾛jsp、模板技术,我们会把前端页⾯放在后端的⼯程⾥⾯,返回⼀个页⾯模板的名字,spring mvc的框架使⽤模板技术,对html页⾯做⼀个渲染;现在:返回⼀个json串,前后端分离,可能前端发送⼀个请求过来,我们只要返回json数据。
- 再把渲染以后的html页⾯返回给浏览器去进⾏显⽰;前端负责把html页⾯渲染给浏览器就可以了。



