spring 面试题

什么是spring?

Spring 是一个轻量级开发框架,旨在提高开发人员的开发效率以及系统的可维护性。

我们一般说的 Spring 框架指的都是 Spring Framework,它是很多模块的集合,使用这些模块可以提高我们开发效率及系统的可维护性。

Spring Framework的核心模块?

  • spring 核心容器:Bean、Core、Context、SpEL
  • 数据访问:jdbc、orm、transaction
  • web:web、servlet
  • AOP
  • Aspects
  • JMS
  • Test
  • instrumentation

@RestController 与 @Controller 的区别?

  • @Controller不与@ResponseBody配合使用的话,会返回一个视图,一般用在前后端不分离的项目。
  • @RestController返回json或者xml形式的数据,用于前后端分离的项目。
  • @RestController相当于@Controller与@ResponseBody配合使用。

什么是spring的 IoC?

控制反转是一种设计思想,就是将 bean 的创建、管理的权利,控制 bean 的整个生命周期交给IoC容器管理, 对于 IoC 来说,最重要的就是容器

什么是spring/IoC容器?

IOC容器就是负责创建bean、管理 bean 的生命周期,控制着 bean 的依赖注入的容器。

IOC容器是指ApplicationContext,它是 BeanFactory 的子类,更好的补充并实现了 BeanFactory 的。

BeanFactory简单理解就是HashMap,key是bean name,value是bean对象。

什么是Bean?

Bean 其实就是包装了的 Object,无论是控制反转还是依赖注入,它们的主语都是 object,而 bean 就是由第三方包装好了的 object。

什么是依赖注入?

程序运行需要依赖外部的资源,容器加载了外部资源,然后把这些资源注入给程序内的对象,维护了程序内外对象之间的依赖关系。

