面试Spring全家桶(一)
谈谈你对Spring 的理解
什么是Spring
- Spring 是一个庞大的生态体系,可以构建Java 应用所需的一切基础设施
- 通常Spring 指的是Spring Frameword
核心解释
-
Spring 是一个轻量级的开源容器框架
-
Spring 是为了解决企业级应用开发的业务逻辑层和其他各层对象和对象直接耦合的问题
-
Spring 是一个IOC和AOP的容器框架
- IOC:控制反转
- AOP:面向切面编程
- 容器:包含并管理应用对象的生命周期
Spring 的优缺点是什么
优点
Spring当中有IOC,AOP,声明事务、集成三方框架比较方便,简化了我们的开发
- Spring IOC 帮我们集中管理了对象,降低了对象与对象之间的耦合度,方便维护对象
- Spring AOP 我们可以在不修改代码的情况下可以对业务代码进行增强,减少重复代码,提高了开发效率,方便系统维护
- 声明事务的支持 :提高了我们的开发效率,因为我们需要一个简单的注解@Transactional
- Spring 实现了测试,是我们可以结合Junit非常方便测试Spring Bean Spring MVC
- Spring 拥有非常强大的粘合度,或者说集成能力非常强,我们只需要简单的配置就可以集成第三方框架,
- 简化了开发,帮我们封装了很多功能性代码
- Spring底层的实现,大量的使用了反射…设计模式等等都值得我们学习,提供了非常多的扩展接口共外部进行扩展
缺点
- Spring 明明是一个很轻量级的框架,给人的感觉却大而全
- 使用门槛高,入门Spring 需要很长的时间
- 从应用层面来说是没有缺点的
- 简化了我们的开发,如果想深入底层去了解的话就非常困难(上层使用越简单,底层封装得就与复杂)
- 源码缺点:由于Spring 大而全(要集成这么多的框架,提供非常多的扩展点,经过十多年的代码迭代),代码量非常大,对我们深入学习代码带来了一定的困难
什么是Spring IOC 容器?有什么作用?优点是什么?
IOC(控制反转)
IOC (控制反转),它把传统上由程序代码直接操控的对象的调用权交给容器,通过容器来实现对象组件的装配和管理,所谓“控制反转”的概念就是对组件对象控制权的转移,从程序代码本身转移到了容器外部
Spring IOC 负责创建对象,管理对象(通过依赖注入(DI),装配对象,配置对象,并且管理这些对象的整个生命周期)
对于IOC来说,最重要的就是容器。容器管理着Bean的生命周期,控制着Bean的依赖注入
控制反转(IOC)的作用
- 管理对象的创建和依赖关系的维护,对象的创建并不是一个简单的事情,在对象关系比较复杂时,如果依赖关系需要程序员来维护的话相当头疼
- 解耦,有容器去维护具体的对象
- 托管了类的产生过程,比如我们需要在类的产生过程中做一些处理 ,最直接的例子就是代理,如果有容器程序可以把这部分交给容器,应用程序则无需关系类时如何完成代理的
IOC的优点是什么?
集中管理对象,方便维护,降低耦合度
- 最小的代价和最小的入侵行时松散耦合得以实现
- IOC容器支持加载服务时的饿汉模式初始化和懒加载
Sping IOC的实现机制是什么?
Spring IOC 的实现机制
一 核心思想与总体流程
-
IOC(Inversion of Control,控制反转)将对象的创建、装配、生命周期管理交给容器;**DI(Dependency Injection,依赖注入)**是 IOC 的具体实现方式(通过构造器、Setter、字段把依赖“送进来”)。
-
典型流程:
- 读取配置元数据(XML、注解或 Java 配置类);
- 解析并注册 BeanDefinition(类名、作用域、依赖关系等);
- 实例化 Bean(通常借助反射,必要时结合工厂模式);
- 依赖注入(按类型/名称解析并注入依赖);
- 初始化回调(如 @PostConstruct、InitializingBean、init-method);
- 使用与销毁(容器关闭时执行 @PreDestroy、DisposableBean、destroy-method)。
-
该流程既支持XML 配置,也支持注解/Java 配置类,并可通过Bean 后处理器在初始化前后扩展行为。
二 关键实现要点
- 工厂模式:容器充当“对象工厂”,屏蔽对象创建细节,统一管理 Bean 的创建与获取。
- 反射机制:运行期读取类结构、调用构造器/方法/字段,实现动态实例化与注入,是 DI 的技术底座。
- 容器接口与实现:
- BeanFactory:IoC 容器根接口,强调基础能力,默认延迟加载;
- ApplicationContext:更高级容器,提供国际化、事件、资源加载、环境抽象等企业能力,通常启动即预初始化单例 Bean。
- 自动装配(Autowiring):
- @Autowired:按类型(byType)注入,配合 @Qualifier 指定名称;
- @Resource:按名称(byName),也可结合类型回退;
- 支持构造器、Setter、字段多种注入方式。
- Bean 作用域:Singleton(默认)、Prototype、Web 环境下的 Request/Session/Application,不同作用域决定实例管理与生命周期策略。
三 Bean 生命周期与扩展点
- 简化流程:实例化 → 属性填充 → 初始化回调 → 使用 → 销毁;
- 细化流程(含扩展点):
- 实例化(调用构造器);
- 属性赋值(依赖注入);
- 执行 BeanPostProcessor.postProcessBeforeInitialization;
- 执行初始化回调(@PostConstruct / InitializingBean / init-method);
- 执行 BeanPostProcessor.postProcessAfterInitialization;
- 使用中;
- 容器关闭时执行 @PreDestroy / DisposableBean / destroy-method。
- 说明:Spring 只对单例 Bean 管理完整生命周期;Prototype Bean 创建后交由使用者管理,容器不再追踪其后续生命周期。
四 配置方式与自动装配策略
-
配置方式对比:
- XML:集中、显式,适合遗留系统或复杂 Bean 组合;
- 注解 + 组件扫描(@ComponentScan):开发效率高,适合现代应用;
- Java 配置类(@Configuration + @Bean):类型安全、IDE 友好,便于编程式与条件化装配。
-
自动装配与语义:
- @Autowired:默认按类型装配,配合 @Qualifier 指定 Bean 名称;
- @Resource:按名称装配,名称不匹配时回退到类型;
- @Inject(JSR-330):按类型装配,语义与 @Autowired 接近。
-
常见实践:优先使用构造器注入表达“必需依赖”,提升不变性与可测试性;对可选/可变依赖使用 Setter 注入
。
五 循环依赖与性能要点
-
循环依赖:Spring 对单例 + Setter/字段注入的循环依赖通过三级缓存(提前暴露早期引用)解决;构造器注入导致的循环依赖无法自动解决,应通过@Lazy 延迟加载或重构设计拆分依赖。
-
启动性能:大型应用在启动时进行配置解析、BeanDefinition 注册、实例化与初始化可能较慢;可通过条件化 Bean(如 @Conditional)、合理划分 Profile、减少不必要的自动扫描范围来优化。
简单工厂+反射的机制实现的 SpringBeanFactory 简单工厂,在实例化的的时候使用反射。
Spring IOC 和DI的区别是什么?
核心定义
- IOC(Inversion of Control,控制反转):一种设计原则,把对象的创建、装配、生命周期管理的控制权从应用代码交给外部容器(如 Spring 容器),从而实现解耦与集中治理。
- DI(Dependency Injection,依赖注入):IOC 的具体实现机制;容器在创建对象时,将对象所依赖的其他 Bean通过构造器、Setter 或字段等方式“注入”,而不是由对象自己创建或查找。
- 关系要点:IOC 是目标与思想,DI 是落地手段;没有 DI,IOC 的对象协作关系无法建立
差异对比
维度 | IOC(控制反转) | DI(依赖注入) |
---|---|---|
概念层级 | 设计原则/思想 | 实现机制/模式 |
关注点 | 谁来控制对象的创建与管理(由容器接管) | 如何把依赖“送入”对象(构造器/Setter/字段) |
作用范围 | 更广泛:涵盖 Bean 的创建、装配、作用域、生命周期、事件等 | 更聚焦:解决“依赖如何被提供”的问题 |
表现形式 | 使用容器管理 Bean(如 BeanFactory / ApplicationContext) | 使用 @Autowired / @Resource / @Inject 等注解或 XML 配置完成注入 |
抽象程度 | 抽象层级高,强调“控制权的转移” | 抽象层级低,强调“注入方式与细节” |
依赖关系 | 强调“依赖抽象而非具体实现”,由容器装配 | 具体执行“把哪个实现注入进来” |
典型产出 | 可复用、可替换的 Bean 定义与生命周期管理 | 可测试、可配置的对象协作关系 |
本质上:IOC 定义“谁来管”,DI 回答“怎么给”
IOC 控制反转:控制的是对象的权力,以前是程序员自己创建对象的,IOC 将控制对象的权力交给程序
DI 依赖注入:是IOC的实现,是实现IOC 的一个重要部分,
紧耦合和松耦合有什么区别?如何编写松耦合的代码
- 紧耦合:在代码中直接New 一个对象(紧密的耦合是指类之间的高度依赖)
- 松耦合:松耦合是通过促进单一职责和关注点分离,依赖倒置的原则来实现
BeanFactory的作用
- BeanFactory 是Spring 中**非常核心的一个顶层接口**
- 他是Bean的工厂,它的**主要职责就是生产Bean**
- 它实现了**简单工厂的设计模式**,通过调用GetBean传入标识生产一个Bean
- 它有分厂多的实现类,每个工厂都有不同的职责(单一职责)功能,最强大的工厂是DefaultListableBeabFactory,Sping 底层就是使用的该类实现工厂进程生产Bean的
- BeanFactory 也是容器,也可以使用getBean方法来获取对象
BeanDefinition的作用
它的作用主要存储Bean的**定义信息**:决定Bean的生产方式
如:spring.xml
<bean class="com.morna.User" id="user" scope="singleton" lazy="false" abstract="false" autowire="null"><property name="username" value="moran">
</bean>
后续BeanFactory根据这些信息就行生产Bean:比如实例化可以通过class反射进而得到实例对象,比如lazy 则不会在IOC加载时创建Bean
BeanFactory和ApplicationContext有什么区别?
核心定位
- BeanFactory:是Spring IOC容器的跟容器 ,提供了Bean 注册,实例化,依赖注入、声明周期等能力,强调“容器内核”
- ApplicationContext 是BeanFactory的超集,在Bean管理之上叠加了国际化、事件机制、资源加载、环境抽象、Web集成等企业级能力,是现在Spring应用的事实容器标准。
关键差异对比
维度 | BeanFactory | ApplicationContext |
---|---|---|
功能范围 | 基础 IoC 容器,聚焦 Bean 的创建与注入 | 在 BeanFactory 之上,增加 i18n、事件、资源、环境、Web 等企业能力 |
Bean 初始化时机 | 默认按需初始化(首次 getBean 才创建),利于节省内存 | 默认预初始化单例 Bean(容器启动即创建),便于启动期发现问题 |
配置与使用方式 | 支持 XML/注解/Java 配置,但功能相对基础 | 支持 XML、注解、Java 配置类 等多种方式,更灵活易用 |
事件机制 | 不提供内置事件发布/监听 | 提供 ApplicationEvent / ApplicationListener 事件模型 |
国际化 | 不直接支持 | 提供 MessageSource 支持多语言 |
资源加载 | 无统一资源加载抽象 | 实现 ResourceLoader,统一加载类路径、文件系统等资源 |
Web 上下文 | 不面向 Web | 提供 WebApplicationContext 等 Web 专用上下文 |
后处理器注册 | 部分后处理器需手动注册 | 常见后处理器自动注册,开箱即用 |
典型实现 | DefaultListableBeanFactory(核心实现);XmlBeanFactory 已废弃 | AnnotationConfigApplicationContext、ClassPathXmlApplicationContext、FileSystemXmlApplicationContext、GenericWebApplicationContext 等 |
说明:在现代 Spring(含 Spring Boot)实践中,ApplicationContext 是首选;只有在资源极其受限或极简测试/嵌入式场景,才会考虑直接使用 BeanFactory
BeanFactory和FactoryBean 有什么区别?
核心定位与职责
- BeanFactory:Spring IOC容器的根接口,它是容器的本身,负责Bean的创建,装配,作用域与生命周期管理等等,常见时间为DefaultListableBeanFactory,而ApplicationContext是其更高级别的子接口,获取Bean的如果是getBean方法
- FactoryBean:一种可编程创建对象的特殊Bean接口,用于封装复杂对象的构造过程(如代理,第三方库集成等)。它本身是容器中的一个Bean,但对外暴露的是其getObject()返回的目标对象,核心方法为:getObject(),getObjectType(),isSingleton()
关键差异对比
维度 | BeanFactory | FactoryBean |
---|---|---|
角色定位 | IoC容器核心接口,管理所有的Bean | 特殊的Bean,用于创建/装配其他Bean |
职责 | 管理Bean的生命周期与依赖注入 | 封装复杂创建逻辑,返回目标对象 |
典型实现/使用方 | DefaultListableBeanFactory、ApplicationContext | 开发者实现(如自定义工厂),Spring 亦是提供大量内置实现 |
获取方式 | 直接按Bean名称获取实例吗,如:getBean(“name”) | 获取目标对象:getBean(“name”),获取工厂本身:getBean(“&name”) |
核心方法 | getBean、containsBean、isSingleton、getType等等 | getObject、getObjectType、isSingleton |
设计意图 | 作为容器/工厂的“总入口” | 作为单个Bean的工厂,解耦复杂实例化细节 |
特殊约定 | 定义常量FACTORY_BEAN_PREFIX=“&” | 带名称获取工厂本身,不带则取产物对象 |
说明:在容器内部,当请求一个实现了FactoryBean的Bean时,框架会识别并调用getObject()返回目标对象,若要获取工厂实例本身,则需要在名称前添加"&",这是两者的最关键交互差异
//定义一个FactoryBean@Comment("myServiceFactory")
public class MyServiceFactoryBean implements FactoryBean<MyService>{@Overridepublic MyService getObject(){return new MyServiceImpl();}@Overridepublic Class<?> getObjectType(){return MyService.class;}@Overridepublic boolean isSingleton(){return true;}
}
// 使用
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
MyService sq = ctx.getBean("myServiceFactory",MyService.class); // 工厂产物
FactoryBean<?> f = ctx.getBean("&myServiceFactory",MyService.class);//工厂本身
要点:不加&得到的时getObject()的返回的对象,加&得到的时FactoryBean实例