谈谈你对Spring的理解
Spring 更像是一个生态,提供了很多组件,来帮助开发项目。
spring的发展历史,近20年时间,发布了6个大版本,每个版本都有不同的升级
spring的组成,轻量级的应用框架,核心是IOC以及AOP,提供不同功能的模块,例如 SpringCore SpringContext SpringMVC Spring ORM等等
spring的好处,轻量,控制反转、aop,springmvc
Spring 中应用了那些设计模式
单例模式:默认创建的bean对象 原型模式:创建 bean 的时候可以设置 scope 属性 模板模式:jdbcTemplate,定义好流程,将需要实现的方法交给各个子类实现 观察者模式:监听事件 工厂模式:BeanFactory 代理模式:aop 实现
Autowired 和 Resource 的区别
Autowired 是 spring 提供的,默认根据类型注入对象的,也可以按照名称进行注入,结合 @Qualififier 注解一起使用 Resource 是 jsr 提供的,有两个重要属性,分别是name和type,使用了name,则按byName自动注入,使用了type则按照byType自动注入,如果都没使用,默认按照byName自动注入,如果都设置了,需要 同时满足,否则抛出异常。
spring 常用的注解
循环依赖的理解
循环依赖有三种情况,自身依赖自身,2个相互依赖,多个间接依赖 解决办法,在依赖之前,将自身先暴露。
Spring 如何解决循环依赖
单例:构造注入,检查是否存在循环依赖,直接抛出异常,设置注入,三层缓存,提前暴露 原型:构造注入,直接抛出异常,设置注入,不支持
Spring 三层缓存
bean.class --→ 反射构造方法---→ 普通对象 ---→ 依赖 ----→ 初始化前 ---→ 初始化 ---→ 初始化后(aop)---→ 放入单例池
-
将需要的创建的放入一个正在创建的集合中,用于判断循环依赖
-
实例化对象,放入三级缓存,放入的是一个lambda表达式
-
填充依赖 --→ 单例池找 ----→ 正在创建集合中 --→ 发现是循环依赖 ---→ earlySingletonObjects 2级缓存 ---→ 没找到继续在 SingletonFactory 三级缓存 ---→ 通过lambda表达式 -→ 判断是否存在aop(aop返回代理对象,否则直接对象)---→ 放入 2级缓存 --→ 填充
-
其他步骤(包括aop),根据2级缓存判断是否提前进行 aop 了。
-
加入到单例池中
-
从正在创建中移除
一级缓存:正式对象,单例池 SingletonObjects 二级缓存:半成品对象 earlySingletoObjects 三级缓存:对象工厂,提供对象,打破循环,只能获取一次,创建成功后,放入2级缓存,后续有循环依赖的,可以直接从2级缓存中获取了
Spring Bean 的生命周期
通过反射创建 bean 对象 设置对象属性 检测 Aware 相关接口依赖 前置处理的方法 检测是否实现了 InitializingBean 接口并调用 afterPropertiesSet init-method 自定义 后置处理方法 使用 是否实现DisposableBean
Spring支持几种作用域
1 prototype: 为每一个bean提供一个实例 2 singleton: 默认,每个容器内只有一个bean实例,单例的模式有 BeanFactory 自身来维护的 3 request: 为每个网络请求创建一个实例,请求完成后,bean 失效会被垃圾回收期回收 4 session: 与 request 范围类似,确保每个session中有一个 bean 对象,bean 失效后,会被垃圾回收器回收 5 global-session: 全局作用域,与 Portlet 应用相关,当应用部署在 Portlet 容器中,包含很多的 portlet,如果要共用全局变量,那么需要存储在 global-session 中,效果和session作用域效果相同。
spring 事务的隔离级别
DEFAULT: 采用数据库默认的隔离级别 READ_UNCOMITTED: 读未提交,会产生脏读 READ_COMMITED: 读已提交,可以避免脏读,但不能解决幻读和不可重复读 REPEATABLE_READ: 可重复读,可以避免脏读和不可重复读,但是存在幻读 SERIALIZABLE: 串行化,最高事务隔离级别,挨个执行事务,性能低
事务隔离级别是指一个事务对数据修改与另一个并行事务的隔离程度,当多个事务访问相同的数据,如果没有采用必要的隔离机制,可能会发生脏读、幻读、不可重复读。
脏读,是指一个事务读取到了另一个事务还未提交的数据,另一个事务可能会对数据进行回滚,导致第一个事务读取到错误数据 幻读,事务A 按照一定条件进行数据读取, 期间事务B 插入了相同搜索条件的新数据,事务A再次按照原先条件进行读取时,发现了事务B 新插入的数据 称为幻读 不可重复读:事务B读取了两次数据资源,在这两次读取的过程中事务A修改了数据,导致事务B在这两次读取出来的数据不一致。
事务的传播行为
PROPAGATION_REQUIRED: 支持当前事务,如果没有事务,则新建一个事务 PROPAGATION_SUPPOTRS: 支持当前事务,如果没有事务,则以非事务的方式执行 PROPAGATION_MANDATORY: 支持当前事务,如果没有事务,则抛出异常 PROPAGATION_REQUIRED_NEW: 新建事务,假设当前存在事务,把当前事务挂起 PROPAGATION_NEVER: 以非事务的方式执行,如果存在事务,则抛出异常 PROPAGATION_REQUIRED_NESTED: 如果存在事务,则嵌套执行,如果没有事务,则新建一个事务
spring 事务的实现方式
编程式事务:手动编写事务代码,灵活性更高,维护度低,代码负责度 声明式事务:通过注解等方式,将业务代码和事务管理分离,交由 spring aop 进行处理
spring 事务的本质以及失效
-
自身调用
-
异常被吃
-
异常类型抛出不对
-
@Transactional 注解属性 propgation 设置错误,以非事务的方式执行
BeanFactory ApplicationContext 理解
BeanFactoryPostProcessor 理解
BeanPostProcessor
谈谈 SpringMVC 的理解
前端控制器,主要用于 web 请求,SpringMVC 有单独的 IOC 容器,和Spring 的IOC容器,存在父子关系, Spring 无法获取到 SpringMVC 容器中的Bean,但 SpringMVC 可以访问 Spring。 主要流程是,客户端发送一个请求,经由 DispatchServlet 前端控制器,找到 HandlerMapping 处理器映射器,执行相关的处理器执行链, 然后找到处理器适配器 HandlerAdapter, 由处理器适配器找到对应的 handler,也即 Controller,执行业务后, 返回对应的 model and view 对象,再经由 DispatchServlet 调用视图解析器进行处理,然后返回给客户端。
谈谈 Spring 和 SpringMVC 的关系
谈谈 DelegatingFilterProxy 的理解
提供给第三方,将自定义的过滤器放入容器中
谈谈 SpringBoot 的自动装配原理
run 初始化IOC容器,SpringBootApplication 加载配置。自动装配主要是通过注解 SpringBootApplication 中的 EnableAutoConfiguration 以及 Import 导入META-INF 中的 spring.factory 定义好的配置类,以及 spring-autoconfigure-metadata.properties 需要过滤类, spi 去重、排除、过滤,然后配置
谈谈你对 Import 注解的理解
-
spring3.0提供,目的是替换 xml 配置中的 import 标签。
-
import 除了可以导入第三方的java配置类,还扩展了其他功能。
-
可以直接将某个类型对象注入到容器中。
-
如果导入的类实现了 ImportSelector,会调用声明的方法,然后将方法返回的全路径类注入到容器中。
-
如果导入的类实现了 ImportBeanDefinitionRegistrar 这个接口,会调用声明的方法,显示的提供注册器来完成注入。
谈谈你对 DeferredImportSelector 的理解
在SpringBoot自动装配中核心是会加载META-INF/spring.factories文件中的配置信息。我们可以加载多个,那么会需要多次操作,我们可以考虑统一加载完,然后注入到容器中。
谈谈 bottstrap.yml 的理解
只能适用于 SpringCloud 环境,作用是在容器启动之前,读取配置中心的配置信息。
如果要对属性文件中的账号密码加密如何实现?
在属性文件加载后,容器刷新之前,通过配置文件后置处理器,来进行密码解密, 然后替换成明文。
-
通过事件监听器,容器在加载完配置文件后,会发出一个事件,可以通过这个来处理
-
声明后置处理,定义一个类,实现 EnvironmentPostProcessor,实现里面解密、替换。
谈谈 Indexed 注解的作用
spring5.0提供的,随着项目越来越复杂,通过 @ComponentScan 扫描加载的 class 会越来越多,启动会造成性能损耗, @Component 用@Indexed标识,编译的时候,回收这些类,然后记录在 META-INF/spring.components 文件中, 系统启动时,只需要读取一个文件就可以了,提升效率,需要单独引入一个依赖。
@Component @Controller @Repository @Service 的区别
都是 bean 对象,主要区分业务作用。
aop 有哪些通知类型
前置通知 @Before, 在执行 joinpoint 之前 后置通知 @AfterReturning 正常执行之后执行 @AfterReturning 异常通知 @AfterThrowing,执行抛出异常时执行 最终通知 @After 在执行完连接点方法后,无论是正常退出,还是异常退出,都会执行 环绕通知 @Around 在执行的前后执行。
介绍下 Spring 中的依赖注入
通过 Spring 的依赖注入,不需要我们手动创建对象然后注入,而是 Spring 通过反射注入,我们只需要描述对象是如何创建的,由容器负责组装起来。
Spring 中的单例 Bean 是线程安全的吗?
spring本身没有提供bean的线程安全策略,对于原型,每次都是新对象,不存在线程安全问题, 对于单例bean,如果不存在共享属性,那么也是线程安全的,也可以采用 ThreadLocal 来处理线程安全的数据。
@ComponentScan 注解是干什么的?
指定扫描路径中的component类,springboot 默认是从 main 所在的类的目录,如果要扫描其他路径,就需要指定
@EnableAutoConfiguration 注解是干什么的?
从命名上看,可以知晓是启动自动配置功能。 里面主要有 @Import 注解,导入了一个 AutoConfigurationImportSelector 类,这个类会读取 META-INF/spring.properties 配置,导入到内存。
@Import 注解的三种用法
-
直接导入成bean对象
-
实现 ImportSelector,可以将返回的类完全限定名导入容器 -
RequestMapping 和 GetMapping 的区别
-
RequestMapping 是具有类属性的,可以指定 GET POST PUT 等请求方法,模糊的匹配
-
GetMapping 作用于方法,已经指明了,接受的请求必须是一个 Get 方法。
SpringBoot 的核心注解是那个?主要由那几个注解组成?
核心注解是 @SpringBootAppliction, 核心注解有 @ComponentScan、 @SpringBootConfiguration、@EnableAutoConfiguration
SpringBoot 可以兼容老项目吗?
可以,通过 @ImportResource 注解导入老的 Spring 配置文件。
SpringBoot 如何定义多套不同环境的配置
application-dev.yml application-test.yml application-prod.yml
在applicaiton.yml中配置当前环境 spring.profiles.active-test,多个用逗号隔开。
SpringBoot 需要独立的容器吗?
不需要,SpringBoot 有内置的 tomcat/jetty 容器
SpringBoot 有哪几种读取配置的方式?
@PropertySource 读取配置文件,除了 properties文件,xml文件也可以,还可以配合 PropertySouceFactory,结合YAML解析器读取yml文件
@Value 读取单个属性,适用于参数比较少的情况, 通过${}方式
通过@Autowired 注入 Environment 类对象,通过getProperty获取属性
@ConfigurationProperties 使用于比较多的情况,可以指定前缀
SpringBoot 支持那些日志框架
logging/log4j,lockback,默认使用lockback,如果需要使用其他的,需要移除lockback
SpringBoot SpringMVC Spring 有什么区别?
SpringBoot 的监视器是什么?
访问到应用程序的当前状态,一些外部应用可以使用这些服务来触发报警信息,还提供了 http rest 端点来检查状态
SpringBoot 打包成 jar 和普通的 jar 有什么区别?
SpringBoot 最终包,是可以执行的文件,通过 java -jar 命令,不能作为其他项目依赖即使依赖了也无法使用其中的类。 他们的结构不同,普通jar包解压就是包名,里面就是我们代码,而springboot在BOOT-INF里面,无法被直接引用。如果需要,在打包时增加配置,打包2个,一个可执行,一个可引用。
SpringBoot 的 run 方法做了什么?
加载配置、创建应用上下文,ioc初始化操作
SpringBoot 的优点
-
可以独立运行,内嵌容器
-
简化配置 通过 spring-boot-starter 的方式,简化了 mave n配置
-
自动装配 组件的装配交由 starter 进行处理,约定大于配置
-
提供一些端点,提供健康检查等
SpringBoot 如何解决跨域问题
通过实现 WebMvcConfigurer 接口,重写 addCorsMappings 方法解决跨域问题
SpringBoot 如何配置 log4j
-
移除 lockback
-
增加 log4j 依赖
-
增加 log4j-spring.properties 配置文件
SpringBoot 如何实现定时任务
-
@Schedule 单体项目
-
第三方框架 @Quartz,使用分布式情况
SpringBoot 自动装配的核心配置文件有哪些?
SpringBoot 自动装配的流程是怎么样的?
介绍几个常用的 starter
你如何理解 SpringBoot 配置加载顺序
-
命令行参数
-
JNDI 参数
-
Java 系统参数
-
操作系统环境变量
-
jar包外部的带 profile的
-
jar包内部带 profile的
-
jar 外部不带profile的
-
jar 内部不带 profile的
-
@PropertySource指定的配置文件。
如何实现 SpringBoot 应用程序的安全性
引入 Security 安全框架
如何在 SpringBoot 启动的时候运行一些特点的代码
实现接口 ApplicationRunner 或者 CommandLineRunner,然后加入容器中即可。
如何重新加载 SpringBoot 的更改,而无需重新启动服务器
什么是 SpringBoot starter?
什么是 SpringBoot?
基于 Spring,基于约定大于配置,提供了自动装配来进行配置,旨在简化 Spring 应用的初始搭建和开发过程,从而使开发人员不需要定义样板化的配置。
我们如何连接一个像 MySQL 的外部数据库
-
引入数据库的连接包
-
配置对应的连接属性
-
启动即可
运行 SpringBoot 项目的方式
-
打包成可执行jar文件,通过 java -jar 命令运行
-
打包成 war 文件,通过外部容器启动
-
通过 maven 或 gradle 插件进行运行