依赖注入的方式?

  • Setter注入:使用set方法注入。

  • 构造器注入:使用构造注入。

  • 接口注入:通过spring提供的容器接口,xxAware进行依赖注入。

  • 方法注入:

    • @Autowired:是Spring自带的注解,依照类型进行装配。
    • @Bean:产生一个Bean对象,然后这个Bean对象交给Spring管理。
    • @Resource:@Resource`是JavaEE的标准,Spring对它是兼容性的支持,依照名称进行装配。
    • @Inject(不常见):jsr330中的规范。

自动装配方式?

  • no:(默认)无自动装配
  • byName:按属性名称自动装配。
  • byType:按照类型自动装配
  • constructor:通过构造器自动装配

IoC 能给我们带来什么好处?

解藕,它把对象之间的依赖关系转成用配置文件来管理,由 Spring IoC Container 来管理。

什么是AOP?

AOP又叫面向切面编程,它是一种编程范式,通过预编译的方式和运行期动态代理实现程序功能一种技术。

通常用来封装不同业务所共有的逻辑,比如常见的事务管理、日志管理、权限控制等。同时实现AOP的方式也有两种:cglib 以及 jdk两种方式来实现。

为什么要有AOP?

对于不同业务所共有的逻辑的封装,比如事务管理、日志管理、权限控制等。如果要每个方法手动添加,工作量太大,不太现实。这时候可以用AOP通过规则匹配,对匹配上的方法进行统一日志打印。

AOP的核心概念?

  • 切面(Aspect): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。一般使用 @Aspect 注解或者 <aop:aspect> 来定义一个切面。
  • 连接点(Join Point):程序执行中的特定点,比如方法执行、处理一个异常等
  • 切点(Pointcut):通过一种规则匹配的正则表达式,当有连接点可以匹配到切点时,就会触发该切点相关联的指定通知。
  • 通知(Advice):在切面中某个连接点采取的动作,通知方式也有5种
    • around(环绕通知):前后都加
    • before(前置通知)
    • after(后置通知)
    • exception(异常通知)
    • return(返回通知)
  • 织入(Weaving):链接切面和目标对象创建一个通知对象的过程。

AOP的执行过程?

当调用具体的方法开始时,会被DynamicAdvisedInterceptor拦截器拦截,在DynamicAdvisedInterceptor中有个List<Object> chain存放了通知方法,然后通过CglibMethodInvocation来启动advice通知,这里使用了责任链模式,通过循环调用,一直到整个chain执行完成。

AspectJ是什么?能做什么?

AspectJ是一个易用的功能强大的AOP框架。

可以单独使用,也可以整合到其它框架中。

单独使用AspectJ时需要使用专门的编译器ajc。

AspectJ和Spring AOP的区别?

Spring AO:

  • 基于动态代理来实现,默认如果使用接口的,用JDK提供的动态代理实现,如果是方法则使用CGLIB实现
  • Spring AOP需要依赖IOC容器来管理,并且只能作用于Spring容器,使用纯Java代码实现
  • 在性能上,由于Spring AOP是基于动态代理来实现的,在容器启动时需要生成代理实例,在方法调用上也会增加栈的深度,使得Spring AOP的性能不如AspectJ的那么好

AspectJ:

  • AspectJ属于静态织入,通过修改代码来实现,有如下几个织入的时机:
    • 编译期织入: 如类 A 使用 AspectJ 添加了一个属性,类 B 引用了它,这个场景就需要编译期的时候就进行织入,否则没法编译类 B。
    • 编译后织入:已经生成了 .class 文件,或已经打成 jar 包了,这种情况我们需要增强处理的话,就要用到编译后织入。
    • 类加载后织入:在加载类的时候进行织入
  • 性能比Spring AOP更好
  • 比 Spring AOP 更复杂

Spring 中的 bean 的作用域?

  • singleton : 唯一 bean 实例,Spring 中的 bean 默认都是单例的。

  • prototype : 每次请求都会创建一个新的 bean 实例。

  • request : 每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。

  • session : 每一次HTTP请求都会产生一个新的 bean,该bean仅在当前 HTTP session 内有效。

Spring 中的单例 bean 的线程安全问题?

当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。

解决办法:

  • 在Bean对象中尽量避免定义可变的成员变量(不太现实)。
  • 在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在 ThreadLocal 中(推荐的一种方式)。

Spring 中的 bean 生命周期?

  • Bean 容器找到配置文件中 Spring Bean 的定义。
  • spring 容器利用 Java反射API 创建一个Bean的实例。
  • 如果涉及到一些属性值 利用 set()方法设置一些属性值。
  • 如果 Bean 实现了 BeanNameAware 接口,调用 setBeanName()方法,传入Bean的名字。
  • 如果 Bean 实现了 BeanClassLoaderAware 接口,调用 setBeanClassLoader()方法,传入 ClassLoader对象的实例。
  • 如果Bean实现了 BeanFactoryAware 接口,调用 setBeanFactory()方法,传入 BeanFactory 对象的实例。
  • 与上面的类似,如果实现了其他 *.Aware接口,就调用相应的方法。
  • 如果有和加载这个 Bean 的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessBeforeInitialization() 方法
  • 如果Bean实现了InitializingBean接口,执行afterPropertiesSet()方法。
  • 如果 Bean 在配置文件中的定义包含 init-method 属性,执行指定的方法。
  • 如果有和加载这个 Bean的 Spring 容器相关的 BeanPostProcessor 对象,执行postProcessAfterInitialization() 方法
  • 当要销毁 Bean 的时候,如果 Bean 实现了 DisposableBean 接口,执行 destroy() 方法。
  • 当要销毁 Bean 的时候,如果 Bean 在配置文件中的定义包含 destroy-method 属性,执行指定的方法。

什么是spring MVC?

MVC是模型(Model)-视图(view)-控制器(controller)的缩写。

模型:封装了数据和对数据的操作,与数据库进行交互。

视图:是应用和用户之间的接口,负责显示模型的数据给用户。

控制器:负责视图和模型之间的交互,控制对用户输入的响应、响应方式和流程。

SpringMVC 工作原理了解吗?

1、 用户发送请求至前端控制器DispatcherServlet。

2、 DispatcherServlet收到请求调用HandlerMapping处理器映射器。

3、 处理器映射器找到具体的处理器(可以根据xml配置、注解进行查找:handler),生成处理器对象及处理器拦截器(如果有则生成HandlerExecutionChain)一并返回给DispatcherServlet。

4、DispatcherServlet调用HandlerAdapter处理器适配器。

5、 HandlerAdapter经过适配调用具体的处理器(Controller,也叫后端控制器)。

6、Controller执行完成返回ModelAndView。

7、 HandlerAdapter将controller执行结果ModelAndView返回给DispatcherServlet。

8、 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。

9、 ViewReslover解析后返回具体View,这个view不是完整的,仅仅是一个页面(视图)名字,且没有后缀名。

10、DispatcherServlet根据View进行渲染视图(即将模型数据填充至视图中)。

11、 DispatcherServlet响应用户。

Spring 框架中用到了哪些设计模式?

工厂设计模式 : Spring使用工厂模式通过 BeanFactoryApplicationContext 创建 bean 对象。

代理设计模式 : Spring AOP 功能的实现。

单例设计模式 : Spring 中的 Bean 默认都是单例的。

模板方法模式 : Spring 中 jdbcTemplatehibernateTemplate 等以 Template 结尾的对数据库操作的类,它们就使用到了模板模式。

观察者模式: Spring 事件驱动模型就是观察者模式很经典的一个应用。

@Component 和 @Bean 的区别是什么?

  • 作用对象不同: @Component 注解作用于类,而@Bean注解作用于方法。
  • 扫描到Spring容器中的方式不同:@Component 通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中,@Bean注解通常是我们在标有该注解的方法中定义产生这个bean的逻辑。
  • 相同:都是用来注册Bean并装配到Spring容器中,但是Bean比Component的自定义性更强。可以实现一些Component实现不了的自定义加载类。

将一个类声明为Spring的 bean 的注解有哪些?

我们一般使用 @Autowired 注解自动装配 bean,要想把类标识成可用于 @Autowired 注解自动装配的 bean 的类,采用以下注解可实现:

  • @Component :通用的注解,可标注任意类为 Spring 组件。如果一个Bean不知道属于哪个层,可以使用@Component 注解标注。
  • @Repository : 对应持久层即 Dao 层,主要用于数据库相关操作。
  • @Service : 对应服务层,主要涉及一些复杂的逻辑,需要用到 Dao层。
  • @Controller : 对应 Spring MVC 控制层,主要用户接受用户请求并调用 Service 层返回数据给前端页面。

Spring 管理事务的方式有几种?

  • 编程式事务,在代码中硬编码。(不推荐使用)

  • 声明式事务,在配置文件中配置(推荐使用)。分为两种:

    • 基于XML的声明式事务
    • 基于注解的声明式事务

Spring 事务中的五种隔离级别?

TransactionDefinition.ISOLATION_DEFAULT: 使用后端数据库默认的隔离级别,Mysql 默认采用的 REPEATABLE_READ隔离级别。spring 默认的隔离级别

TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 读未提交,可能会导致脏读、幻读或不可重复读

TransactionDefinition.ISOLATION_READ_COMMITTED: 读已提交,可以阻止脏读,但是幻读或不可重复读仍有可能发生

TransactionDefinition.ISOLATION_REPEATABLE_READ: 可重复读,对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。

TransactionDefinition.ISOLATION_SERIALIZABLE: 序列化,最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。

什么是事务传播行为?

事务传播行为是描述,当发生方法调用时,事务在当前方法和被调用方法之间如何传播。

事务传播的七钟行为?

事务传播行为类型 说明
PROPAGATION_REQUIRED 如果当前没有事务,就新建一个事务,如果已经存在一个事务中,加入到这个事务中。这是最常见的选择。spring默认的传播行为。
PROPAGATION_SUPPORTS 支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY 使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW 新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER 以非事务方式执行,如果当前存在事务,则抛出异常。
PROPAGATION_NESTED 如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

@Transactional(rollbackFor = Exception.class)注解了解吗?

  • @Transactional注解作用于类上时,该类的所有 public 方法将都具有该类型的事务属性。当@Transactional注解作用于方法上时,这个方法将具有事务属性。
  • @Transactional注解中如果不配置rollbackFor属性,那么事物只会在遇到RuntimeException的时候才会回滚,加上rollbackFor=Exception.class,可以让事物在遇到非运行时异常时也回滚。
  • @Transactional只有在public方法上才会生效,事务进行时,如果不是public方法,会直接return。

非事务方法A中调用事务方法B,事务的行为事怎么样的?

当非事务方法A调用非事务方法B时,不会开启新事务,也是就会B的事务不会生效。因为spring的事务时由动态代理实现的,动态代理最终会调用原始对象的方法,调用原始对象的方法时不会触发代理了。

同一个Service中,事务方法A调研事务方法B,行为事怎么样的?

事务A生效,而事务B不生效。原因跟上一个问题类似,解决办法有两个:

  • 将两个方法拆分到两个Service中,进行调用。

  • 通过 AopContext.currentProxy()获取当前代理对象,然后用代理对象调用方法,此时还需要手动暴露代理对象 @EnableAspectJAutoProxy(exposeProxy = true),此时会让A方法和B方法都开启各自的事务进行执行。

spring 是如何解决循环依赖的?

解决的前提:

  • 循环依赖的双方都是 set方法注入。
  • 构造器注入需要分情况:A、B循环依赖,如果A先实例化,则A必须是set方法注入,B可以是构造器注入。否则无法解决循环依赖。
  • Bean是单例模式的,原型模式不支持循环依赖,会抛出bean并发创建异常(BeanCurrentlyInCreationException)。

解决过程:

spring bean的创建,本质上是分两步,第一步是对象的实例化(无参构造器),第二步是对象属性赋值。

在spring中,为了解决循环依赖,设置了三重缓存,分别是完成实例化和初始化的单例池(singletonObjects),只完成了对象实例化,没有完成初始化的单例池(earlySingletonObjects),和singletonFactory。

  • 首先实例A对象,然后给A设置属性值,发现依赖B,在第一二三级缓存中都没有查找到B,于是将A放到第三级缓存中,去实例化B。
  • 实例化B后,发现依赖A,依次从一二三级缓存中,在第三级缓存中找到了A,于是将A放到第二级缓存,删除第三级缓存中的A。将A设置给B,完成B的初始话。将B放到第一级缓存中。
  • 继续初始化A,从第一级缓存中拿到B,设置给A,完成A的初始化。
  • 从而解决循环依赖。

5.那 BeanFactory 和 FactoryBean 又有什么区别?

  • 这两个是不同的产物

  • BeanFactory 是 IOC 容器,实现的一个接口,用来扩展IOC容器,是用来承载对象。

  • FactoryBean 是一个接口,为 Bean 提供了更加灵活的处理方式,通过代理一个Bean对象,对方法前后做一些操作。

springBoot 自动装配原理?

  • spring boot的启动类上的注解@SpringBootApplication可以看做是@Configuration@EnableAutoConfiguration@ComponentScan 注解的集合。

  • 其中@EnableAutoConfiguration是实现自动装配的核心注解。

  • 首先判断应用是不是开启了自动装配配置,如果开启了,进一步读取所有jar包下的 META-INF/spring.factories文件中org.springframework.boot.autoconfigure.EnableAutoConfiguration中配置的所有需要自动装配的类的全限定名。

  • 然后排除掉不需要加载的、重复的、再根据条件筛选后剩下的都是需要进行自动装配类的全限定名。

  • 根据类的全限定名,进行装配到spring 容器中。

如何实现一个Starter?

  • 第一步:创建一个test-spring-boot-starter项目,引入依赖
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
  • 第二步:创建一个配置类,配置类中,自动装配了一个叫TestTemplate的对象。
@Configuration
public class TestAutoConfiguration {

  @Bean
  @ConditionalOnMissingBean(value = TestTemplate.class)
  public TestTemplate getTestTemplate(){
    return new TestTemplate();
  }

}
  • 第三步:在工程下的resources目录中创建META-INF/spring.factories文件。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.example.TestAutoConfiguration
  • 第四步:在新项目中引入test-spring-boot-starter,将项目跑起来,并获取这个自动装配的对象。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348

推荐阅读更多精彩内容