Spring-面试题
什么是Spring Framework?
- Spring 是一个开源应用框架,旨在降低应用程序开发的复杂度.
- 它是轻量级、松散耦合的.
- Spring核心主要两部分:
- IOC - 控制反转
- AOP - 面向切面编程可以将应用业务逻辑和系统服务分离,以实现高内聚.
Spring Framework有哪些核心模块?
- spring-core: Spring基础API模块,如资源管理,泛型处理;
- spring-beans: Spring Bean相关,如依赖查找,依赖注入;
- spring-aop: Spring AOP处理,如动态代理,AOP字节码提升;
- spring-context: 事件驱动,注解驱动,模块驱动等;
- spring-expression: Spring表达式语言模块;
什么是IoC?
IoC是反转控制,类似好莱坞原则,主要实现有依赖注入(DI)和依赖查找;
- IoC: 将类的对象的创建交给Spring容器来管理创建
- DI: 将类里面的属性在创建类的过程中给属性赋值
依赖查找和依赖注入的区别?
- 依赖查找是通过容器或上下文来查找所需的依赖关系,并将其注入到所需的类或组件中.
- 这种方式需要在代码中显式地通过容器或上下文来查找所需的依赖关系,因此它的灵活性较高,可以根据不同的需求进行定制和调整.
- 依赖注入则是通过容器或上下文来自动注入所需的依赖关系,而不需要在代码中显式地进行查找和注入.
- 这种方式可以将组件的创建和依赖关系的管理分离开来,使代码更加简洁、易于维护和可测试.
Spring作为IoC容器有什么优势?
典型的IoC管理,依赖查找和依赖注入
- AOP抽象
- 强大的第三方整合
- 事务抽象
- 事务机制
- 易测试性
- SPI扩展
- 更好的面向对象
BeanFactory和ObjectFactory的区别?
-
BeanFactory
是一个基础接口,它定义了Spring Bean容器的基本功能.它提供了一种机制来管理Spring Bean的创建、配置、装配和销毁等生命周期,同时也支持对Bean进行依赖注入. -
ObjectFactory
是一个工厂接口,它定义了一个简单的机制来创建对象的实例.它通常被用作Bean的属性值,以支持Bean属性的惰性初始化.当需要使用一个Bean属性时,ObjectFactory
会被调用来创建实际的Bean实例.与BeanFactory
不同的是,ObjectFactory
并不关心如何管理和配置Bean实例,它只关心如何创建Bean实例. -
ObjectFactory通常是针对单类Bean做延迟获取的,BeanFactory则是全局Bean管理的容器;
-
ObjectFacotry与BeanFactory均提供依赖查找的能力,不过ObjectFactory仅关注一个类或一种类型的Bean依赖查找,并且自身不具备依赖查找的能力,能力由BeanFactory输出;
-
BeanFactory则提供单一类型,集合类型以及层次类型的依赖查找;
- 单一类型依赖查找:根据Bean的名称或类型查找单个Bean实例,如
getBean(String name)
和getBean(Class<T> requiredType)
方法. - 集合类型依赖查找:根据Bean的类型查找多个Bean实例,返回一个集合,如
getBeansOfType(Class<T> type)
方法. - 层次类型依赖查找:可以查找到多个BeanFactory中的Bean实例,如
getParentBeanFactory()
方法,可以获取当前BeanFactory的父级BeanFactory.
- 单一类型依赖查找:根据Bean的名称或类型查找单个Bean实例,如
BeanFactory和FactoryBean的区别?
-
BeanFactory,以Factory结尾,表示它是一个工厂类(接口),用于管理Bean的一个工厂.在Spring中,BeanFactory是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖.
-
FactoryBean以Bean结尾,表示它是一个Bean,不同于普通Bean的是:它是实现了FactoryBean<T>接口的Bean,根据该Bean的ID从BeanFactory中获取的实际上是FactoryBean的getObject()返回的对象,而不是FactoryBean本身,如果要获取FactoryBean对象,请在id前面加一个&符号来获取.
- 实现了这个接口后,Spring在容器初始化时,把实现这个接口的Bean取出来,使用接口的getObject()方法来生成我们要想的Bean
-
FactoryBean
是一种特殊的Bean,需要注册IoC容器通过容器getBean
获取FactoryBean#getObject()
方法的内容,而BeanFactory#getBean
则是依赖查找,如果Bean没有初始化,那么将从底层查找或构建;-
一个常见的使用
FactoryBean
的例子是在Spring
中配置MyBatis
的SqlSessionFactory
对象.SqlSessionFactory
是一个复杂的对象,需要进行一些特定的处理,比如配置数据源、类型别名等.使用FactoryBean
,我们可以将这些配置逻辑封装到一个工厂类中,然后在Spring
的配置文件中定义一个FactoryBean
的Bean,从而获取SqlSessionFactory
对象.
-
对应关系就是 BeanFactory 就是那个造球模的机器,球模就是 Bean,而球模造出来的球就是 Bean 的实例。那前面所说的几个扩展点又在什么地方呢? BeanFactoryPostProcessor 对应到当造球模被造出来时,你将有机会可以对其做出设当的修正,也就是他可以帮你修改球模。而 InitializingBean 和 DisposableBean 是在球模造球的开始和结束阶段,你可以完成一些预备和扫尾工作。BeanPostProcessor 就可以让你对球模造出来的球做出适当的修正。最后还有一个 FactoryBean,它可是一个神奇的球模。这个球模不是预先就定型了,而是由你来给他确定它的形状,既然你可以确定这个球模型的形状,当然他造出来的球肯定就是你想要的球了,这样在这个箱子里尼可以发现所有你想要的球
内建依赖和自定以Bean的区别
- 内建依赖是指在BeanFactory创建时会预先实例化的Bean,包括
BeanFactory
自身、Environment
、SystemProperties
等,可以通过DefaultListableBeanFactory#preInstantiateSingletons()
方法进行预实例化. - 自定义Bean指的是用户手动注册到容器中的Bean,可以通过
DefaultSingletonBeanRegistry#registerSingleton
、ConfigurableListableBeanFactory#registerSingleton
等方法进行注册. - 依赖注入时,
@Autowired
、@Value
等注解会在DefaultListableBeanFactory#resolveDependency
方法中处理依赖关系,包括从resolvableDependencies
、已经实例化的单例Bean中查找依赖对象,同时也会通过调用BeanFactory#getBean
方法获取Bean. - 依赖查找通过
BeanFactory#getBean
方法进行查找,如果Bean没有被实例化,则会通过Bean定义的配置信息进行实例化.在实例化过程中,如果存在依赖关系,则会递归进行依赖查找和依赖注入操作.在依赖注入操作中,同样会从resolvableDependencies
、已经实例化的单例Bean中查找依赖对象.
BeanFactory和ApplicationContext谁才是Spring IoC容器?
BeanFactory
是Spring底层IoC容器;ApplicationContext
是具备应用特性的BeanFactory超集;ApplicationContext
是BeanFactory
的子接口,说明ApplicationContext is BeanFactory
,并且ApplicationContext
的包装类,也就是内部组合了BeanFactory
的实现(DefaultListableBeanFactory
)
依赖注入和依赖查找的依赖来源是否相同?
- 否;
- 依赖查找的来源仅限于
Spring BeanDefinition
以及单例对象; - 而依赖注入的来源还包括
Resolvable Dependency
以及@Value
所标注的外部化配置;
单例对象能在IoC容器启动后注册吗?
- 可以的
- 单例对象的注册与
BeanDefinition
不同,BeanDefinition
会被ConfigurableListableBeanFactory#freezeConfiguration
方法影响,从而冻结注册,单例对象则没有这个限制;
Spring依赖注入的来源有哪些?
-
Spring
BeanDefinition
-
单例对象
-
Resolvable Dependency
- 其中
Resolvable Dependency
是一个比较特殊的依赖来源,它是在容器启动时通过DefaultListableBeanFactory
的preInstantiateSingletons()
方法进行处理的,用于存储当前BeanFactory无法处理的、但是可以通过其他方式解析得到的依赖关系.
- 其中
-
@Value
外部化配置
有多少中依赖注入的方式 ?
- 构造器注入
Setter
注入- 字段注入
- 方法注入
- 接口回调注入
Spring内建的Bean的作用域有几种?
- singletion
- prototype
- request
- session
- application
- websocket
Singleton Bean是否在一个应用是唯一的?
- 否;
- Singletoin bean仅在当前Spring IoC容器(BeanFactory)中是单例对象;
BeanPostProcessor 的使用场景有哪些?
-
BeanPostProcessor
提供 Spring Bean 初始化前和初始化后的生命周期回调,分别对应postProcessBeforeInitialization
以及postProcessAfterInitialization
方法,允许对关心的 Bean 进行扩展,甚至是替换.- 实现自定义初始化逻辑:通过实现 BeanPostProcessor 接口,可以在 Bean 初始化前后进行一些自己的处理逻辑,例如修改 Bean 属性值、校验 Bean 状态等.
- 实现自定义销毁逻辑:通过实现 DisposableBean 接口或者使用 @PreDestroy 注解,可以在 Bean 销毁前执行自己的逻辑.
- 实现 AOP 非侵入式的增强:通过实现 BeanPostProcessor 接口,可以在 Bean 创建后,通过代理模式实现对 Bean 的增强,这种方式实现的 AOP 是非侵入式的.
- 实现 Bean 属性加密:通过实现 BeanPostProcessor 接口,可以在 Bean 属性注入时进行加密,并在获取属性值时进行解密,保证属性值的安全性.
- 实现缓存功能:通过实现 BeanPostProcessor 接口,可以在 Bean 创建后将其缓存起来,避免重复创建 Bean 实例,提高系统性能.
-
其中
ApplicationContext
相关的 Aware 回调也是基于BeanPostProcessor
实现,即ApplicationContextAwareProcessor
.
BeanFactoryPostProcessor 与BeanPostProcessor 的区别
-
BeanFactoryPostProcessor
和BeanPostProcessor
都是Spring框架提供的扩展点,用于在容器实例化Bean和初始化Bean的过程中进行拦截和定制化处理.它们的主要区别如下: -
执行时间不同
BeanFactoryPostProcessor
是在Bean的实例化之前执行的,用于修改BeanDefinition属性信息- 而
BeanPostProcessor
是在Bean的实例化之后执行的,用于修改Bean实例的属性信息.
-
处理的对象不同
BeanFactoryPostProcessor
的处理对象是BeanFactory中的所有BeanDefinition,因为它是在BeanFactory实例化Bean之前执行的.- 而
BeanPostProcessor
的处理对象是BeanFactory中所有的Bean实例,因为它是在Bean实例化之后执行的.
-
功能不同
BeanFactoryPostProcessor
主要用于修改BeanDefinition的属性信息,例如修改Bean的作用域、修改属性值等.BeanPostProcessor
主要用于修改Bean实例的属性信息,例如初始化前后执行的逻辑处理、属性值替换等.
BeanFactory是怎么处理Bean生命周期的
BeanFactory默认实现为DefaultListableBeanFactory
其中Bean生命周期与方法映射如下:
-
BeanDefinition配置阶段:
loadBeanDefinitions
-
BeanDefinition注册阶段:
registerBeanDefinition
-
BeanDefiniton解析阶段:
parseBeanDefinitions
-
getBean==>doGetBean
-
BeanDefinition合并阶段:
getMergedLocalBeanDefinition
-
Bean实例化前阶段:
applyBeanPostProcessorsBeforeInstantiation
和resolveBeforeInstantiation
-
Bean实例化:
createBeanInstance
-
Bean实例化后阶段:
applyBeanPostProcessorsAfterInstantiation
、applyBeanPostProcessorsBeforeInitialization
和populateBean
-
Bean属性赋值前阶段:
applyBeanPostProcessorsBeforeInitialization
-
Bean属性赋值阶段:
applyPropertyValues
-
Bean Aware接口回调阶段:
applyBeanPostProcessorsBeforeInitialization
和invokeAwareMethods
-
Bean 初始化前阶段:
applyBeanPostProcessorsBeforeInitialization
-
Bean 初始化阶段:
invokeInitMethods
-
Bean 初始化后阶段:
applyBeanPostProcessorsAfterInitialization
-
Bean 初始化完成阶段:
preInstantiateSingletons
-
Bean 销毁前阶段:
applyBeanPostProcessorsBeforeDestruction
-
Bean 销毁阶段:
destroyBean
-
Bean 销毁完成阶段:
destroySingletons
Spring 內建 XML Schema 常见有哪些?
命名空间 | 所属模块 | Schema 资源 URL |
---|---|---|
beans | spring-beans | https://www.springframework.org/schema/beans/spring-beans.xsd |
context | spring-context | https://www.springframework.org/schema/context/spring context.xsd |
aop | spring-aop | https://www.springframework.org/schema/aop/spring-aop.xsd |
tx | spring-tx | https://www.springframework.org/schema/tx/spring-tx.xsd |
util | spring-beans | https://www.springframework.org/schema/util/spring-util.xsd |
tool | spring-beans | https://www.springframework.org/schema/tool/spring-tool.xsd |
Spring配置元信息具体有哪些?
- Bean 配置元信息:通过媒介(如 XML、Proeprties 等),解析 BeanDefinition
- IoC 容器配置元信息:通过媒介(如 XML、Proeprties 等),控制 IoC 容器行为,比如注解驱动、AOP 等
- 外部化配置:通过资源抽象(如 Proeprties、YAML 等),控制 PropertySource
- Spring Profile:通过外部化配置,提供条件分支流程
Extensible XML authoring 的缺点?
- 高复杂度:开发人员需要熟悉 XML Schema,spring.handlers,spring.schemas以及 Spring API .
- 嵌套元素支持较弱:通常需要使用方法递归或者其嵌套解析的方式处理嵌套(子)元素.
- XML 处理性能较差:Spring XML 基于 DOM Level 3 API 实现,该 API 便于理解,然而性能较差.
- XML 框架移植性差:很难适配高性能和便利性的 XML 框架,如 JAXB
Spring配置资源中有哪些常见类型?
- XML资源
- Properties资源
- YAML资源
请例举不同类型Spring配置资源?
- XML资源
- 普通Bean Definition XML配置资源 :
*.xml
- Spring Schema 资源 :
*.xsd
- 普通Bean Definition XML配置资源 :
- Properties资源
- 普通Properties格式资源:
*.properties
- Spring Handler实现类映射文件:
META-INF/spring.handlers
- Spring Schema资源映射文件:
META-INF/spring.schemas
- 普通Properties格式资源:
- YAML资源
- 普通YAML配置资源:
*.yaml
或*.yml
- 普通YAML配置资源:
Java标准资源管理扩展的步骤
- 简易实现
- 实现
URLStreamHandler
并放置在sun.net.www.protocol.${protocol}.Handler
包下
- 实现
- 自定义实现
- 实现
URLStreamHandler
- 添加
-Djava.protocol.handler.pkgs
启动参数,指向URLStreamHandler
实现类的包下
- 实现
- 高级实现
- 实现
URLStreamHandlerFactory
并传递到URL之中
- 实现
SpringBoot为什么要新建MessageSource Bean
AbstractApplicationContext
的实现决定了MessageSource
內建实现- Spring Boot 通过外部化配置简化
MessageSource Bean
构建 Spring Boot
基于Bean Validation
校验非常普遍
Spring国际化接口有哪些?
- 核心接口:
MessageSource
- 层次性接口:
org.springframework.context.HierarchicalMessageSource
Spring 有哪些 MessageSource 內建实现 ?
-
org.springframework.context.support.ResourceBundleMessageSource
- 基于
java.util.ResourceBundle
的MessageSource
实现,可以从属性文件中加载消息.通过setBasename
方法指定属性文件的名称前缀即可.
- 基于
-
org.springframework.context.support.ReloadableResourceBundleMessageSource
- 基于
ResourceBundleMessageSource
实现,支持动态加载属性文件.通过setBasename
和setCacheSeconds
方法指定属性文件的名称前缀和缓存时间即可.
- 基于
-
org.springframework.context.support.StaticMessageSource
- 静态
MessageSource
实现,消息被硬编码在实现中,适用于消息数量较少的情况.
- 静态
-
org.springframework.context.support.DelegatingMessageSource
- 代理
MessageSource
实例,可以切换不同的MessageSource
实现.
- 代理
-
org.springframework.context.HierarchicalMessageSource
- 代理
MessageSource
实例,可以切换不同的MessageSource
实现.
- 代理
如何实现配置自动更新 MessageSource ?
- 主要技术
Java NIO2
:java.nio.file.WatchService
Java Concurrency
:java.util.concurrent.ExecutorService
Spring
:org.springframework.context.support.AbstractMessageSource
Spring 校验接口是哪个?
org.springframework.validation.Validator
Spring 有哪些校验核心组件?
- 检验器:
org.springframework.validation.Validator
- 错误收集器:
org.springframework.validation.Errors
- Java Bean 错误描述:
org.springframework.validation.ObjectError
- Java Bean 属性错误描述:
org.springframework.validation.FieldError
- Bean Validation 适配:
org.springframework.validation.beanvalidation.LocalValidatorFactoryBean
Spring 类型转换器接口有哪些 ?
- 类型转换接口 -
org.springframework.core.convert.converter.Converter
- 通用类型转换接口 -
org.springframework.core.convert.converter.GenericConverter
- 类型条件接口 -
org.springframework.core.convert.converter.ConditionalConverter
- 综合类型转换接口 -
org.springframework.core.convert.converter.ConditionalGenericConverter
Java 泛型擦写发生在编译时还是运行时?
- Java 泛型擦除发生在编译时.在编译期间,Java 编译器会将所有的泛型类型信息删除,并且使用原始类型替换所有类型参数,这个过程就叫做泛型擦除.在运行时,Java 虚拟机只知道这些对象的类型是 Object 或者是其他非泛型类型,而不知道它们的具体泛型类型.因此,由于泛型擦除,运行时无法访问泛型类型的具体信息.
请介绍 Java 5 Type 类型的派生类或接口 ?
-
java.lang.Class
- 表示具体的类型.在 Java 编程中,Class 对象可以用于获取类的名称、方法、属性等元信息
-
java.lang.reflect.GenericArrayType
- 表示数组类型,例如
T[]
.
- 表示数组类型,例如
-
java.lang.reflect.ParameterizedType
- 表示参数化类型,即带有参数类型的类型,例如
List<String>
就是一个参数化类型.
- 表示参数化类型,即带有参数类型的类型,例如
-
java.lang.reflect.TypeVariable
- 表示类型变量,即泛型类型参数,例如
T
.
- 表示类型变量,即泛型类型参数,例如
-
java.lang.reflect.WildcardType
- 表示通配符类型,即
?
,可用于限定泛型类型的上限或下限.
- 表示通配符类型,即
Spring事件核心接口/组件
- Spring事件:
org.springframework.context.ApplicationEvent
- Spring事件监听器:
org.springframework.context.ApplicationListener
- Spring事件发布器:
org.springframework.context.ApplicationEventPublisher
- Spring事件广播器:
org.springframework.context.event.ApplicationEventMulticaster
Spring同步和异步事件处理的使用场景
- Spring同步事件: 绝大多数Spring使用场景: 如
ContextRefreshedEvent
- Spring异步事件: 主要
@EventListener
与@Async
,实现异步处理,不阻塞主线程,不如长时间的数据计算任务等.不要轻易调整SimpleApplicationEventMulticaster
中关联的taskExecutor
对象,除非使用者非常了解Spring事件机制,否则容易出现异常行为;
简单介绍Spring Environment
接口
- 核心接口:
org.springframework.core.env.Environment
- 父接口:
org.springframework.core.env.PropertyResolver
- 可配置接口:
org.springframework.core.env.ConfigurableEnvironment
- 职责:
- 管理Spring配置属性源
- 管理
Profiles
Spring应用上下文生命周期有哪些阶段?
- 刷新阶段:
ConfigurableApplicationContext#refresh
- 启动阶段:
ConfigurableApplicationContext#start
- 停止阶段:
ConfigurableApplicationContext#stop
- 关闭阶段:
ConfigurableApplicationContext#close