公司动态

技术面:Spring (bean的生命周期、创建方式、注入方式、作用域)

📅 2026/7/26 20:34:46
技术面:Spring (bean的生命周期、创建方式、注入方式、作用域)
技术面Spring (bean的生命周期、创建方式、注入方式、作用域)在Java企业级开发中Spring框架几乎是必问的技术栈。面试中Spring Bean的相关问题经常被用来考察候选人对框架核心的掌握程度。本文将用大量代码演示从实战角度深入解析Spring Bean的生命周期、创建方式、注入方式以及作用域。—## 一、Spring Bean 的生命周期Spring Bean的生命周期是面试中的高频考点。它描述了Bean从创建到销毁的完整过程。理解它有助于我们利用Spring提供的钩子进行自定义操作。### 1.1 生命周期流程图简化版1.实例化通过构造器或工厂方法创建Bean实例。2.属性赋值设置Bean的属性依赖注入。3.初始化调用init-method或实现InitializingBean接口。4.使用Bean就绪供应用程序调用。5.销毁容器关闭时调用destroy-method或实现DisposableBean接口。### 1.2 实战代码演示下面是一个完整的示例展示Bean生命周期中的关键点。javaimport org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.InitializingBean;public class UserBean implements InitializingBean, DisposableBean { private String name; public UserBean() { System.out.println(1. 实例化调用构造器 UserBean()); } public void setName(String name) { this.name name; System.out.println(2. 属性赋值设置 name name); } // 实现 InitializingBean 接口 Override public void afterPropertiesSet() throws Exception { System.out.println(3. 初始化回调afterPropertiesSet() 执行); if (name null) { name 默认用户; } } // 自定义初始化方法通过 Bean 的 initMethod 指定 public void customInit() { System.out.println(3.5 自定义初始化customInit() 执行); } // 业务方法 public void greet() { System.out.println(4. 使用BeanHello, name); } // 实现 DisposableBean 接口 Override public void destroy() throws Exception { System.out.println(5. 销毁回调destroy() 执行); } // 自定义销毁方法 public void customDestroy() { System.out.println(5.5 自定义销毁customDestroy() 执行); }}XML配置applicationContext.xmlxmlbean iduserBean classcom.example.UserBean init-methodcustomInit destroy-methodcustomDestroy property namename value张三//bean运行代码javaimport org.springframework.context.support.ClassPathXmlApplicationContext;public class BeanLifecycleDemo { public static void main(String[] args) { ClassPathXmlApplicationContext context new ClassPathXmlApplicationContext(applicationContext.xml); UserBean user (UserBean) context.getBean(userBean); user.greet(); context.close(); // 触发销毁 }}输出结果1. 实例化调用构造器 UserBean()2. 属性赋值设置 name 张三3. 初始化回调afterPropertiesSet() 执行3.5 自定义初始化customInit() 执行4. 使用BeanHello, 张三5. 销毁回调destroy() 执行5.5 自定义销毁customDestroy() 执行注意afterPropertiesSet()在属性赋值后、自定义初始化方法之前执行。如果同时使用接口和XML配置接口方法优先。—## 二、Bean 的创建方式Spring支持多种创建Bean的方式常见的有三种构造器、静态工厂和实例工厂。### 2.1 构造器方式最常用默认使用无参构造器或通过constructor-arg传参。xmlbean iduser classcom.example.User constructor-arg namename value李四/ constructor-arg nameage value25//bean### 2.2 静态工厂方法适用于不需要Spring管理工厂类实例的场景。javapublic class UserFactory { // 静态方法返回Bean public static User createUser() { User user new User(); user.setName(王五); user.setAge(30); return user; }}xmlbean iduserFromFactory classcom.example.UserFactory factory-methodcreateUser/### 2.3 实例工厂方法需要先创建工厂Bean再通过它创建目标Bean。javapublic class UserInstanceFactory { // 非静态方法 public User createUser() { User user new User(); user.setName(赵六); user.setAge(28); return user; }}// 配置bean idfactory classcom.example.UserInstanceFactory/bean iduserFromInstance factory-beanfactory factory-methodcreateUser/### 2.4 注解方式推荐现代Spring开发更倾向于使用注解如Component和Bean。javaComponentpublic class User { Value(张三) private String name; // getter/setter...}// 或在配置类中Configurationpublic class AppConfig { Bean public User user() { return new User(李四, 25); }}—## 三、依赖注入方式依赖注入DI是Spring的核心功能主要有三种方式属性注入、构造器注入和setter注入。### 3.1 属性注入Field Injection通过Autowired直接注入到字段上代码最简洁但不推荐用于生产环境因为难以单元测试。javaimport org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Component;Componentpublic class OrderService { Autowired private UserRepository userRepository; // 直接注入 public void process() { userRepository.save(new User()); }}### 3.2 构造器注入Constructor InjectionSpring官方推荐的方式保证依赖不可变且注入时对象已完成初始化。javaComponentpublic class OrderService { private final UserRepository userRepository; // Spring自动调用构造器注入依赖 Autowired public OrderService(UserRepository userRepository) { this.userRepository userRepository; } public void process() { userRepository.save(new User()); }}注意如果类只有一个构造器Autowired可以省略Spring 4.3。### 3.3 Setter注入通过setter方法注入适合可选依赖。javaComponentpublic class OrderService { private UserRepository userRepository; Autowired public void setUserRepository(UserRepository userRepository) { this.userRepository userRepository; } public void process() { userRepository.save(new User()); }}### 3.4 注入方式对比| 方式 | 优点 | 缺点 | 适用场景 ||------|------|------|----------|| 属性注入 | 代码简洁 | 难以测试依赖不明确 | 快速原型不推荐生产 || 构造器注入 | 依赖明确不可变 | 代码稍长 | 强制依赖推荐使用 || Setter注入 | 可选依赖 | 可变可能忘记调用 | 可选依赖或循环引用 |—## 四、Bean 的作用域作用域决定了Bean的存活范围和共享方式。Spring定义了5种作用域Web环境有3种额外作用域。### 4.1 常见作用域| 作用域 | 描述 | 适用场景 ||--------|------|----------|| singleton | 默认单例整个容器共享一个实例 | 无状态Bean如Service || prototype | 每次获取都创建新实例 | 有状态Bean如User || request | 每个HTTP请求一个实例Web环境 | 请求级别的数据 || session | 每个HTTP Session一个实例Web环境 | 用户会话数据 || application | 每个ServletContext一个实例Web环境 | 全局共享数据 |### 4.2 代码演示javaimport org.springframework.context.annotation.Scope;import org.springframework.stereotype.Component;ComponentScope(singleton) // 默认就是singleton可省略public class SingletonBean { private int count 0; public void increment() { count; System.out.println(Singleton count count); }}ComponentScope(prototype) // 每次获取新实例public class PrototypeBean { private int count 0; public void increment() { count; System.out.println(Prototype count count); }}测试代码javaimport org.springframework.context.ApplicationContext;import org.springframework.context.annotation.AnnotationConfigApplicationContext;public class ScopeDemo { public static void main(String[] args) { ApplicationContext context new AnnotationConfigApplicationContext(com.example); // 获取两次单例Bean SingletonBean s1 context.getBean(SingletonBean.class); SingletonBean s2 context.getBean(SingletonBean.class); s1.increment(); // 输出: Singleton count 1 s2.increment(); // 输出: Singleton count 2 (共享同一个实例) // 获取两次原型Bean PrototypeBean p1 context.getBean(PrototypeBean.class); PrototypeBean p2 context.getBean(PrototypeBean.class); p1.increment(); // 输出: Prototype count 1 p2.increment(); // 输出: Prototype count 1 (不同实例) }}### 4.3 作用域使用注意事项-singleton与prototype混用如果singleton Bean注入prototype Beanprototype Bean会被固化。解决方案使用Lookup注解或Provider。-Web作用域仅在Web应用如Spring MVC中生效需要配置RequestContextListener或EnableWebMvc。—## 总结本文从实战角度出发用具体代码演示了Spring Bean的四大核心概念1.生命周期实例化 → 属性赋值 → 初始化 → 使用 → 销毁提供了InitializingBean、DisposableBean接口以及init-method、destroy-method等钩子。2.创建方式构造器最常用、静态工厂、实例工厂以及注解方式Component、Bean。3.注入方式属性注入简洁但危险、构造器注入推荐、Setter注入可选依赖其中构造器注入是Spring官方推荐的最佳实践。4.作用域singleton单例默认、prototype原型、request、session、application选择合适的作用域可以提升性能和资源利用率。面试中不仅要记住概念更要能结合实际项目场景解释为什么选择某种方式。例如用构造器注入保证依赖不可变用prototype作用域处理有状态Bean等。希望本文的代码示例能帮助你在面试中脱颖而出。