栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring系列面试题(Spring、SpringMvc、SpringBoot)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring系列面试题(Spring、SpringMvc、SpringBoot)

1、springboot、springmvc和spring有什么区别

spring 是一个ioc容器、用来管理bean、使用依赖注入实现控制反转、可以很方便整合各种框架、提供aop弥补oop的代码重复问题,方便将不同类相同方法抽取成切面,自动注入给方法执行,比如日志、异常

springmvc 是spring对web框架的一个解决方案,提供了前端控制器,用来接收请求,然后定义了一套路由策略(url到handle的映射)及适配执行handle,将handle结果使用视图解析技术生成试图展示给前端

springboot 是spring提供的一个快熟开发工具包,让程序员更加方便,更加快速的开发spring+springmvc应用,简化了配置(约定了默认配置)。整合了一系解决方案(starter机制),开箱即用

2、springmvc工作流程

1、 用户发送http请求至前端控制器(DispatcherServlet)

2、前端控制器会去遍历所有的处理器映射器(HandlerMapping),寻找一个可以处理该HTTP请求的处理器,生成处理器及处理器拦截器一并返回给前端控制器

3、前端控制前会调用处理器适配器(HandlerAdapter),处理器适配器将请求传递给处理器,处理器(Controller)调用Service业务层对数据逻辑进行处理(交给Mybatis框架),控制器完成请求处理后,返回ModelAndView对象传给处理器适配器,最终由处理器适配器返回给前端控制器。

4、 前端控制器将ModelAndView传给视图解析器,并根据View进行渲染视图

5、将处理过后的ModelAndView视图交给前端控制器,并由前端控制器响应给客户端(展示画面)。

具体参考:SpringMVC工作流程 -- 详解_布诺i的博客-CSDN博客_springmvc工作流程

3、mybatis里的#{}和${}的区别

#{}是预编译处理,${}是字符串替换。

Mybatis在处理#{}时,会将sql中的#替换为?号,调用PreparedStatement的set方法来赋值;

Mybatis在处理${}时,就是把${}替换成变量的值。

使用#{}可以有效的防止SQL注入,提高系统安全性。

4、谈谈对ioc的理解

ioc容器实际上是一个map,里面存放是各种对象,在项目启动的时候会读取配置文件里的bean节点,根据限定类名使用反射创建对象放入map里面,这时候map里面有各种对象,接下来我们在代码中使用里面的对象时候,通过依赖注入。

依赖注入是实现ioc的方法,就是在ioc容器在运行期间,动态的将某种依赖关系注入到对象中。

控制反转指控制权不是由当前的对象来管理的,由其它类来管理。

5、谈谈对aop的理解

将程序中的交叉业务逻辑(比如日志、事务),封装成一个切面,然后注入到目标对象中,aop可以对某个对象或某个对象的功能进行增强,比如对象中的方法进行增强,可以在执行某个方法之前额外的做一些事情,在某个方法执行之后额外的做一些事情

6、描述下spring bean 生命周期

Spring的生命周期被分为五个阶段:

  1. 创建前准备阶段
  2. 创建实例阶段
  3. 依赖注入阶段
  4. 容器缓存阶段
  5. 销毁实例阶段

创建前准备阶段:

这个阶段主要是开始bean加载之前,从spring上下文中去获取相关的配置并且解析,然后找到bean有关的一些配置内容

创建实例阶段:

这个阶段主要是通过反射去创建bean实例对象,并且扫描和解析bean的声明的一些属性.

依赖注入阶段:

这个阶段会监测被实例化的bean是否会存在其他依赖,如果存在其他依赖,就需要将这些依赖注入到bean里面,比如说通过读取注解@Autowired等注解去完成依赖注入的配置,这个阶段又会触发一些扩展的调用,比如说常见的扩展类BeanPostProcessors,它用来实现bean初始化前后的一个回调;再比如InitializingBean,这个类里面有一个afterPropertiesSet方法,它给属性去赋值.其次还会调用一些后缀Aware接口:

如果 Bean 实现了 BeanNameAware 接口,则 Spring 调用 Bean 的 setBeanName() 方法传入当前 Bean 的 id 值。
如果 Bean 实现了 BeanClassLoaderAware 接口,则 Spring 调用 setBeanClassLoader() 方法传入classLoader的引用。
如果 Bean 实现了 BeanFactoryAware 接口,则 Spring 调用 setBeanFactory() 方法传入当前工厂实例的引用。
还有其他一些诸如 EnvironmentAware ,EmbeddedValueResolverAware等接口
容器缓存阶段

这个阶段主要是将bean保存在IOC容器中缓存起来,到了这个阶段,bean就可以去被开发者使用了,那么这个阶段涉及到的操作有,常见的init-method属性配置的方法会在这个阶段被调用,比如说BeanPostProcessors类的后置处理方法,如postProcessAfterInitialization.

销毁实例阶段

这个阶段是完成spring应用上下文的时候,将去销毁spring上下文中所有bean,如果bean实现了DisposableBean接口的话,或者配置了destory-method属性的方法都将在这个阶段被调用.

参考:https://blog.csdn.net/weixin_47303191/article/details/124433022

7、springboot自动配置原理

自动装配,简单来说就是自动把第三方组件的Bean装载到Spring IOC器里面,不需要开发人员再去写Bean的装配配置。

