Spring 面试大纲(持续更新)
2021-12-29 17:35:43 5 举报
AI智能生成
Spring 面试大纲,本人曾靠此面经拿到 35k offer
作者其他创作
大纲/内容
整个Spring 都是围绕 Bean 这个核心概念来工作的
是否精通 Spring 就看你有没有掌握好 Spring 有哪些扩展点,以及它们的内在机理
K8s
计算机系统软件体系结构采用一种层的结构:“计算机科学领域的任何问题都可以通过增加一个间接的中间层来解决” “Any problem in computer science can be solved by anther layer of indirection.”
通过分析 Spring 给我一个很大的启示就是其这套设计理念其实对我们有很强的借鉴意义,它通过抽象复杂多变的对象,进一步做规范,然后根据它定义的这套规范设计出一个容器,容器中构建它们的复杂关系,其实现在有很多情况都可以用这种类似的处理方法。
我所理解的 Spring
DefaultListableBeanFactory
AbstractBeanFactory
BeanFactory
AbstractApplicationContext
GenricApplicationContext
AbstractApplication
ApplicationContext
Spring IoC 容器两大接口
bean name默认为 类名首字母小写
指定bean name @Component(\"userService\")
创建可被发现的bean - @Component
@ComponentScan
BeanPostProcessor 来处理 此注解
在 bean后置处理器中 AutowiredAnnotationBeanPostProcessor
@Autowried 、@Inject是如何被解析的?
CommonAnnotationBeanPostProcessor
@Resource 是如何被解析的?
bean自动装配 - @Autowried
可以扩展 此注解,支持分组注入,比如 @LoaderBlance
@Qualifier
@Resource 也是 byType
bean自动装配 - @Resource(java EE 规范)
读取配置文件属性值
@Value(\"${server.port}\")
不能应用在 static 属性上
@Value +.property 不能注入集合类型
@Value + .yml 可以注入
注意点
@Value
注入其他配置文件(.property 或者 .yml)然后可以使用 @Value() 进行注入
@PropertySource
需要注意 @Configuration 与 @Import 不能一起使用
工厂读取配置
多配置bean整合
与@Component整合
Spring在配置Bean中加入了@Configuration注解后,底层就会通过Cglib 的代理方式,来进行相关Bean 的创建。
配置Bean 底层实现原理
@Configuration: 配置Bean
结合 @Configuration 一起使用
FactoryBean 接口也可以创建复杂对象
可以创建复杂对象
@Bean(\"id\")
自定义id值
@Bean@Scop(\"singleton\")
指定作用域
@Bean
使用 Import 导入多个 类作为 Spring IoC 容器的 Bean。
@Import 也可以导入其他配置类
@Import
创建 Bean 的优先级:@Component及其衍生注解 < @Bean <bean 标签
Spring 创建Bean 的几种 方式:
自定义 Condition(根据不同操作系统注入不同的 Bean)
@Condition
FactoryBean 是 Spring 提供的用来创建复杂 Spring Bean 的接口。那什么是复杂对象(Bean)呢?复杂对象(Bean)就是那些不能简单通过构造方法实例化的对象
FactoryBean
实现不同的 Aware 接口可以获取不同的 Spring 内置 bean或者功能
每一种 xxxAware 都对应这一个 xxxProcessor 进行处理而一个 xxxProcessor 可以处理多个 xxxAware 接口
Aware 系列接口
对 Spring 工厂创建的 Bean 进行再加工(Bean 初始化方法调用前后)
BeanPostProcessor
时机: BeanFactory 初始化后,所有 bean 定义都已保存在 BeanFactory 中,但还未实例化
BeanFactoryPostProcessor
时机: 所有的 BeanDefinition 被加载之后,所有的 Bean 还未实例化> BeanDefinitionRegistryPostProcessor 优先于 BeanFactoryPostProcessor 执行
BeanDefinitionRegistryPostProcessor
需要注意的是:所有的 BeanPostProcessor 也会被当做Bean注入到 Spring 容器中
AnnotationConfigUtils
PostProcessor
Spring 中的事件机制使用了观察者模式,1. IoC 容器启动时,扫描所有的 Listener 组件,每次发布一个 AppilcationEvent 就 循环这些 Listener 回调方法。
ApplicationListener
多环境配置
Spring Profile
YAML 与Spring 整合
Spring YAML
Spring 注解驱动开发
实例化 Instantiation属性赋值 Populate初始化 Initialization销毁 Destruction实例化和初始化前后都快可以进行微调
bean的生命周期
Spring 容器启动过程
Spring Bean
比如有两个类,A和B,A中有个属性为 b,B中有个属性为 a,这样在Spring 的IoC 容器为我们注入依赖的时候,就会产生所谓的循环依赖。
首先抛弃掉Spring,如果使我们自己来创建这两个对象,怎么解决呢?很容易: 把 A ,B都先实例化出来,再set不就好了。A a = new A();B b = new B();a.setB(b);b.setA(a);
如何解决?
Spring内部维护了三个Map,也就是我们通常说的三级缓存。在Spring的DefaultSingletonBeanRegistry类中,你会赫然发现类上方挂着这三个Map: singletonObjects 它是我们最熟悉的朋友,俗称“单例池”“容器”,缓存创建完成单例Bean的地方。 singletonFactories 映射创建Bean的原始工厂 earlySingletonObjects 映射Bean的早期引用,也就是说在这个Map里的Bean不是完整的,甚至还不能称之为“Bean”,只是一个Instance.
一句话解释:Spring 在创建Bean 的时候,如果发现自己还有其它依赖,就把自己放在 一个早期Bean 池里面,即earlySingletonObjects 中
Spring 解决循环依赖的思路也是类似的!(三级缓存)(三个Map)
首先搞清楚什么是Spring 的 Bean 创建循环依赖?
Spring容器会将每一个正在创建的Bean 标识符放在一个“当前创建Bean池”中。因此如果在创建Bean过程中发现自己已经在“当前创建Bean池”里时将抛出BeanCurrentlyInCreationException异常表示循环依赖;而对于创建完毕的Bean将从“当前创建Bean池”中清除掉。
构造器
Bean 实例化图
setter循环依赖(单例)
setter 循环依赖(原型)
Spring 循环依赖分为三种:
Spring 不支持构造器循环依赖!
Spring 如何解决循环依赖?
GenericBeanDefiniion:通用 BeanDefinition
RootBeanDefinition:无Parent的BeanDefinitio或者合并后的BeanDefinition
被@Component 标注的类,会在Spring 开启类路径扫描时,自动装配为 Spring 的Bean。
ClassPathBeanDefinitionScanner:Bean Definition 扫描器,把被@Component及其衍生注解标注的类扫描为 Bean Definition 并注册到 BeanFactory 中。
扫描动作是由 ConfigurationClassPostProcessor#postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) 完成触发的。可以自定义这个BeanFactoryPostProcessor 在这里面手动注册 BeanDefinition
@Component 及其衍生注解
基于java注解装载 Spring bean 配置元信息
AnnotatedBeanDefinition:注解标注的BeanDefinition
主要分为以下几类
Bean 配置元信息BeanDefinition
Spring Bean 相关
引入动机?
Spring Resource 相关
Spring 放弃了自己的校验实现,整合了 hibernate-calidator 校验框架
一图看懂 @Valid 和 @Validated 注解
Spring Validation 最佳时间及其实现原理,参数校验没那么简单?
Spring 校验:Validated
ApplicationEvent 继承了 java.util.EventObject:ApplicationContextEvent
接口方式: ApplicationListener
注解方式:@EventListener
监听器的两种实现方式
事件监听器: ApplicationListener:监听 ApplicationEvent 类型事件
一: ApplicationEventPublisherAware 接口回调注入
二:依赖注入:ApplicationPublisher
三:使用 ApplicationCopntext 发布事件
获取ApplicationEventPublisher 的方式
依赖查找
依赖注入
获取 ApplicationEventMulticaster 的方式:
事件发布器:ApplicationEventPublisher(事件发布)ApplicationEcentMulticaster(事件广播)
Demo
分为三步:1. 自定义事件:扩展ApplicationEvent2. 自定义事件监听器(或者使用@EventListener):ApplicationEventListener,注册到ApplicationContext 容器中。3.发布自定义事件:使用ApplicationContext,或者 实现 ApplicationEventPublisherAware 接口 获取 ApplicationEventPublisher
自定义 Spring事件
广播事件,可以添加监听器,可以向所有添加的监听器进行广播;类似 发布订阅模式
ApplicationEventMulticaster
广播事件
方法一
方法二:使用注解:@Async
异步事件
SpringBoot 中的事件
Spring Cloud 中的事件
答
Spring 同步事件和异步事件的使用场景?
基于BeanPostProcesor
。。。
@EventListener 的工作原理?
Spring 事件:ApplicationEvent -> ApplicationListener
BeanFactory 提供了一个配置框架的基本功能,可以获取任意 object 的工厂,ApplicationContext 提供了一些更加高级的功能。比如与 AOP 集成,国际化,事件处理,注解,Environment以及与 Web 整合。
AppilcationContext 是 BeanFactory 的子类,但是是内部持有了一个 DefaultListenerableBeanFactory 对象来代理实现 BeanFactory 的所有方法。可以认为Application 是Beanfactory 的超集。
这是 ApplicationContext 的实现类,是很多其他具体 ApllicationContext 的实现类。
GenericApplicationContext
BeanFactory 和 AppilcationContext 谁才是 Spring 的 IoC 容器?
答:BeanFactory 是IoC的底层容器;FactoryBean 是创建Bean的一种方式,帮助实现复杂的初始化逻辑。
BeanFactory和FactoryBean?
prepareRefresh()
创建BeanFactory实例的工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
往 BeanFactory 实例中放置一些内建的Bean或者非Bean对象
配置工厂的标准上下文特征,例如上下文的ClassLoader和后置处理器。
prepareBeanFactory(beanFactory); 准备工厂
扩展点:子类实现
postProcessBeanFactory(beanFactory);
实例化并调用所有已注册的BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
扩展点:实例化并注册所有BeanPostProcessor Bean在Bean实例化后做一些调整
registerBeanPostProcessors(beanFactory);
国际化
initMessageSource();
initApplicationEventMulticaster();
容器和Bean都已经调整完毕
onRefresh();
扩展点:注册监听器Listener
registerListeners();
完成BeanFactory 的实例化,后的一些操作
finishBeanFactoryInitialization(beanFactory);
发布相应事件 Event,告知监听器Listener
finishRefresh();
refresh()方法第一部分: 准备 Beanfactory第二部分: 准备 Bean第三部分: 国际化,监听器等
BeanDefinition 是Spring 中定义 Bean 的配置元信息接口。包含 Bean 的类名即父类信息,作用域,生命周期回调,其它Bean依赖等。
BeanDefinitionRegistry#registry(BeanDefinition beanDefinition)
什么是BeanDefinition?
BeanDefinition配置阶段
BeanDefinition解析阶段
BeanDefinitionRegister
BeanDefinition注册阶段
BeanDefinition 合并
1. Spring Bean 元信息创建-- BeanDefinition
String -》 Class
Bean Class 类加载阶段
实例化前:回调InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation()方法;让我们有机会自己实例化对象。
实例化后:回调 InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation() 方法;让我们在填充Bean 之前回调。
Bean 实例化阶段
2. Spring Bean 创建
属性赋值前回调:InstantitationAwareBeanPostProcessor#postProcessProperties
3. Bean实例化后进行属性赋值
执行顺序
Aware 的处理是在 BeanPostProcessor 中处理的:ApplicationContextAwareProcessor
4. Aware 接口回调
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#font color=\"#f15a23\
Spring Bean 初始化完成回调:SmartInitializingSingleton
5. Spring Bean 初始化
在 BeanPostProcessor 中处理
6. Spring Bean 销毁
1.关闭Spring容器(应用上下文)
2.执行GC
Spring Bean 覆盖的 finalize() 方法被回调
7. Spring Bean 垃圾收集
Spring IoC 容器生命周期:IoC容器启动停止过程发生了什么?BeanFactory 是怎样处理 Bean 的生命周期的?
答:BeanPostProcessor 提供了 Spring Bean 初始化前和初始化后的生命周期回调;在 Spring 中,有很多特性都是基于 BeanPostProcessor 来实现的:应用一:并且允许对关心的Bean 进行扩展,替换等,比如:Spring AOP 的实现(AnnotationAwareAspectJAutoProxyCreator);应用二:并且,ApplicationContext 相关的系列 Aware 接口的回调也是基于 BeanPostProcessor 实现的。(ApplicationContextAwareProcessor);应用三:@Autowried,@Resource,@Inject 等自动装配的注解支持也是基于 BeanpoatProcessor(AutowiredAnnotationBeanPostProcessor)。
BeanPostProcessor 的使用场景有哪些?
答:BeanFactoryPostProcessor 是Spring BeanFactory(ConfigurableListableBeanFactory) 的后置处理器。主要用来扩展 BeanFactory 或者通过 BeanFactory 进行依赖查找和依赖注入。需要注意的是:BeanFactoryPostProcessor 必须由 Spring ApplicationContext 执行,BeanFactory 无法与其直接交互。 而 BeanPostProcessor 的回调实际上是由 BeanFactry (DefaultListableBeanFactory)来执行的。
BeanFactoryPostProcessor 的一个典型应用场景:扫描 @Component及其衍生注解,注册为Spring Bean
BeanFactoryPostProcessor和BeanPostProcessor的区别?
BeanFactory相关
可选的依赖
Setter 方法
少依赖,强制依赖
开发方便
字段
方法
xxxAware
接口回调注入
依赖注入有哪几种类型?
@Bean,@Autowried ,@EventListener等等
Spring BeanDefinition 作为依赖来源
Environment,MessageSource,ApplicationEventMulticaster 等等
单例对象作为依赖来源
// BeanFactory interface not registered as resolvable type in a plain factory.\t\t// MessageSource registered (and found for autowiring) as a bean.\t\tbeanFactory.font color=\"#f15a23\
游离的几个对象
非Spring容器管理对象作为依赖来源
外部化配置作为依赖来源
SpringIoC依赖来源?-- Spring容器管理的和游离的对象
依赖注入的来源比依赖查找多一项,那就是游离对象,即使用 registerResolvableDependency()注入容器的对象,注意:这些对象是不能通过依赖查找(getBean()方法)获取的。默认会帮我们注入四种
Spring容器管理的和游离的对象
不同:依赖查找的来源仅限于 Spring BeanDefinition 以及单例对象; 而依赖注入的来源还包括 Resolvable Dependency 以及 @Value 所标注的外部化配置。
Spring依赖注入和依赖查找的区别?注入和查找的依赖来源是否相同?
org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency
DependencyDescriptor descriptor 依赖描述符,描述当前要解析的 bean 的一些信息
在 bean后置处理器中 AutowiredAnnotationBeanPostProcessor 判断是有被 @Autowried 标注,是的话构造 依赖描述符,等信息,调用 DefaultListableBeanFactory#resolveDependency()方法进行依赖处理。
@Autowried 是如何被解析的?
依赖处理
是线程安全的,操作过程会增加一个互斥锁。很好理解,因为有些Bean是延迟初始化的,或者非单例的。
BeanFactory.getBean() 操作是否线程安全?
Singleton Bean 无论依赖查找还是注入,均为同一个对象。Prototype Bean 无论依赖查找还是注入,均为新生成的对象。
结论一:
无论是 Singleton 还是 Prototype 均会执行Bean初始化方法回调,不过只有 Singleton 只会执行销毁。
结论二:
singleonprototyperequestsessionapplication
Bean 作用域
否,Singleton Bean 仅在当前Spring IoC 容器(BeanFactory)中是单例对象。一个应用可能包含多个 BeanFactory
singleton Bean 是否在整个应用中是惟一的?
可以的,实际上 application Bean 与 singleton Bean 没有本质区别。
aoolication Bean 是否可以被其他方案替代?
依赖查找和依赖注入DL 和 DI
工作原理
@AliasFor,注解继承多个元注解,显示指定覆盖哪一个元注解的属性
显示别名
注解继承,覆盖元注解中的属性
隐式别名
注解别名、元标注
第一步:新建一个注解 @EnableXXX
第二步:@EnableXXX 上打上元注解 @Import()
第三步:利用@Import()注解的作用导入其他配置Bean,或者普通 Bean; 或者可以利用 @ImportSelector()注解进行逻辑条件导入
实现方式
@EnbaleXXX 模块驱动
实现原理
@Conditional 条件注解
Sring 注解编程
Spring Environment 抽象
this.startupDate = System.currentTimeMillis();
启动时间 - startipDate
this.closed.set(false);\t\tthis.active.set(true);
状态标识
// Initialize any placeholder property sources in the context environment.\t\tinitPropertySources();
初始化 propertySources
// Validate that all properties marked as required are resolvable:\t\t// see ConfigurablePropertyResolver#setRequiredProperties\t\tgetEnvironment().validateRequiredProperties();
校验 Environment 中必须属性
// Store pre-refresh ApplicationListeners...\t\tif (this.earlyApplicationListeners == null) {\t\t\tthis.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);\t\t}\t\telse {\t\t\t// Reset local application listeners to pre-refresh state.\t\t\tthis.applicationListeners.clear();\t\t\tthis.applicationListeners.addAll(this.earlyApplicationListeners);\t\t}
初始化事件监听器集合(早期事件)
上下文创建前准备阶段:prepareRefresh()
创建一个 DefaultListableBeanFactory 的实例
BeanFactory创建阶段:beanFactory = obtainFreshBeanFactory();
BeanFactory 准备阶段:\t\t\tprepareBeanFactory(beanFactory);
BeanFactory 后置处理阶段:postProcessBeanFactory(beanFactory);
Spring 应用上下文生命周期AbstractApplicationContext#refresh
极客时间
IOC
AOP,Spring AOP ,Aspectj,CGLIB 傻傻分不清?
基于接口
JDK 动态代理
基于父子继承
Cglib 动态代理
Spring 实现 AOP 的两种方式
Spring AOP 的底层实现
模拟实现 Spring 借助 BeanPostProcessor 实现动态代理
启用 Spring AOP: @EnableAspectJAutoProxy
默认是使用 JDk 动态代理
坑:代理对象内的方法相互调用
Spring 基于注解(Aspectj)的AOP编程
Spring 是如何为我们创建代理对象的?
A:原子性
C:一致性
I:持久性
D:隔离性
四个特点(ACID)
Connection.setAutoCommit(false);Connection.commit();Connection.rollback();
如何控制事务
给DataSourceTransaction注入DataSource依赖
加在方法上
加在类上
@Transactional
基于注解的事务使用:引入依赖 spring-tx
Spring控制事务的开发:AOP
两个事务同事访问同一条数据
描述了事务解决并发问题的特征
大部分情况下都不允许脏读的情况出现
一个事务读取了另一个事务没有提交的数据。
解决方案:@Transactional(isolation = Isolation.READ_COMMITTED)意思就是读: 可以读取已提交的数据
脏读/读未提交
一个事务中,多次读取相同(一条)的数据,但读取结果不一样。
解决方案:@Transactional(isolation = Isolation.REPEATABLE_READ)意思就是 可重复度
MySQL 默认隔离级别:可重复读
不可重复读
一个事物中,多次多整表进行统计查询,结果不一致。
解决方案:@Transactional(isolation = Isolation.SERIALIZABLE)意思就是,事务要阻塞执行
幻读
并发事务会产生那些问题?
通过隔离属性解决,隔离属性中设置不同的值,解决并发事务遇到的问题
并发事务问题如何解决?
MySQL:可重复读
最好使用默认值
现实中推荐使用 乐观锁
如果遇到并发事务问题
隔离属性在实战中的建议
隔离属性(Isolation)
增删改
@Transactional(propagation = Propagation.REQUIRED)外部不存在事务,开启新事物;存在事务,就加入。
查
@Transactional(propagation = Propagation.SUPPORTS)外部不存在事务,不开启新事物;存在事务,就加入。
其他的及其不常用。
事务嵌套
Propagation.REQUIRED(传播_需要)
建议使用默认值。
传播属性(propagation)为了解决一个事务方法调用另一个事务方法的事务嵌套问题喜马拉雅面试
针对只进行查询的事务,加上只读属性,会提高效率。
@Transactional(readOnly = true)默认值为 false
只读属性(readOnly)
数据库默认的等待时间是 50 s
@Transactional(timeout = 5)默认值为-1,表示使用数据库默认事务等待超时时间。
当前事务访问其他加锁事务,必须等待的时候,可以指定一个等待时间。超过等待时间就会抛出异常:TransactionTimedOutException:Transaction timed out
建议使用默认值
超时属性(timeout)
@Transactional(rollbackFor = RuntimeException.class)默认只对 RuntimeException 异常及其子类进行异常回滚。
Exception 和 RuntimeException 区别
异常属性
什么是事务属性?描述事务特征的一系类值
Spring 中的事务属性
Spring 事务
AOP
问题:Web 开发中如何创建工厂?
Web 环境下,Spring工厂为: WebApplicationContext/WebXmlApplicationContext
全局作用范围,整个应用程序共享,生命周期为:应用程序启动到停止。
非常适合用来存储 Spring 的Web工厂。
application(对应 ServletContext 对象)
session
request(对应 HttpServletRequest/ServletRequest对象)
page(对应 this)
四大作用域
servlvlet知识点回顾:
问题:那么如何保存Web工厂并且保证工厂唯一?
在 ServletContext 对象创建的时候把工厂存储在Servlet 的全局作用域: application(ServletContext 对象中)
问题:ServletContext 对象何时创建?
使用 ServletContextListener 在监听到 ServletContext 创建后,就创建 Web工厂并且往里面存放 Web工厂对象
问题:SpringMVC 中到底如何整合的?
1.创建工厂
把工厂存放在 ServletContext 中
SpringWebMVC 中有一个类: ContextLoaderListener 为我们做了上面的所有事情:
SpringMVC 与 Spring 如何整合?
SpringMVC 工作流程?
SpringMVC
font color=\"#f15a23\
Spring Boot 通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类,想要其生效必须引入spring-boot-starter-xxx包实现起步依赖
说一说 SpringBoot 自动装配原理?
说一说 SpringBoot 如何与 Tomcat 整合的?
Spring框架设计理念与设计模式分析
Spring
0 条评论
回复 删除
下一页