面试2_Spring
参考资料
- CSDN_Spring面试题
- 简书_Spring常见面试题
- 知乎_Spring面试题IOC系列
- CSDN_面试题 Spring IOC相关
- 有道云_面试3_Spring
- SpringBoot自动配置注解原理解析
- Cglib和jdk动态代理的区别
一、spring概述
1. Spring组成模块
核心容器
(Core Container)AOP
(Aspect Oriented Programming)和设备支持(Instrmentation)数据访问与集成
(Data Access/Integeration)Web
消息
(Messaging)Test
2. Spring使用的设计模式
-
工厂模式
:BeanFactory,用来创建对象的实例; -
单例模式
:Bean默认为单例模式。 -
代理模式
:AOP功能 -
模板方法
:解决代码重复的问题 观察者模式
3. Spring事件类型
-
上下文更新事件
:在调用ConfigurableApplicationContext 接口中的refresh()方法时被触发。 -
上下文开始事件
:当容器调用ConfigurableApplicationContext的Start()方法开始/重新开始容器时触发该事件。 -
上下文停止事件
:当容器调用ConfigurableApplicationContext的Stop()方法停止容器时触发该事件。 -
上下文关闭事件
:当ApplicationContext被关闭时触发该事件。容器被关闭时,其管理的所有单例Bean都被销毁。 -
请求处理事件
:在Web应用中,当一个http请求(request)结束触发该事件。
4. 核心容器模块详情
BeanFactory 是 任何以spring为基础的应用的核心。是工厂模式的一个实现,提供了控制反转功能。
二、IOC
1. IOC、DI
- IOC是
控制反转
,依赖对象的创建及维护是由外部容器负责的
- DI也就是
依赖注入
,实现IOC的方式之一
。运行期间由外部容器
动态地将依赖对象注入到组件
中
2. IOC作用
- 管理
对象的创建
,依赖关系的维护
解耦
,由容器去维护具体的对象托管类产生过程
- 容易测试,
单元测试不再需要单例和JNDI查找机制
。 - 支持加载服务时的
饿汉式初始化
和懒加载
3. IOC支持的功能
依赖注入
依赖查找
自动装配
- 支持集合
- 指定初始化方法和销毁方法
4. IOC实现原理
**工厂模式
+ 反射机制
5. IOC初始化
- Resource 定位
- Bean 注册
- BeanDefinitionReader
读取、解析bean的配置信息
- 將bean的配置信息
转换为 BeanDefinition 对象
,并保存在内存中 - registerBeanDefinition 将 BeanDefinition
注入到 Bean定义注册表
。
- BeanDefinitionReader
- Bean 实例化
- 遍历Bean定义注册表,调用
getBean方法
拿出Class对象通过反射机制
进行实例化
,保存在Bean缓存池
中。
- 遍历Bean定义注册表,调用
6. DI实现方式、区别
-
接口
注入 -
Setter
方法注入 -
构造器
注入
区别 | 构造函数注入 | setter 注入 |
---|---|---|
部分注入 |
没有 | 有 |
覆盖 setter 属性 |
不会 | 会 |
任意修改会创建新实例
|
会 不会 | |
适用范围 | 适用于设置很多属性
|
适用于设置少量属性
|
7. BeanFactory、 FactoryBean区别
- BeanFactory是
IOC的底层容器
,用于管理Bean
,通过getBean
进行依赖查找
,若 Bean 未初始化,则从底层查找或构建。 - FactoryBean是特殊的
Bean
,需注册到 IoC 容器,通过容器的getBean
获取FactoryBean#getObject()
方法的内容,作用主要是自定义实际Bean的产生过程
。
8. BeanFactory、ApplicationContext区别
-
ApplicationContext实现BeanFactory接口,提供更多功能:
- 提供
国际化
的消息访问, MessageSource 统一的资源文件访问
方式, ResourceLoader事件传递
:通过实现ApplicationContextAware接口。消息发送、响应机制(ApplicationEventPublisher)Bean的自动装配
- 载入多个(有继承关系)上下文 ,使得
每一个上下文都专注于一个特定的层次
。各种不同应用层的Context实现
- 提供
-
区别
区别 | BeanFactory | ApplicationContext |
---|---|---|
·加载方式· |
懒加载 ,使用时才被实例化 |
启动时实例化 可以为Bean配置lazy-init=true来让Bean延迟实例化 能尽早的发现系统中的 配置问题
|
·创建方式· | 编程式 | 编程式 + 声明式 |
·注册方式· BeanPostProcessor、BeanFactoryPostProcessor的使用 |
手动注册 | 自动注册 |
9. Bean 自动装配
自动装配类型
-
no
:默认的方式是不进行自动装配的,通过手工设置ref属性来进行装配bean。 -
byName
:通过bean的名称进行自动装配,如果一个bean的 property 与另一bean 的name 相同,就进行自动装配。 -
byType
:通过参数的数据类型进行自动装配。 -
constructor
:利用构造函数进行装配,并且构造函数的参数通过byType进行装配。 -
autodetect
:自动探测,如果有构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。
自动装配注解原理
- @SpringBootApplication:启动类
- @EnableAutoConfiguration:开启自动配置类
- @AutoConfigurationPackage:自动配置包
- 返回当前主程序类的
同级以及子级
的包组件
- 返回当前主程序类的
- @Import:导入自动配置的组件
- 继承了 ImportSelector,来加载 **
META-INF/spring.factories
**外部文件
- 继承了 ImportSelector,来加载 **
- @AutoConfigurationPackage:自动配置包
- @EnableAutoConfiguration:开启自动配置类
10. Bean 生命周期
-
bean实例化
; -
属性填充
:将值和bean的引用注入到bean对应的属性中; -
检查Aware相关接口并设置相关依赖
; -
BeanPostProcessor前置处理
; - 调用
InitializingBean接口的afterPropertiesSet()
方法; -
BeanPostProcessor后置处理
; -
bean准备就绪
; -
销毁bean
- 调用
DisposableBean的destroy()
方法。 调用定制的销毁方法
- 调用
11. Bean 作用域
-
bean标签里面有
scope属性
用于设置单实例还是多实例
- singleton
加载 spring 配置文件时
就会创建单实例对象 - prototype 在
调用getBean 方法时
创建多实例对象
作用域 | 说明 |
---|---|
singleton |
在 Spring 容器中仅存在一个 bean 的实例,bean 以单例形式存在。 这是99默认的作用域99 |
prototype |
每次从容器中获取 bean 时,都将生成一个新的实例, 即相当于每次都执行 new xxxBean() |
request |
在 HTTP 请求 (request) 的完整生命周期中,将创建并使用单个实例。 该作用域仅适用于 WebApplicatonContext 环境 |
session |
在 HTTP 会话 (session) 的完整生命周期中,将创建并使用单个实例。 该作用域仅适用于 WebApplicationContext 环境 |
global-Session |
在全局的 HTTP 会话 (session) 的完整生命周期中,将创建并使用单个实例。 该作用域仅适用于 WebApplicationContext 环境,且通常只能用在 Portlet 环境中。 |
12. 单例bean线程安全?
- 单例bean不是线程安全的
- 大部分时候 spring bean 无状态的,某种程度上来说 bean 也是安全的
- bean 有状态的话,要开发者去保证线程安全,
改变 bean 的作用域
,把“singleton”变更为“prototype”- 有状态就是有数据存储功能。
- 无状态就是不会保存数据。
12. 如何保证 Controller 并发的安全
- Controller对象是单例的,Spring 多线程请求过来调用的Controller对象都是同一个
使用ThreadLocal来保存类变量
- 添加注解
@Scope(“prototype”)
让Controller以多实例形式创建
13. 如何解决循环依赖
- Spring
三个缓存区
-
setter方法注入
形成的单例循环依赖能够解决 - 通过ObjectFactory提前曝光,
放到三级缓存
14. 为什么需要三个缓存,而不是直接两个缓存?
保证单例
- 使用AOP情况下,只使用一级、三级缓存无法解决循环依赖的问题
- 每次从三级缓存中拿到singleFactory对象,在执行getObject()时会产生新的代理对象
-
产生的代理对象放到二级缓存中
。然后把这个三级缓存删除掉,这样以后就使用二级缓存的同一个对象。
15. MVC 的工作原理
三、AOP
1. AOP的实现原理
-
静态代理
的代表为AspectJ
-
动态代理
则以 Spring AOP 为代表
2. JDK动态代理、cglib动态代理
- JDK动态代理,
拦截器+反射
生成一个代理接口的匿名类
,在调用具体方法前调用InvokeHandler来处理,只能对实现了接口的类生成代理。 - cglib动态代理,通过
修改其字节码生成子类来处理
,覆盖其中的方法。
四、Spring事务
Spring 事务管理机制
Spring 事务传播行为及其作用
五、Spring注解
1. @Component, @Controller, @Repository, @Service
将 java 类标记为 bean,@Component为父接口
2. @Required
bean的属性必须在配置时设置
,通过一个bean定义的显式的属性值或通过自动装配
3. @Autowired、@Resource的区别
-
@Autowired可用于:
构造函数、成员变量、Setter方法
-
@Autowired默认按
类型
装配注入,默认情况下它要求依赖对象必须存在(可以设置它required属性为false)。 -
@Resource默认按
名称
装配注入,找不到才按类型
装配注入。
4. @Qualifier
创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,使用@Qualifier 注解和 @Autowired 通过指定应装配确切的 bean 来消除歧义
5. @RequestMapping
- 将特定 HTTP 请求方法映射到将处理相应请求的控制器中的特定类/方法。