1、谈谈对spring的理解
- spring的组成
- spring是一个轻量级的ioc和aop容器,用于简化企业应用开发,它使得开发者只需要关心业务需求。常见的配置方式有三种:基于XML配置、基于注解的配置、基于java的配置
- spring的好处
- 轻量
- 控制反转
- 面向切面编程
- 容器
- mvc框架
- 事务管理
- 异常处理
2、spring中应用到的设计模式
- 单例:spring容器里面管理的就是单例的对象
- scope设置成单例
- 原型:也叫克隆模式,当需要大量使用该对象时,使用原型模式,相当于在new的对象的基础上进行拷贝,clone方法可以自己重写,默认clone方法是浅拷贝
- scope可以设置成原型
- 模板方法:父类定义好流程,然后将流程中需要子类实现的方法抽象给子类实现,JdbcTemplate就是这样实现的
- SQL处理部分
- 观察者模式:事件监听,监听器,发布订阅等
- 工厂模式:beanFactory
- 简单工厂:根据唯一值确定要实例化的对象
- 工厂方法:对象通过工厂类的方法进行创建
- 适配器模式:将一个类的接口转换成另一个接口,使得原本不兼容的接口可以进行兼容
- Advice和Interceptor
- 装饰者模式:基本上所有的Wrapper类。动态的为一个对象增加新的功能。
- 代理模式:AOP,默认cglib
- 策略模式:用户从某些算法中选出一个解决某一问题,同时可以方便更换算法或者增加新的算法
- spring中beanDefinition的生成,可以根据xml,配置类等方式进行生成
- 责任链模式:AOP中的拦截器链
3、谈谈Autowired和Resource的区别
- 共同点
- 都是可以写在属性和setter方法上
- 不同点
- autowired
- spring提供,需要导入
- 只按照byType进行注入
- 如果需要按照名称装配,需要配合Qualifier使用
- Resource
- javaee提供,默认按照ByName自动注入,可以手动设置name和type属性
- 装配顺序
- 如果同时配置name和type,组合找
- 如果name,按照name
- 如果type,按照type
- 如果没有,按照name,没有均抛异常
- autowired
4、Spring中是如何解决循环依赖问题的
- 单例
- 构造注入:无解。如果出现循环依赖,会抛出栈溢出异常
- 设值注入:三级缓存——提前暴露
- 原型
- 构造注入:无解。如果出现循环依赖,会抛出栈溢出异常
- 设值注入:不支持循环依赖
5、Spring中如何解决设值注入的循环依赖——三级缓存
场景:A依赖B,B依赖A,先创建A
查找:先找一级、再找二级、最后找三级,找不到就创建
一级缓存(singletonObjects):存放已经实例化好的对象
二级缓存(earlySingletonObjects):提前暴露的对象,存放已经创建完成,但是没有注入好的对象!
-
三级缓存(singletonFactories):提前暴露的对象,存放已经创建完成,但是还没有注入好的对象的工厂对象!通过这个工厂可以返回这个对象!
- 主要解决aop代理对象
-
A在创建过程中需要B,于是A先将自己放到三级缓存里面,存的是一个lambda表达式,去实例化B,B实例化的时候发现需要A,于是B先查一级缓存,没有再查二级缓存,还是没有,再查三级缓存,找到了A,此时可以判断出现循环依赖,然后调用三级缓存A对象的lambda表达式,如果A有AOP,则返回代理对象,没有AOP,则返回原对象;然后把三级缓存里面的这个A对象或代理对象放到二级缓存里面,并删除三级缓存里面的A
B顺利初始化完毕,将自己放到一级缓存里面(此时B里面的A依然是创建中状态);然后回来接着创建A,此时B已经创建结束,直接从一级缓存里面拿到B,然后完成创建,并将A放入到一级缓存中
6、Spring中Bean的生命周期
- 推断构造方法:有无参用无参,有唯一用唯一,多个构造不包括无参则报错
- 实例化对象:先bytype再byName
- 依赖注入
- 初始化前(@PostConstruct):调用某些方法进行一些数据的初始化
- 初始化(InitializingBean):初始化方法
- 初始化后(AOP):生成代理对象,代理对象里面属性target是原对象实例
- 放入ApplicationContext容器
- Bean对象完成
7、Spring中的事务隔离级别
- 多个事务访问相同数据可能出现的问题
- 脏读:A事务读取B事务修改未提交的数据
- 幻读:A事务修改全表数据时,B事务添加了数据,导致A未全部修改
- 不可重复读:同一个事务在未作写操作前提下,两次相同select查询结果不一致
- spring事务隔离级别:一般默认
- DEFAULT:使用数据库本身的隔离级别,oracle(读已提交),mysql(可重复读)
- READ_UNCOMMITED:读未提交
- READ_COMMITED:读已提交
- REPEATABLE_READ:可重复读
- SERIALIZABLE:全部串行化
8、事务的传播行为
- 保证事务:ACID
- 行为
- 默认,没有事务就创建事务
- 没有事务以非事务方式运行
- 没有事务抛出异常
- 新建事务,当前事务挂起
- 存在事务,挂起,以非事务方式运行
- 存在事务抛异常
- 存在则嵌套,没有则按照默认
9、Spring事务的实现方式
- 编程式事务管理:手动编写代码
- 获取事务管理器对象
- 设置自动提交关闭
- 执行过程
- 手动提交
- 声明式事务管理:配置。注解或XML
10、Spring事务的本质
-
什么是事务
- 事务是数据库运行中的逻辑工作单位
- 单个逻辑工作单位执行一系列操作,要么完全地执行,要么完全地不执行
-
事务的四大特性(ACID)
- 原子性:一个事务中的所有SQL,要么都成功,要么都失败
- 原理:依赖undo.log日志,记录事务执行的sql,失败时回滚
- 一致性:事务前后总量不变,数据库的完整性约束没有被破坏
- 原理:从数据库层面,数据库是通过原子性,隔离性和持久性保证一致性的
- 从应用层面,通过代码判断数据库是否有效,然后决定回滚还是提交数据
- 隔离性:一个事务的执行不会被其它事务干扰
- 写-写 操作:通过锁的方式实现
- 写-读 操作:MVCC
- 持久性:事务一旦提交,结果是永久性修改的
- 数据库保证
- 原子性:一个事务中的所有SQL,要么都成功,要么都失败
-
@Transactional:这个注解只是一些配置元数据,在运行时被消费,并用这些元数据来配置bean的事务行为。
- 表明该方法要参与事务
- 配置相关属性来定制事务的参与方式
- 可以注解在类上,也可以标注在方法上。当在类上时,默认应用到所有方法;方法上标注优先级高于类上;所有被标注的方法必须是public修饰的,否则无法被代理。
11、BeanFactoryPostProcessor的理解
BeanFactoryPostProcessor:是在BeanFactory创建后的后置处理
BeanFactory:对外提供Bean对象
该后置处理器就是在BeanFactory创建好之后做了一些扩展的处理
比如:对@Configuration注解的识别、解析等
12、BeanPostProcessor的理解
- Bean对象的后置处理器,也是AOP处理的地方
13、谈谈对SpringMVC框架的理解
- 用户通过浏览器发起 HttpRequest 请求到前端控制器 (DispatcherServlet)。
- DispatcherServlet 将用户请求发送给处理器映射器 (HandlerMapping)。
- 处理器映射器 (HandlerMapping)会根据请求,找到负责处理该请求的处理器,并将其封装为处理器执行链 返回 (HandlerExecutionChain) 给 DispatcherServlet
- DispatcherServlet 会根据 处理器执行链 中的处理器,找到能够执行该处理器的处理器适配器(HandlerAdaptor) --注,处理器适配器有多个
- 处理器适配器 (HandlerAdaptoer) 会调用对应的具体的 Controller
- Controller 将处理结果及要跳转的视图封装到一个对象 ModelAndView 中并将其返回给处理器适配器 (HandlerAdaptor)
- HandlerAdaptor 直接将 ModelAndView 交给 DispatcherServlet ,至此,业务处理完毕
- 业务处理完毕后,我们需要将处理结果展示给用户。于是DisptcherServlet 调用 ViewResolver,将 ModelAndView 中的视图名称封装为视图对象
- ViewResolver 将封装好的视图 (View) 对象返回给 DIspatcherServlet
- DispatcherServlet 调用视图对象,让其自己 (View) 进行渲染(将模型数据填充至视图中),形成响应对象 (HttpResponse)
- 前端控制器 (DispatcherServlet) 响应 (HttpResponse) 给浏览器,展示在页面上
14、Spring和SpringMVC的关系
- Spring和SpringMVC都有一个ioc容器
- Controller层中定义的实例都是SpringMVC容器维护的
- Service和Dao中的实例都是由Spring的Ioc容器维护的
- 这两个容器是一个父子容器的关系
- Spring容器是SpringMVC的父容器,所以SpringMVC可以调用Spring容器的对象,但是Spring容器调用不到SpringMVC容器中的对象
15、SpringBoot自动装配原理的理解
- SpringBoot项目的启动,完成的是一个Spring容器的初始化过程
- @SpringBootApplication:标识当前类为启动类
- @SpringBootConfiguration:表明这是一个配置类
- @EnableAutoConfiguration:
- @AutoConfigurationPackage:向容器内注入一个组件 组件的作用是保存一些包路径
- @Import:导入类到容器
- 会扫描spring.factories文件里的对象
- @ComponentScan:扫描路径
16、对Import注解的理解
- 可以导入第三方的java配置类
- 可以把某个类型的对象注入到容器中
- 导入的类型如果实现了ImportSelector接口,那么会调用接口中声明的方法,然后把方法返回的类型全类路径的类对象注入到容器中
- 如果导入的类型实现了ImportBeanDefinitionRegister这个接口,那么就会调用声明的方法在该方法中显示的提供注册器来完成注册
17、对DeferredImportSelector注解的理解
- 在springboot自动装配中核心是会加载spring.factories文件中的配置信息,如果有多个文件,需要多次操作,所以可以把所有信息都加载后统一注入到容器中去
- DeferredImportSelector:延迟注入Bean实例的作用
18、谈谈bootstrap.properties文件的理解
- 单体的springboot项目中其实用不到bootstrap.yaml,该文件的使用需要SpringCloud的支持,因为在微服务环境下我们都是有配置中心的,来统一的管理相关配置属性。
- bootstrap.properties文件是用来在微服务环境下加载配置中心内容的一个容器
19、@indexed注解的作用
- 随着componentScan扫描的Class文件越来越多,引入该注解提高系统启动速度
- 作用是在系统编译的时候会收集所有被@Indexed注解标识的java类,然后记录在META-INF/spring.components文件中,那么系统启动的时候就只需要读取该文件中的内容旧不用再遍历所有的目录了,提升了效率
20、@Componet,@Controller,@Repository,@Service有何区别?
都能将标记的类导入到IOC容器中
@Component:将java类标记为bean,其它三个注解都被该注解注解过
@Controller:将一个类标记为Spring Web MVC控制器
@Repository:DAO层使用,并使未经检查的异常有资格转换成DataAccessException
@Service:业务层注解
21、AOP有哪些通知类型
- before:前置通知
- after returning:后置通知
- after throwing:异常通知
- after:最终通知,一定会通知
- around:环绕通知
23、什么是Spring的依赖注入
- 是IOC的一方面
- 通常的解释是你不需要创建对象,只需要描述对象如何被创建,也就是在配置文件中如何定义对象;也不用在代码里直接组装你的组件和服务,但是要在配置文件里描述哪些组件需要哪些服务,之后一个IOC容器负责把他们组装起来
24、Spring中的单例bean是线程安全的吗?
- 不是线程安全的,都是无状态的单例bean
- 如果是线程安全的,那么每一个单例bean的访问都是串行的,会很影响效率