在Spring Boot应用里面,只需要在启动类加上@SpringBootApplication注解就可以实现自动装配

@SpringBootApplication是一个复合注解,真正实现自动装配的注解@EnableAutoConfiguration。

原理是:

1、引入Starter启动依赖组件的时候,这个组件里面必须要包含@Configuration配置类,在这个配置类里面通过@Bean注解声明需要装配到IOC容器的Bean对象

2、这个配置类是放在第三方的jar包里面,然后通过SpringBoot中的约定优于配置思想,把这个配置类的全路径放在classpath:/META-INF/spring.factories文件中。这样SpringBoot就可以知道第三方jar包里面的配置类的位置,这个步骤主要是用到了Spring里面的SpringFactoriesLoader来完成的。

3、SpringBoot拿到所第三方jar包里面声明的配置类以后,再通过Spring提供的ImportSelector接口,实现对这些配置类的动态加载

8、springboot核心注解是什么,它有哪些注解组成

@SpringBootApplication是核心注解 这个注解是整个SpringBoot项目的入口注解,是SpringBoot项目必不可少的注解,它是复合注解,由一下注解组成:

1、@SpringBootConfiguration:SpringBoot的配置类,将此注解标注在某个类上表示这个是一个SpringBoot的配置类。

2、@EnableAutoConfiguration:开启自动配置功能,SpringBoot会帮我们自动配置;

3、@ComponentScan:开启包的扫描功能

9、springboot中如何解决跨域问题

跨域都是通过前端JSONP来解决,但只能处理get类型请求,像post、put、delete就不支持,所以一般采用后端跨域通过WebMvcConfiguration接口来重写addCorsMappings方法,解决跨域问题。

10、springboot多环境切换的⽅法


1111是Spring对不同环境提供不同配置功能的⽀持,可以通过激活不同的环境版本,实现快速切换环境;
例如:
application-test.properties 代表测试环境配置
application-dev.properties 代表开发环境配置
但是Springboot并不会直接启动这些配置⽂件,它默认使⽤application.properties主配置⽂件;
我们需要通过⼀个配置来选择需要激活的环境:
spring.profiles.active=dev
spring.profiles.active可以指定配置环境,如指定为dev就会选择 application-dev.properties ⽂件作为配置环境,同理,要指定
不同的环境配置,只需指定application-xxx.properties的xxx即可。
 

11、spring事务什么时候会失效

spring事务的原理是aop ,进行了切面的增强,那么失败的根本原因是这个aop不起作用的,常见如下:1、发生自调用:类里面使用this调用本类的方法,此时this对象不是代理类,而是userService对象本身

2、方法不是public  @Transactional只能用于public方法上,否则事务不会生效

3、数据库不支持事务 4、没被spring管理  5、异常被吃掉,事务不会回滚

12、说下mybatis的一级缓存和二级缓存

一级缓存是指sqlSession,默认都是开启的,在同一个sqlsession中执行相同的sql,第一次去查询数据库,存在缓存中,第二次直接从缓存中获取,当有insert update delete 操作时,会清空缓存,重新获取

二级缓存是指mapper级别的,默认不开启,如果多个sqlsession之前需要共享内存,则需要使用二级缓存,使用二级缓存属性类,需要实现序列化接口(用来保存对象的状态)

13、说清楚spring如何解决循环依赖

循环依赖,注意,这里说的是依赖,而不是调用,这是两个概念,一定不要混淆。

循环依赖从字面意思来看,就是A依赖B,然后B依赖A,当然,这个依赖过程也可以更长,不一定就非要两个互相依赖,十个八个也是循环依赖,只要形成了一个闭环。

Spring中的循环依赖包括两种,构造器循环依赖和setter循环依赖。

构造器循环依赖

当使用构造器注入方式时,Spring是无法解决循环依赖的,在出问题时会报错,抛出BeanCurrentlyInCreationException异常。

setter循环依赖

主要来说一下setter循环依赖,通过Spring在创建bean时的一级、二级、三级缓存的概念解决的。

注意:这里解决的只是单例模式下的setter循环依赖,非单例模式下的依然没有办法解决,在业务环境中应当尽量避免此类情况。

创建Bean的缓存概念:

一级缓存:singletonObjects,可以称为成品池,存放完全实例化属性赋值完成的Bean,直接可以使用。

二级缓存:earlySingletonObjects,可以称为半成品池,存放早期Bean的引用,尚未属性装配的Bean

三级缓存:singletonFactories,可以称为工厂池,存放实例化完成的Bean工厂。

1)X1在创建时,首先根据构造函数创建bean,暴露一个Factory给三级缓存(工厂池),并且将其放入二级缓存(半成品池);然后进行属性的装配,发现有依赖关系,查询三级缓存是否存在,如没有,前往创建。

2)创建X2时,同X1,前往创建X3。

3)创建X3时,这时三级缓存中已经存在X1,即可直接注入,然后将X3的bean对象放入一级缓存(成品池)。

4)随后X2、X1依次可以创建完成,并且放入一级缓存中。

5)如此就完成setter循环依赖问题的解决,核心就是这个三级缓存。

注意:这里的bean对象创建完成,放入一级缓存中时,会将对应的二级、三级缓存清掉。

参考:高频面试题-说清楚Spring如何解决循环依赖? - SegmentFault 思否

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/952674.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号