Spring
注意:括号中为八股在每次面试中出现的概率
Bean 的生命周期了解么?(576/1759=32.7%)
Bean 的生命周期是 Spring 容器管理 Bean 从创建到销毁的整个过程,主要包括实例化、属性赋值、初始化和销毁这四个阶段,下面我将分阶段进行讲述。
首先,创建 Bean 实例。Spring 容器会根据配置文件或注解信息,使用 Java 反射机制实例化 Bean。
然后,属性赋值和依赖注入。Spring 会解析 Bean 的属性,例如 @Autowired、@Value 或 @Resource 等注解,并通过构造方法或 setter 方法将依赖注入到 Bean 中。
接着,初始化 Bean。在这个阶段,Spring 会进行一些额外的处理:
如果 Bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,Spring 会调用相应的 set 方法,将 Bean 名称、类加载器和 BeanFactory 传递给 Bean。
如果有 BeanPostProcessor 处理器,Spring 会在初始化前调用 postProcessBeforeInitialization() 方法。
如果 Bean 实现了 InitializingBean 接口,则会执行 afterPropertiesSet() 方法。
如果在配置中指定了 init-method,Spring 会调用该方法执行自定义初始化逻辑。
初始化后,Spring 还会调用 BeanPostProcessor 的 postProcessAfterInitialization() 方法。
最后,销毁 Bean。当 Spring 容器关闭时,它会销毁 Bean:
如果 Bean 实现了 DisposableBean 接口,则会执行 destroy() 方法。
如果在配置中定义了 destroy-method,则会调用指定的销毁方法。
如果使用 @PreDestroy 注解标记了销毁前的方法,Spring 也会执行该方法释放资源。
如何记忆:
1.口诀记忆法
口诀:
创建实例先登场,
属性赋值注入忙。
初始化中三步走,
销毁资源不慌张。
解释:
“创建实例先登场” :对应 Bean 的实例化阶段。
“属性赋值注入忙” :对应属性赋值和依赖注入阶段。
“初始化中三步走” :对应初始化阶段的三个主要步骤(Aware 接口、BeanPostProcessor 前后处理、自定义初始化逻辑)。
“销毁资源不慌张” :对应销毁阶段,释放资源。
2.联想记忆法
联想:开餐馆的流程
创建实例 :开一家新餐馆,首先要租下店面(创建 Bean 实例)。
属性赋值 :装修店面并采购设备(属性赋值),比如冰箱、烤箱等(依赖注入)。
初始化 :
餐馆老板告诉员工餐馆的名字(Aware 接口)。
厨师检查厨房设备是否正常(BeanPostProcessor 前处理)。
正式开业前,老板安排试营业(InitializingBean 或 init-method)。
开业后,厨师调整菜单(BeanPostProcessor 后处理)。
销毁 :餐馆关门时,清理库存、关闭设备(DisposableBean 或 destroy-method)。
拓展:
1.Spring Bean 的生命周期图
2.Bean 是线程安全的吗?
Spring 框架中的 Bean 是否具备线程安全性,主要取决于它的作用域以及是否包含可变状态。
Bean 线程安全性的影响因素
Spring 默认的 Bean 作用域是 singleton,即在 IoC 容器中只会创建一个实例,并被多个线程共享。如果这个 Bean 维护了可变的成员变量,就可能在并发访问时引发数据不一致的问题,从而导致线程安全风险。
而 prototype 作用域 下,每次获取 Bean 都会创建新的实例,因此不会发生资源竞争,自然也就没有线程安全问题。
单例 Bean 是否一定不安全?
不一定!
无状态 Bean 是线程安全的:例如常见的 Service 或 Dao 层 Bean,它们通常不存储可变数据,仅执行业务逻辑,因此不会受到并发影响。
有状态 Bean 可能会引发线程安全问题:如果 Bean 存储了可变成员变量,比如用户会话信息、计数器等,可能会因多个线程同时访问导致数据不一致。
解决有状态 Bean 的线程安全问题
如果一个单例 Bean 需要维护状态,可通过以下方式确保线程安全:
设计为无状态 Bean:尽量避免定义可变成员变量,或在方法内部使用局部变量。
使用 ThreadLocal:让每个线程拥有独立的变量副本,防止数据共享导致冲突。
同步控制:在访问共享资源时,使用 synchronized 或 ReentrantLock 进行加锁,确保线程互斥访问。
3.将一个类声明为 Bean 的注解有哪些?
注解 |
用途 |
示例场景 |
@Component |
通用注解,标记任意类为 Bean |
通用组件 |
@Service |
标记服务层组件 |
业务逻辑层 |
@Repository |
标记数据访问层组件 |
数据库操作 |
@Controller |
标记表现层组件 |
Web 控制器 |
@Configuration |
配置类,配合 @Bean 显式声明 Bean |
自定义 Bean 配置 |
@Conditional |
根据条件动态注册 Bean |
环境或逻辑条件 |
@Profile |
根据激活的环境注册 Bean |
不同环境下的配置 |
@Scope |
定义 Bean 的作用域 |
单例、原型等 |
@RestController |
RESTful Web 服务控制器 |
API 接口开发 |
@EnableScheduling |
配合 @Scheduled 声明定时任务 Bean |
定时任务 |
谈谈自己对于 Spring IoC 的了解(664/1759=37.7%)
Spring IoC(Inversion of Control,控制反转)是 Spring 框架的核心机制之一,负责管理对象的创建、依赖关系和生命周期,从而实现组件解耦,提升代码的可维护性和扩展性。接下来我会详细讲述 Spring IoC 的核心概念、实现方式、工作流程以及它解决的问题。
首先,IoC 的核心思想 是将对象的管理权从应用程序代码中转移到 Spring 容器。传统方式下,类 A 依赖于类 B,A 需要自己创建 B 的实例,而在 IoC 模式下,Spring 负责实例化和注入 B,A 只需要声明依赖即可。
其次,Spring IoC 主要通过依赖注入(DI)来实现。Spring 通过 XML 配置、Java 注解(@Autowired、@Resource)或 Java 代码(@Bean)定义 Bean 及其依赖关系,容器会在运行时自动解析并注入相应的对象。
接着,Spring IoC 的工作流程 可以分为三个阶段:
第一个阶段是IOC 容器初始化,
Spring 解析 XML 配置或注解,获取所有 Bean 的定义信息,生成 BeanDefinition。
BeanDefinition 存储了 Bean 的基本信息(类名、作用域、依赖等),并注册到 IOC 容器的 BeanDefinitionMap 中。
这个阶段完成了 IoC 容器的初始化,但还未实例化 Bean。
第二个阶段是Bean 实例化及依赖注入
Spring 通过反射实例化那些 未设置 lazy-init 且是单例模式 的 Bean。
依赖注入(DI)发生在这个阶段,Spring 根据 BeanDefinition 解析 Bean 之间的依赖关系,并通过构造方法、setter 方法或字段注入(@Autowired)完成对象的注入。
第三个阶段是Bean 的使用
业务代码可以通过 @Autowired 或 BeanFactory.getBean() 获取 Bean。
对于 设置了 lazy-init 的 Bean 或非单例 Bean,它们的实例化不会在 IoC 容器初始化时完成,而是在 第一次调用 getBean() 时 进行创建和初始化,且 Spring 不会长期管理它们。
最后,Spring IoC 主要解决三个问题,
第一个是降低耦合,组件之间通过接口和依赖注入解耦,增强了代码的灵活性。
第二个是简化对象管理,开发者无需手动创建对象,Spring 统一管理 Bean 生命周期。
第三个是提升维护性,当需要修改依赖关系时,只需调整配置,而无需修改业务代码。
如何记忆:
1.口诀记忆法
口诀:
控制反转交容器,
依赖注入解耦合。
初始化时解析好,
实例注入用得妙。
使用阶段灵活调,
降低耦合效率高。
解释:
“控制反转交容器” :IoC 核心思想是将对象管理权交给 Spring 容器。
“依赖注入解耦合” :通过依赖注入(DI)实现组件之间的解耦。
“初始化时解析好” :IoC 容器初始化阶段解析 BeanDefinition。
“实例注入用得妙” :Bean 实例化和依赖注入阶段完成对象创建与注入。
“使用阶段灵活调” :业务代码可以通过多种方式获取 Bean。
“降低耦合效率高” :Spring IoC 解决了耦合问题,提升了代码维护性。
2.谐音记忆法
谐音:爱豆三步曲
“爱” :Inversion of Control(控制反转)。
“豆” :Dependency Injection(依赖注入)。
“三步曲” :Spring IoC 的三个主要阶段(初始化、实例化、使用)。
具体谐音:
“爱” :控制反转,爱上了 Spring 容器。
“豆” :依赖注入,像一颗颗小豆子被种下。
“三步曲” :第一步:解析清单(初始化);第二步:种下豆子(实例化);第三步:收获果实(使用)。
示例:
想象一个农夫种豆子的过程:
农夫(开发者)把种子(对象)交给土地(Spring 容器);
土地自动浇水施肥(依赖注入);
最后收获成熟的豆子(使用阶段)。
拓展:
1.传统应用程序图
2.IoC控制反转图
3.IoC 和 DI 的区别?
IoC(Inversion of Control,控制反转)和 DI(Dependency Injection,依赖注入)是 Spring 框架中非常重要的两个概念。虽然它们密切相关,但它们的含义和作用有所不同。以下是它们的区别及联系:
(1)定义与核心思想
IoC(控制反转)
定义:控制反转是一种设计原则,指的是将对象的创建、依赖管理和生命周期的控制权从应用程序代码转移到框架或容器中。
核心思想:传统开发中,对象需要自己负责创建依赖的对象(即“正向控制”)。而在 IoC 中,对象不再负责创建依赖,而是由容器来管理这些依赖关系。
DI(依赖注入)
定义:依赖注入是 IoC 的一种实现方式,指的是容器通过构造方法、setter 方法或字段注入的方式,将对象的依赖自动传递给它。
核心思想:对象只需要声明它需要的依赖,而不需要关心如何获取这些依赖。容器会负责将依赖注入到对象中。
(2)区别对比
维度 |
IoC(控制反转) |
DI(依赖注入) |
定义 |
一种设计原则,强调控制权的转移 |
一种具体实现方式,用于实现 IoC |
关注点 |
对象的创建、依赖管理和生命周期的控制权 |
如何将依赖传递给对象 |
实现方式 |
通过容器(如 Spring 容器)管理对象 |
通过构造方法、setter 方法或字段注入依赖 |
范围 |
更广泛,包含 DI 和其他实现方式 |
是 IoC 的一个子集 |
示例 |
Spring 容器接管了对象的创建和管理 |
Spring 容器通过 |
(3)联系
DI 是 IoC 的实现方式:依赖注入是控制反转的一种具体实现形式。IoC 是一种更广泛的设计原则,而 DI 是 IoC 的一种技术手段。
共同目标:两者都旨在降低代码的耦合性,提升代码的可维护性和扩展性。
(4)示例说明
传统方式(无 IoC 和 DI)
public class UserService { private UserRepository userRepository; public UserService() { this.userRepository = new UserRepository(); // 自己创建依赖 } public void addUser(String name) { userRepository.save(name); } }
问题:UserService 直接依赖 UserRepository,耦合度高。如果需要更换 UserRepository 的实现,必须修改 UserService 的代码。
使用 IoC 和 DI
@Component public class UserService { @Autowired private UserRepository userRepository; // 声明依赖 public void addUser(String name) { userRepository.save(name); } }
改进:UserService 不再负责创建 UserRepository,而是通过 Spring 容器注入依赖。如果需要更换 UserRepository 的实现,只需在配置中调整,无需修改 UserService 的代码。
什么是动态代理?(453/1759=25.8%)
动态代理是一种在运行时动态生成代理对象,并在代理对象中增强目标对象方法的技术。它被广泛用于 AOP(面向切面编程)、权限控制、日志记录等场景,使得程序更加灵活、可维护。动态代理可以通过 JDK 原生的 Proxy 机制或 CGLIB 方式实现。接下来我会讲述动态代理的实现方式和执行流程。
首先,JDK 动态代理基于接口,适用于代理实现了接口的对象,当使用 JDK 动态代理时,主要分为四步,
第一步是定义接口,由于动态代理是基于接口进行代理的,因此目标对象必须实现接口。
第二步是创建并实现 InvocationHandler 接口,并在 invoke 方法中定义增强逻辑。
第三步是生成代理对象,使用 Proxy.newProxyInstance 创建代理对象,代理对象内部会调用 invoke 方法。
第四步是调用代理方法,当调用代理对象的方法时,invoke 方法会被触发,执行增强逻辑,并最终调用目标方法。
其次,
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
神哥引路,稳稳起步!!早鸟特惠,仅剩177名额!晚了就涨到29.9了! 核心亮点: 1.数据驱动,精准高频:基于1759篇面经、24139道八股题,精准提炼真实高频八股。 2.科学记忆,高效掌握:融合科学记忆法和面试表达技巧,记得住,说得出。 3.提升思维,掌握财商:不仅可学习八股,更可教你变现,3个月赚不回购买价,全额退。 适宜人群: 在校生、社招求职者及自学者。