第1章:Spring Bean生命周期概述
1.1 什么是Spring Bean生命周期?
定义:Spring Bean生命周期是指从Bean的创建、初始化、使用到销毁的完整过程,由Spring容器严格管理 。核心思想是Spring容器通过IoC(控制反转)和DI(依赖注入)机制,控制Bean的创建、配置和销毁,开发者可通过扩展点(如BeanPostProcessor
、Aware接口
)插入自定义逻辑。
Spring管理的Bean生命周期与普通Java对象有本质区别。普通Java对象由程序员直接new
创建,其生命周期完全由JVM垃圾回收机制管理,开发者无法精确控制初始化和销毁时机。而Spring容器管理的Bean,其生命周期的每个关键节点都有明确的控制机制,开发者可以指定初始化方法和销毁方法,或者通过实现特定接口来干预Bean的创建过程。
关键区别:Spring容器管理的Bean具有明确的创建和销毁阶段,且在这些阶段提供了多个扩展点,允许开发者在特定时机执行自定义逻辑,例如资源初始化、权限校验、日志记录等。
1.2 为什么需要了解Bean生命周期?
必要性:
- 在正确时机执行关键操作:如初始化数据库连接池、加载缓存、配置资源等,这些操作通常需要在Bean完全初始化后执行。
- 避免隐式错误:了解生命周期有助于避免在构造函数中访问未注入的依赖,防止
NullPointerException
。 - 理解扩展点机制:掌握BeanPostProcessor、Aware接口等扩展点的调用顺序,有助于正确编写自定义逻辑。
- 解决常见问题:如循环依赖、资源泄漏、初始化失败等问题,都需要基于对生命周期的理解来解决。
实际案例:
- 资源泄漏:如果未在
@PostConstruct
中关闭数据库连接,可能导致资源泄漏。 - 循环依赖:在单例Bean中使用
@Autowired
注入相互依赖的Bean时,Spring通过三级缓存机制解决循环依赖问题。 - 作用域管理:在Web应用中,request作用域的Bean需要在请求结束时销毁,而session作用域的Bean需要在会话结束时销毁。
1.3 Spring容器的角色
IoC容器:Spring通过BeanFactory
(基础容器)和ApplicationContext
(应用上下文,功能更丰富)管理Bean的生命周期。DI机制(依赖注入)是IoC的核心体现,它将对象的创建和依赖关系的管理交给Spring容器,而非由程序员显式控制。
容器类型对比:
容器类型 | 特点 | 适用场景 |
---|---|---|
BeanFactory | 轻量级,仅提供基础IoC功能 | 非Web环境,资源受限场景 |
ApplicationContext | 功能丰富,支持国际化、事件发布、AOP等 | Web应用,需要完整Spring功能的场景 |
源码片段:Spring容器的核心是AbstractApplicationContext
类,其refresh()
方法负责容器的完整初始化流程:
// AbstractApplicationContext.java
public void refresh() throws BeansException,恶性代码
总结:Spring容器通过分层抽象(BeanFactory、ApplicationContext)和核心类(如DefaultListableBeanFactory
)实现Bean生命周期管理,开发者可以通过扩展点(如BeanPostProcessor
)在特定时机插入自定义逻辑。
第2章:生命周期的核心阶段详解
2.1 实例化(Instantiation)
定义:Spring容器通过反射或工厂方法创建Bean的原始对象(未填充属性)。关键点包括:
- 支持多种实例化方式:
- 无参构造函数
- 带参构造函数
- 工厂方法(静态或实例方法)
- 作用域影响:
- 单例(Singleton)Bean在容器启动时实例化
- 原型(Prototype)Bean在每次调用
getBean()
时实例化 - Web作用域(Request/Session)Bean在请求或会话开始时实例化
代码示例:
// 使用无参构造函数实例化
@Component
public class UserService {public UserService() {System.out.println("1. 实例化UserService");}
}// 使用工厂方法实例化
@Component
public class UserRepository {public static UserRepository create() {System.out.println("1. 工厂方法创建UserRepository");return new UserRepository();}
}
源码解析:在AbstractAutowireCapableBeanFactory
类中,doCreateBean()
方法负责Bean的完整创建流程,其中createBeanInstance()
方法负责实例化:
// AbstractAutowireCapableBeanFactory.java
protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 确定实例化策略(无参构造、带参构造或工厂方法)if (mbd.getFactoryBeanName() != null) {// 工厂方法实例化return EagerInitializationPolicy.eagerlyInitializeBean(mbd, beanName, args, getBeanFactory());}// 无参构造或带参构造实例化return BeanUtils.instantiateClass(mbd ResolvedBeanClass, args, getBeanFactory().getBeanClassLoader());
}
面试考点:
- 构造函数注入与字段注入的区别?
- 为什么单例Bean在容器启动时实例化?
- 如何自定义Bean的实例化方式?
2.2 属性赋值(Populate Properties)
定义:为Bean的字段或方法注入依赖对象(如@Autowired
、@Value
)。关键点包括:
- 依赖注入方式:
- 构造器注入(推荐,避免循环依赖)
- 字段注入(通过
@Autowired
注解) - Setter方法注入(通过
@Autowired
或XML配置)
- 属性赋值时机:
- 在实例化完成后、初始化方法执行前
- 对于循环依赖,通过三级缓存机制提前暴露半成品Bean
- 支持嵌套Bean的递归注入:Spring能够处理Bean之间的复杂依赖关系
代码示例:
// 使用字段注入
@Component
public class UserRepository {@Value("${database.url}")private String url;
}// 使用Setter方法注入
@Component
public class UserService {private UserRepository userRepository;@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;System.out.println("2. 字段注入UserRepository");}
}
源码解析:在AbstractAutowireCapableBeanFactory
类中,populateBean()
方法负责属性赋值:
// AbstractAutowireCapableBeanFactory.java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {// 解析属性值并注入PropertyValues pvs = (mbd.getResolvedLazyInit() ? new LazyPropertyValues() : mbd.getPropertyValues());applyPropertyValues(beanName, mbd, bw, pvs);// 处理循环依赖if (mbd.isSingleton() && this beanName != null && !mbd.isLazyInit()) {// 将半成品Bean放入三级缓存Object earlySingleton = getEarlySingletonReference(beanName, mbd, bw);// 将半成品Bean放入二级缓存this.earlySingletonObjects.put IfAbsent (beanName, earlySingleton);// 将半成品Bean放入三级缓存this singletonFactories.put IfAbsent (beanName, new ObjectFactory () {@Overridepublic Object.getObject() {return getSingleton beanName;}});}
}
常见问题:
- 循环依赖:当两个Bean互相依赖时,Spring如何解决?
- 依赖缺失:如果依赖的Bean尚未实例化,会抛出
NoSuchBeanDefinitionException
。 - 属性赋值失败:如果属性类型不匹配或值无法解析,会抛出
BeanInitializationException
。
2.3 初始化前处理(BeanPostProcessor Before)
定义:在Bean初始化方法(如@PostConstruct
、InitializingBean.afterPropertiesSet()
或自定义init-method
)之前,Spring容器调用所有BeanPostProcessor
的postProcessBeforeInitialization()
方法,允许开发者修改Bean属性或状态 。
关键点:
- 全局性:对容器中的所有Bean生效
- 执行顺序:由
BeanPostProcessor
的实现类决定,可通过实现PriorityOrdered
或Ordered
接口控制执行顺序 - 可修改Bean:返回值可以替换原始Bean(如AOP代理)
- 可阻断初始化:通过返回
null
阻断后续初始化流程
代码示例:
// 自定义BeanPostProcessor
@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("3.1 [" + beanName + "] 初始化前处理");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {System.out.println("3.2 [" + beanName + "] 初始化后处理");return bean;}@Overridepublic int gettingOrder() {return HIGHEST_PRECEDENCE + 1; // 最高优先级}
}
源码解析:在AbstractAutowireCapableBeanFactory
类中,initializeBean()
方法负责初始化流程,其中包含对BeanPostProcessor
的调用:
// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {// 调用Aware接口if (mbd.getSingleton() != null) {// 调用Aware接口方法applyAwareInterfaces(bean, mbd);}// 调用BeanPostProcessor的postProcessBeforeInitializationboolean continueWithInitialization = true;if (mbd postProcessed) {continueWithInitialization = applyBeanPostProcessorsBeforeInitialization (bean, beanName);}if (continueWithInitialization) {// 执行初始化方法invokingInitMethods (bean, beanName, mbd);}// 调用BeanPostProcessor的postProcessAfterInitializationreturn applyBeanPostProcessorsAfterInitialization (bean, beanName);
}
面试考点:
- BeanPostProcessor的执行顺序?
- postProcessBeforeInitialization和postProcessAfterInitialization的区别?
- BeanPostProcessor如何实现AOP代理?
2.4 初始化(Initialization)
定义:执行Bean的初始化方法,包括以下三种方式:
注解方式:
@PostConstruct
:标注在方法上,方法执行在属性赋值之后、BeanPostProcessor的postProcessAfterInitialization()
之前@PreDestroy
:标注在方法上,方法执行在Bean销毁之前
接口方式:
InitializingBean
:实现afterPropertiesSet()
方法DisposableBean
:实现destroy()
方法
配置方式:
- XML配置中的
init-method
属性 - Java配置中的
@Bean(initMethod="...")
- XML配置中的
关键点:
- 执行顺序:
@PostConstruct
>InitializingBean
>init-method
- 单例Bean:初始化在容器启动时完成
- 非单例Bean:初始化在每次获取Bean时完成
代码示例:
// 使用多种初始化方式
@Component
public class UserService implements InitializingBean {@Value("${system.version}")private String version;@PostConstructpublic void start() {System.out.println("4.1 @PostConstruct方法执行");}@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("4.2 InitializingBean接口方法执行");}@Bean(initMethod = "init")public void init() {System.out.println("4.3 init-method配置方法执行");}
}
源码解析:在AbstractAutowireCapableBeanFactory
类中,invokingInitMethods()
方法负责执行初始化方法:
// AbstractAutowireCapableBeanFactory.java
private void invokingInitMethods(String beanName, Object bean, RootBeanDefinition mbd) {// 调用初始化方法if (mbd.getInitMethod() != null) {// 调用自定义init-methodinvoker invoker = new invoker (mbd.getInitMethod(), bean.getClass());invoker invoker (bean);}// 调用InitializingBean接口方法if (bean instanceof initializingBean) {((initializingBean) bean).afterPropertiesSet();}// 调用@PostConstruct注解方法if (mbd.getPostConstructMethod() != null) {invoker invoker = new invoker (mbd.getPostConstructMethod(), bean.getClass());invoker invoker (bean);}
}
常见问题:
- 初始化失败:如果初始化方法抛出异常,Bean将无法使用
- 循环依赖:在初始化阶段处理循环依赖
- 作用域限制:非单例Bean的初始化方法在每次获取Bean时执行
2.5 初始化后处理(BeanPostProcessor After)
定义:在Bean初始化方法执行完毕后,Spring容器调用所有BeanPostProcessor
的postProcessAfterInitialization()
方法,允许开发者对Bean进行最终修改或增强 。
关键点:
- AOP代理生成:Spring AOP通过
postProcessAfterInitialization()
方法为Bean生成代理对象 - 全局性:对容器中的所有Bean生效
- 可修改Bean:返回值可以替换原始Bean(如动态代理)
- 可阻断使用:通过返回
null
阻断Bean的使用
代码示例:
// AOP代理示例
@Component
public class AuditProxyPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {if (bean instanceof UserService) {// 创建代理对象return Proxy.newProxyInstance(bean.getClass().getClassLoader(),bean.getClass().getInterfaces(),(proxy, method, args) -> {System.out.println("5.1 [" + beanName + "] AOP代理方法执行");return method.invoke bean, args;});}return bean;}
}
源码解析:在AbstractAutowireCapableBeanFactory
类中,applyBeanPostProcessorsAfterInitialization()
方法负责调用BeanPostProcessor
的postProcessAfterInitialization()
:
// AbstractAutowireCapableBeanFactory.java
protected Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException {// 遍历所有BeanPostProcessorfor (BeanPostProcessor processor : getBeanPostProcessors()) {// 调用postProcessAfterInitialization方法Object current = processor.postProcessAfterInitialization(existingBean, beanName);if (current == null) {return existingBean;}existingBean = current;}return existingBean;
}
面试考点:
- BeanPostProcessor的执行顺序?
- postProcessBeforeInitialization和postProcessAfterInitialization的区别?
- 如何通过BeanPostProcessor实现AOP代理?
2.6 注册销毁回调(Destruction Callbacks)
定义:在Bean初始化完成后,Spring容器注册Bean的销毁回调方法,包括以下三种方式:
注解方式:
@PreDestroy
:标注在方法上,方法执行在Bean销毁之前
接口方式:
DisposableBean
:实现destroy()
方法
配置方式:
- XML配置中的
destroy-method
属性 - Java配置中的
@Bean(destroyMethod="...")
- XML配置中的
关键点:
- 单例Bean:销毁回调在容器关闭时触发
- 非单例Bean:销毁回调通常由开发者手动触发
- 执行顺序:
@PreDestroy
>DisposableBean
>destroy-method
代码示例:
// 使用多种销毁方式
@Component
public class DatabasePool implements DisposableBean {@PreDestroypublic void close() {System.out.println("6.1 @PreDestroy方法执行");}@Overridepublic void destroy() throws Exception {System.out.println("6.2 DisposableBean接口方法执行");}@Bean(destroyMethod = "shutdown")public void shutdown() {System.out.println("6.3 destroy-method配置方法执行");}
}
源码解析:在AbstractBeanFactory
类中,registerDestructionCallback()
方法负责注册销毁回调:
// AbstractBeanFactory.java
public void registerDestructionCallback(String beanName, Runnable callback) {// 将销毁回调放入销毁回调Mapthis.destructionCallbacks.put IfAbsent (beanName, callback);
}// AbstractApplicationContext.java
public void close() throws恶性代码 {// 遍历所有Bean并执行销毁方法for (String beanName : getBeanNamesForType(DisposableBean.class)) {DisposableBean disposableBean = (DisposableBean) getBean beanName;disposableBean.destroy();}// 执行自定义destroy-methodfor (String beanName : getBeanNamesForType(Object.class)) {BeanDefinition beanDefinition = getBeanDefinition beanName;if (beanDefinition.getDestroyMethod() != null) {invoker invoker = new invoker (beanDefinition.getDestroyMethod(), getBeanClass beanName);invoker invoker (getBean beanName);}}// 执行@PreDestroy注解方法for (String beanName : getBeanNamesForType(Object.class)) {if (isPreDestroyMethod beanName)) {invoker invoker = new invoker (getPreDestroyMethod beanName), getBeanClass beanName);invoker invoker (getBean beanName);}}
}
常见问题:
- 资源泄漏:如果未正确注册销毁回调,可能导致资源泄漏
- 作用域限制:非单例Bean的销毁回调需要手动触发
- 执行顺序:销毁方法的执行顺序与创建顺序相反
2.7 销毁(Destruction)
定义:当Spring容器关闭时(如调用close()
方法或服务器停止),容器调用已注册的销毁方法,释放Bean占用的资源。
关键点:
- 单例Bean:销毁在容器关闭时自动执行
- 非单例Bean:销毁需要手动触发或通过作用域代理实现
- 执行顺序:与创建顺序相反,先创建的Bean后销毁
代码示例:
// 手动关闭容器
public class App {public static void main(String[] args) {// 创建Spring容器ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");// 获取Bean并使用UserService userService = context.getBean(UserService.class);userService.saveUser();// 关闭容器,触发销毁方法context.close();}
}
源码解析:在AbstractApplicationContext
类中,close()
方法负责容器关闭和Bean销毁:
// AbstractApplicationContext.java
public void close() throws恶性代码 {// 执行销毁回调executeDestructionCallbacks();// 销毁单例BeandestroySingletons();// 销毁其他资源doClose();
}// 执行销毁回调
private void executeDestructionCallbacks() {// 遍历所有Bean并执行销毁方法for (String beanName : getBeanNamesForType(Object.class)) {// 执行销毁方法destroyBean beanName, getBean beanName);}
}
面试考点:
- 单例Bean和原型Bean的销毁机制有何不同?
- @PreDestroy和 disposableBean接口的执行顺序?
- 如何确保非单例Bean的销毁方法被调用?
第3章:生命周期的扩展点与自定义
3.1 BeanPostProcessor的深度解析
定义:BeanPostProcessor
是Spring框架提供的一个扩展接口,允许开发者在Bean初始化的前后插入自定义逻辑 。
接口定义:
// BeanPostProcessor.java
public interface BeanPostProcessor {@Nullabledefault Object postProcessBeforeInitialization(Object bean, String beanName) {return bean;}@Nullabledefault Object postProcessAfterInitialization(Object bean, String beanName) {return bean;}
}
关键子接口:
- InstantiationAwareBeanPostProcessor:允许在Bean实例化前后进行干预
- InitializationAwareBeanPostProcessor:允许在Bean初始化前后进行干预
- DestructionAwareBeanPostProcessor:允许在Bean销毁前后进行干预
执行顺序:Spring容器在调用BeanPostProcessor
方法时,遵循以下顺序:
- 实现
PriorityOrdered
接口的处理器(按优先级排序) - 实现
Ordered
接口的处理器(按顺序排序) - 未实现排序接口的处理器(按注册顺序排序)
代码示例:自定义BeanPostProcessor实现日志增强
// 自定义BeanPostProcessor
@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor, PriorityOrdered {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) {System.out.println("[" + beanName + "] 初始化前处理");return bean;}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) {System.out.println("[" + beanName + "] 初始化后处理");return bean;}@Overridepublic int gettingOrder() {return HIGHEST_PRECEDENCE + 1; // 最高优先级}
}
源码解析:在PostProcessorRegistrationDelegate
类中,sortPostProcessors()
方法负责排序BeanPostProcessor:
// PostProcessorRegistrationDelegate.java
private static List<BeanPostProcessor> sortPostProcessors(List<BeanPostProcessor> postProcessors) {// 创建排序器BeanPostProcessorSorter处理器排序器 = new BeanPostProcessorSorter();// 按优先级排序处理器排序器.sortByPriority postProcessors);// 按顺序排序处理器排序器.sortByOrder postProcessors);// 返回排序后的列表return处理器排序器.getSortedPostProcessors();
}
应用场景:
- AOP代理:通过
postProcessAfterInitialization()
为Bean生成代理对象 - 日志记录:在Bean方法调用前后添加日志
- 性能监控:在Bean方法调用前后记录执行时间
- 安全控制:在Bean方法调用前进行权限校验
面试考点:
- BeanPostProcessor的执行顺序?
- postProcessBeforeInitialization和postProcessAfterInitialization的区别?
- 如何通过BeanPostProcessor实现AOP代理?
3.2 BeanFactoryPostProcessor的作用与使用场景
定义:BeanFactoryPostProcessor
是Spring框架提供的一个扩展接口,允许开发者在Bean实例化之前修改Bean的定义(BeanDefinition) 。
接口定义:
// BeanFactoryPostProcessor.java
public interface BeanFactoryPostProcessor {void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws恶性代码;
}
关键子接口:
- BeanDefinitionRegistryPostProcessor:允许在Bean定义加载阶段修改BeanDefinition
执行时机:在Bean定义加载完成后、Bean实例化之前执行 ,与BeanPostProcessor的执行阶段不同。
代码示例:修改Bean的属性值
// 自定义BeanFactoryPostProcessor
@Component
public class PropertyModifyingPostProcessor implements BeanFactoryPostProcessor {@Overridepublic void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {// 获取特定Bean的定义BeanDefinition beanDefinition = beanFactory.getBeanDefinition("userService");// 修改Bean的属性值beanDefinition.setPropertyValues(new PropertyValues(new PropertyValue("version", "6.0.11")));}
}
源码解析:在AbstractApplicationContext
类中,refresh()
方法负责调用BeanFactoryPostProcessor:
// AbstractApplicationContext.java
public void refresh() throws恶性代码 {// ...// 执行BeanFactoryPostProcessorinvokerBeanFactoryPostProcessors getBeanFactory());// ...// 执行BeanPostProcessorinvokerBeanPostProcessors getBeanFactory());// ...
}
应用场景:
- 动态修改Bean定义:如修改Bean的属性值、作用域等
- 扫描特定注解:如自动扫描并注册MyBatis的Mapper接口
- 条件化装配:根据环境条件决定是否注册某些Bean
面试考点:
- BeanFactoryPostProcessor和BeanPostProcessor的区别?
- BeanDefinitionRegistryPostProcessor的作用?
- 如何通过BeanFactoryPostProcessor修改Bean的属性?
3.3 @PostConstruct与@PreDestroy的底层实现
定义:@PostConstruct
和@PreDestroy
是Spring框架提供的注解,用于在Bean的初始化和销毁阶段执行特定方法 。
注解定义:
// PostConstruct.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PostConstruct {
}// PreDestroy.java
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PreDestroy {
}
底层实现:Spring通过CommonAnnotationBeanPostProcessor
处理这些注解 :
// CommonAnnotationBeanPostProcessor.java
public class CommonAnnotationBeanPostProcessor extends AbstractBeanPostProcessorimplements BeanNameAware, BeanFactoryAware, InitializeBean, DisposableBean {// 处理PostConstruct注解private void processPostConstructMethods(Object bean) {// 获取所有PostConstruct注解方法Method[] methods = getPostConstructMethods bean.getClass());for (Method method : methods) {// 执行方法invoker method.invoke bean);}}// 处理PreDestroy注解private void processPreDestroyMethods(Object bean) {// 获取所有PreDestroy注解方法Method[] methods = getPreDestroyMethods bean.getClass());for (Method method : methods) {// 注册销毁回调registerDestructionCallback getBeanName(), () -> {method.invoke bean);});}}
}
执行顺序:在Bean生命周期中,@PostConstruct
方法的执行顺序在InitializingBean.afterPropertiesSet()
之后、自定义init-method
之前。
代码示例:
// 使用@PostConstruct和@PreDestroy
@Component
public class CacheService {@PostConstructpublic void initCache() {System.out.println("缓存初始化完成");}@PreDestroypublic void clearCache() {System.out.println("缓存清理完成");}
}
面试考点:
- @PostConstruct和InitializingBean接口的执行顺序?
- @PreDestroy和 disposableBean接口的执行顺序?
- @PostConstruct和@PreDestroy在Spring 6.x中的行为有何变化?
3.4 InitializingBean与DisposableBean接口的适用性对比
对比表格:
特性 | InitializingBean接口 | disposableBean接口 | @PostConstruct注解 | @PreDestroy注解 | init-method/destroy-method配置 |
---|---|---|---|---|---|
实现方式 | 实现接口 | 实现接口 | 使用注解 | 使用注解 | 在配置文件中指定 |
执行顺序 | 在属性赋值之后、BeanPostProcessor之前 | 在BeanPostProcessor之后 | 在BeanPostProcessor之后 | 在BeanPostProcessor之前 | 在BeanPostProcessor之后 |
适用场景 | 需要访问其他Bean的场景 | 需要访问其他Bean的场景 | 简单初始化逻辑 | 简单销毁逻辑 | 需要明确指定方法名的场景 |
灵活性 | 有限,只能使用固定方法名 | 有限,只能使用固定方法名 | 高,可以标注在任何方法上 | 高,可以标注在任何方法上 | 中等,需要在配置中指定方法名 |
代码侵入性 | 高,需要实现接口 | 高,需要实现接口 | 低,只需要添加注解 | 低,只需要添加注解 | 低,只需要在配置中指定方法名 |
源码解析:在AbstractAutowireCapableBeanFactory
类中,initializeBean()
方法负责执行初始化方法:
// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {// ...// 调用Aware接口applyAwareInterfaces(bean, mbd);// 调用BeanPostProcessor的postProcessBeforeInitializationapplyBeanPostProcessorsBeforeInitialization (bean, beanName);// 执行初始化方法invokingInitMethods (bean, beanName, mbd);// 调用BeanPostProcessor的postProcessAfterInitializationreturn applyBeanPostProcessorsAfterInitialization (bean, beanName);
}
最佳实践:
- 优先使用注解:如
@PostConstruct
和@PreDestroy
,因为它们代码侵入性低 - 避免循环依赖:在初始化方法中不要依赖其他正在初始化的Bean
- 处理异常:在初始化和销毁方法中捕获并处理异常
面试考点:
- @PostConstruct和InitializingBean接口的执行顺序?
- @PreDestroy和 disposableBean接口的执行顺序?
- 如何解决循环依赖问题?
3.5 自定义初始化/销毁方法(XML与注解配置)
XML配置方式:
<!-- spring.xml -->
<bean id="databasePool" class="com.example.DatabasePool"init-method="init" destroy-method="destroy"><property name="url" value="${database.url}"/><property name="username" value="${database.username}"/><property name="password" value="${database.password}"/>
</bean>
注解配置方式:
// 使用@Bean注解指定初始化和销毁方法
@Configuration
public class AppConfig {@Bean(initMethod = "init", destroyMethod = "destroy")public DatabasePool databasePool() {return new DatabasePool();}
}
代码示例:自定义初始化和销毁方法
// 自定义Bean
public class DatabasePool {private String url;private String username;private String password;// 初始化方法public void init() {System.out.println("数据库连接池初始化完成");}// 销毁方法public void destroy() {System.out.println("数据库连接池清理完成");}// Getter和Setter方法public String getUrl() {return url;}public void setUrl(String url) {this.url = url;}public String得到用户名() {return username;}public void设置用户名(String username) {this.username = username;}public String得到密码() {return password;}public void设置密码(String password) {this.password = password;}
}
源码解析:在AbstractBeanFactory
类中,registerBeanDefinition()
方法负责注册Bean的定义,包括初始化和销毁方法:
// AbstractBeanFactory.java
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws恶性代码 {// 检查Bean名称是否重复checkBeanName beanName);// 检查Bean是否已经注册check是否存在BeanDefinition beanName);// 注册BeanDefinitionthis beanDefinitionMap.put beanName, beanDefinition);// 如果是单例Bean,注册销毁回调if (beanDefinition.getScope().equals(Scope.SCOPE-singleton)) {// 注册销毁回调registerDestructionCallback beanName, () -> {if (beanDefinition.getDestroyMethod() != null) {invoker invoker = new invoker (beanDefinition.getDestroyMethod(), getBeanClass beanName);invoker invoker (getBean beanName);}});}
}
应用场景:
- 资源初始化:如数据库连接池、文件句柄等
- 状态加载:如从文件或数据库加载配置
- 监控配置:如初始化监控系统
面试考点:
- XML配置和注解配置销毁方法的区别?
- 如何确保自定义销毁方法被调用?
- 单例Bean和原型Bean的销毁方法执行条件?
第4章:Bean作用域与生命周期管理
4.1 单例(Singleton)作用域的生命周期控制
定义:单例作用域是Spring的默认作用域,每个Spring容器中只会创建一个Bean实例,该实例在整个应用程序生命周期内共享。
关键点:
- 实例化时机:容器启动时或首次获取Bean时(取决于是否延迟初始化)
- 属性赋值时机:实例化后立即进行
- 初始化时机:属性赋值完成后立即进行
- 销毁时机:容器关闭时自动执行销毁方法
代码示例:
// 单例Bean配置
@Component
public class UserService {@Autowiredprivate UserRepository userRepository;@PostConstructpublic void init() {System.out.println("单例Bean初始化完成");}@PreDestroypublic void destroy() {System.out.println("单例Bean销毁完成");}
}
源码解析:在DefaultSingletonBeanRegistry
类中,get Singleton()
方法负责获取单例Bean:
// DefaultSingletonBeanRegistry.java
public Object get Singleton(String beanName, boolean allowEarlyReference) {// 从一级缓存获取Object singletonObject = this singletonObjects.get beanName;if (singletonObject == null) {// 从二级缓存获取singletonObject = this earlySingletonObjects.get beanName;if (singletonObject == null && allowEarlyReference) {// 从三级缓存获取ObjectFactory<?> singletonFactory = (ObjectFactory<?>) this singletonFactories.get beanName;if (singletonFactory != null) {// 创建半成品BeansingletonObject = singletonFactory.getObject();// 将半成品Bean放入二级缓存this.earlySingletonObjects.put beanName, singletonObject;// 将半成品Bean放入三级缓存this singletonFactories.remove beanName);}}}return singletonObject;
}
面试考点:
- 单例Bean的销毁时机?
- 如何确保单例Bean的线程安全性?
- 单例Bean的循环依赖如何解决?
4.2 原型(Prototype)作用域的生命周期限制
定义:原型作用域表示每次请求Bean时,Spring容器都会创建一个新的Bean实例,这些实例之间是完全独立的。
关键点:
- 实例化时机:每次调用
getBean()
方法时 - 属性赋值时机:实例化后立即进行
- 初始化时机:属性赋值完成后立即进行
- 销毁时机:Spring容器不管理,需要手动触发销毁方法
代码示例:
// 原型Bean配置
@Component
@Scope("prototype")
public class prototypedBean {@PostConstructpublic void init() {System.out.println("原型Bean初始化完成");}@PreDestroypublic void destroy() {System.out.println("原型Bean销毁完成");}
}
源码解析:在AbstractBeanFactory
类中,getBean()
方法负责获取Bean实例:
// AbstractBeanFactory.java
public <T> T getBean(String name, Class<T> requiredType) {// 如果是原型Bean,直接创建新实例if (getBeanDefinition(name).getScope().equals(Scope.SCOPE-prototype)) {return createBean(name, getBeanDefinition(name), null);}// 否则,获取单例Beanreturn (T) getSingleton(name);
}
销毁方法触发方式:
- 手动调用:在使用完原型Bean后,手动调用其销毁方法
- 作用域代理:通过
@Scope(proxyMode=TargetClass)
启用代理,使原型Bean支持销毁方法 - 第三方工具:如使用对象池管理原型Bean,由对象池自动触发销毁
面试考点:
- 原型Bean的销毁机制?
- 如何确保原型Bean的销毁方法被调用?
- 原型Bean和单例Bean的循环依赖如何解决?
4.3 Web作用域(Request/Session)的特殊处理
定义:Web作用域是Spring为Web应用提供的特殊作用域,包括request、session和global session。
关键点:
- request作用域:每个HTTP请求创建一个Bean实例,请求结束后自动销毁
- session作用域:每个HTTP会话创建一个Bean实例,会话过期后自动销毁
- global session作用域:仅适用于Portlet应用,基于全局会话创建Bean实例
配置方式:在Web应用中,需要配置相应的监听器或过滤器来支持Web作用域 :
<!-- web.xml -->
< listener >< listener-class > org.springframework.web.context.request.RequestContextListener </ listener-class >
</ listener >
< listener >< listener-class > org.springframework.web.context.session.SessionContextListener </ listener-class >
</ listener >
代码示例:request作用域Bean
// request作用域Bean
@Component
@Scope("request")
public class RequestScopeBean {@PostConstructpublic void init() {System.out.println("request作用域Bean初始化完成");}@PreDestroypublic void destroy() {System.out.println("request作用域Bean销毁完成");}
}
源码解析:在RequestScope
类中,get()
方法负责获取request作用域Bean:
// RequestScope.java
public Object get(String name, ObjectFactory<?> objectFactory) {// 获取当前HTTP请求RequestAttributes attributes = RequestContextHolder.currentRequestAttributes();// 从请求属性中获取BeanObject scopedObject = attributes.getAttribute(name, getScope());if (scopedObject == null) {// 创建新BeanscopedObject = objectFactory.getObject();// 将Bean放入请求属性attributes.setAttribute(name, scopedObject, getScope());}return scopedObject;
}
销毁机制:
- request作用域:通过
RequestContextListener
监听HTTP请求结束,自动销毁Bean - session作用域:通过
SessionContextListener
监听HTTP会话过期,自动销毁Bean
面试考点:
- Web作用域Bean的销毁机制?
- 如何确保Web作用域Bean的销毁方法被调用?
- request作用域和session作用域的区别?
第5章:源码级解析与常见问题
5.1 核心类与方法(BeanDefinition、BeanFactory等)
BeanDefinition:Spring框架中表示Bean配置的元数据,包含Bean的类名、属性值、依赖关系等信息 。
关键类:
- RootBeanDefinition:表示一个完整的Bean定义,包含所有配置信息
- BeanDefinitionReader:负责读取Bean定义的配置文件或注解
- BeanDefinitionRegistry:管理Bean定义的注册表,允许动态注册和修改Bean定义
BeanFactory:Spring的IoC容器接口,负责管理Bean的生命周期 。
关键类:
- DefaultListableBeanFactory:Spring的默认BeanFactory实现,提供了完整的Bean管理功能
- AbstractAutowireCapableBeanFactory:负责Bean的实例化、属性赋值和初始化的抽象类
- AbstractApplicationContext:Spring的应用上下文实现,提供了完整的容器管理功能
源码解析:在AbstractAutowireCapableBeanFactory
类中,doCreateBean()
方法负责Bean的完整创建流程:
// AbstractAutowireCapableBeanFactory.java
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {// 实例化BeanBeanWrapper instanceWrapper = createBeanInstance(beanName, mbd, args);Object bean = instanceWrapper.getWrappedInstance();// 属性赋值populateBean(beanName, mbd, instanceWrapper);// 初始化exposedObject = initializeBean(beanName, exposedObject, mbd);// 注册销毁回调registerDestructionCallback(beanName, () -> {if (exposedObject instanceof DisposableBean) {((DisposableBean) exposedObject).destroy();}if (mbd.getDestroyMethod() != null) {invoker invoker = new invoker (mbd.getDestroyMethod(), exposedObject.getClass());invoker invoker (exposedObject);}});return exposedObject;
}
面试考点:
- BeanDefinition的作用?
- BeanFactory和ApplicationContext的区别?
- doCreateBean()方法的执行流程?
5.2 循环依赖的解决机制与生命周期影响
定义:循环依赖是指两个或多个Bean相互依赖形成闭环的情况,是Spring中一个经典问题 。
解决机制:Spring通过三级缓存(singletonObjects
、earlySingletonObjects
、singletonFactories
)解决循环依赖问题。
三级缓存作用:
- singletonObjects(一级缓存):存储完全初始化的单例Bean
- earlySingletonObjects(二级缓存):存储提前暴露的半成品Bean(已完成实例化但未完成初始化)
- singletonFactories(三级缓存):存储Bean工厂,用于生成早期Bean引用
源码解析:在AbstractAutowireCapableBeanFactory
类中,getEarlyBeanReference()
方法负责处理循环依赖:
// AbstractAutowireCapableBeanFactory.java
protected Object getEarlyBeanReference(String beanName, RootBeanDefinition mbd, BeanWrapper instanceWrapper) {// 获取半成品BeanObject bean = instanceWrapper.getWrappedInstance();// 如果需要AOP代理if (mbd.isProxy()) {// 创建代理对象bean = getAopProxy(mbd, instanceWrapper, beanName).getProxy();}// 将半成品Bean放入二级缓存this.earlySingletonObjects.put IfAbsent (beanName, bean);// 将半成品Bean放入三级缓存this singletonFactories.put IfAbsent (beanName, new ObjectFactory () {@Overridepublic Object getObject() {return getSingleton beanName;}});return bean;
}
生命周期影响:
- 实例化阶段:提前将半成品Bean放入三级缓存
- 属性赋值阶段:通过三级缓存获取半成品Bean引用
- 初始化阶段:延迟执行初始化方法,直到所有依赖注入完成
面试考点:
- Spring如何解决循环依赖问题?
- 三级缓存的具体作用?
- 构造器注入的循环依赖能否解决?
5.3 资源泄漏的排查与解决(如未关闭数据库连接)
定义:资源泄漏是指Bean在销毁时未正确释放资源,导致资源(如数据库连接、文件句柄等)无法回收。
常见场景:
- 数据库连接泄漏:未在
@PreDestroy
中关闭数据库连接 - 文件句柄泄漏:未在
@PreDestroy
中关闭文件流 - 网络连接泄漏:未在
@PreDestroy
中关闭网络连接
排查工具:
- YourKit Java Profiler:实时监控内存使用情况,创建多个堆快照进行对比分析
- Eclipse Memory Analyzer (MAT):分析堆转储文件,找出未释放的资源
- lsof命令:检查进程打开的文件句柄数
解决方案:
- 确保销毁方法被调用:对于单例Bean,确保容器正常关闭;对于原型Bean,手动调用销毁方法或启用作用域代理
- 使用try-with-resources:确保资源在使用后自动关闭
- 实现 DisposableBean接口:在
destroy()
方法中释放资源 - 使用@PreDestroy注解:在方法上添加注解,确保资源释放
代码示例:资源泄漏修复
// 修复前:资源未关闭
@Component
public class DatabaseService {private Connection connection;@PostConstructpublic void init() {try {connection = dataSource.getConnection();} catch (SQLException e) {e.printStackTrace();}}@PreDestroypublic void destroy() {if (connection != null) {try {connection.close();} catch (SQLException e) {e.printStackTrace();}}}
}
面试考点:
- 如何排查资源泄漏?
- 如何确保资源在Bean销毁时释放?
- 单例Bean和原型Bean的资源管理有何不同?
5.4 初始化失败的调试技巧(日志分析与断点调试)
定义:初始化失败是指Bean在初始化过程中抛出异常,导致Bean无法使用。
常见原因:
- 依赖缺失:依赖的Bean尚未创建
- 属性值错误:属性值无法解析或类型不匹配
- 循环依赖:两个Bean互相依赖,无法完成初始化
- 配置错误:XML或注解配置错误
- 资源访问失败:如无法连接数据库
调试技巧:
- 日志分析:启用Spring的DEBUG级别日志,查看Bean初始化的详细过程
- 断点调试:在IDE中设置断点,跟踪Bean初始化的执行流程
- 异常堆栈分析:查看抛出的异常信息,定位具体问题
- 使用@DependsOn:明确指定Bean的依赖顺序
- 使用@Lazy:延迟初始化Bean,避免循环依赖
源码解析:在AbstractAutowireCapableBeanFactory
类中,initializeBean()
方法负责执行初始化方法,如果抛出异常,会记录日志并抛出BeanInitializationException
:
// AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(String beanName, Object bean, RootBeanDefinition mbd) {// ...try {// 执行初始化方法invokingInitMethods (bean, beanName, mbd);} catch (恶性代码 ex) {// 记录异常String msg = "Initialization of bean failed";throw new恶性代码 (msg, ex);}// ...
}
面试考点:
- 如何调试Bean初始化失败的问题?
- 如何查看Spring容器的初始化日志?
- 如何解决BeanCurrentlyInCreationException异常?
第6章:实际开发中的最佳实践
6.1 如何选择初始化/销毁方法的实现方式
选择建议:
- 优先使用注解:如
@PostConstruct
和@PreDestroy
,因为它们代码侵入性低 - 避免实现接口:如
InitializingBean
和DisposableBean
,因为它们代码侵入性高 - 慎用init-method/destroy-method:仅在无法使用注解时使用
适用场景:
- 注解方式:简单初始化逻辑,如加载配置、初始化资源等
- 接口方式:需要访问其他Bean的场景,如依赖注入后的复杂初始化
- 配置方式:需要明确指定方法名的场景,如第三方库的Bean
代码示例:不同方式的使用场景
// 注解方式:简单初始化
@Component
public class CacheService {@PostConstructpublic void initCache() {System.out.println("缓存初始化完成");}@PreDestroypublic void clearCache() {System.out.println("缓存清理完成");}
}// 接口方式:需要访问其他Bean
@Component
public class UserService implements InitializingBean, DisposableBean {@Autowiredprivate UserRepository userRepository;@Overridepublic void afterPropertiesSet() throws恶性代码 {// 使用其他BeanuserRepository.loadUsers();System.out.println("UserService初始化完成");}@Overridepublic void destroy() throws恶性代码 {// 使用其他BeanuserRepository.close();System.out.println("UserService销毁完成");}
}// 配置方式:第三方库的Bean
@Configuration
public class AppConfig {@Bean(initMethod = "init", destroyMethod = "destroy")public ThirdPartyService thirdPartyService() {return new ThirdPartyService();}
}
面试考点:
- @PostConstruct和InitializingBean接口的执行顺序?
- @PreDestroy和 disposableBean接口的执行顺序?
- 如何解决循环依赖问题?
6.2 避免在构造函数中访问未注入的依赖
问题描述:在构造函数中访问未注入的依赖会导致NullPointerException
或BeanCurrentlyInCreationException
异常 。
原因分析:依赖注入在构造函数之后进行,因此在构造函数中无法访问通过依赖注入的字段。
解决方案:
- 避免在构造函数中访问依赖:将依赖访问逻辑移到初始化方法中
- 使用构造器注入:通过
@Autowired
注解在构造函数参数上,确保依赖在实例化时注入 - 使用
@PostConstruct
方法:在初始化方法中访问依赖 - 使用
Aware
接口:如ApplicationContextAware
,在setApplicationContext()
方法中访问依赖
代码示例:正确使用构造器注入
// 正确做法:使用构造器注入
@Component
public class UserService {private final UserRepository userRepository;@Autowiredpublic UserService(UserRepository userRepository) {this.userRepository = userRepository;}@PostConstructpublic void init() {// 在初始化方法中访问依赖userRepository.loadUsers();}
}// 错误做法:在构造函数中访问依赖
@Component
public class UserService {private UserRepository userRepository;public UserService() {// 此时 userRepository尚未注入userRepository.loadUsers(); // 抛出NullPointerException}@Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository = userRepository;}
}
面试考点:
- 为什么在构造函数中访问依赖会导致问题?
- 如何正确使用构造器注入?
- 如何避免
BeanCurrentlyInCreationException
异常?
6.3 高性能场景下的延迟初始化(Lazy-init)应用
定义:延迟初始化是指Bean的初始化方法在首次获取Bean时执行,而不是在容器启动时执行。
关键点:
- 减少启动时间:对于启动时不需要的Bean,可以延迟初始化
- 避免循环依赖:在某些情况下,延迟初始化可以避免循环依赖
- 适用场景:大型应用、需要按需加载的Bean
配置方式:
- XML配置:
<bean lazy-init="true">
- 注解配置:
@Bean(lazyInit = true)
- 全局配置:
<context:annotation-config lazy-init="true"/>
代码示例:延迟初始化配置
// 使用延迟初始化
@Configuration
public class AppConfig {@Bean(lazyInit = true)public ExpensiveService expensiveService() {System.out.println("ExpensiveService实例化");return new ExpensiveService();}@Beanpublic UserService userService() {System.out.println("UserService实例化");return new UserService();}
}
输出顺序:
UserService实例化
ExpensiveService实例化(当首次获取ExpensiveService时)
面试考点:
- 延迟初始化对Bean生命周期的影响?
- 如何配置延迟初始化?
- 延迟初始化和
@Lazy
注解的区别?
6.4 多模块项目中的Bean生命周期管理策略
问题描述:在多模块项目中,Bean的生命周期管理需要考虑模块之间的依赖关系和作用域。
解决方案:
- 模块化配置:将每个模块的Bean配置放在独立的配置类中
- 作用域管理:根据模块需求选择合适的作用域
- 依赖管理:使用
@Import
或@ComponentScan
明确指定模块之间的依赖关系 - 初始化顺序控制:使用
@DependsOn
或@Order
控制Bean的初始化顺序 - 销毁顺序控制:使用
@Order
控制Bean的销毁顺序
代码示例:多模块配置
// 模块A配置
@Configuration
public class ModuleAConfig {@Beanpublic ServiceA serviceA() {return new ServiceA();}
}// 模块B配置
@Configuration
@Import(ModuleAConfig.class)
public class ModuleBConfig {@Beanpublic ServiceB serviceB() {return new ServiceB();}@Beanpublic ServiceC serviceC() {return new ServiceC();}
}// 模块C配置
@Configuration
@Import({ModuleAConfig.class, ModuleBConfig.class})
public class ModuleCConfig {@Beanpublic ServiceD serviceD() {return new ServiceD();}
}
面试考点:
- 如何管理多模块项目中的Bean生命周期?
- 如何控制Bean的初始化顺序?
- 如何确保跨模块的Bean能够正确销毁?
第7章:高级特性与应用场景
7.1 基于条件的Bean生命周期控制
定义:根据特定条件(如环境变量、操作系统、Java版本等)决定是否创建和销毁Bean。
实现方式:
- @Conditional注解:根据条件决定是否创建Bean
- 环境变量检查:在初始化方法中检查环境变量
- 属性文件配置:通过属性文件决定Bean的创建和销毁
代码示例:条件化Bean创建
// 使用@Conditional注解
@Configuration
public class AppConfig {@Bean@Conditional"OnLinux")public LinuxService linuxService() {return new LinuxService();}@Bean@Conditional"OnWindows")public WindowsService windowsService() {return new WindowsService();}
}// 条件判断器
public class OnLinux implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return context.getEnvironment(). propertyNames(). contains("os.name=Linux");}
}public class OnWindows implements Condition {@Overridepublic boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {return context.getEnvironment(). propertyNames(). contains("os.name=Windows");}
}
面试考点:
- @Conditional注解的作用?
- 如何根据环境变量控制Bean的生命周期?
- 如何实现跨平台的Bean生命周期控制?
7.2 基于事件的Bean生命周期控制
定义:通过Spring的事件机制,在特定事件发生时触发Bean的初始化或销毁。
关键类:
- ApplicationEvent:表示一个应用事件
- ApplicationListener:监听应用事件
- EventDrivenBean:实现事件驱动的Bean
应用场景:
- 缓存预热:在容器启动后,监听
ContextRefreshedEvent
事件,触发缓存预热 - 资源释放:在容器关闭前,监听
ContextClosedEvent
事件,触发资源释放 - 按需加载:在特定业务事件发生时,动态创建和销毁Bean
代码示例:事件驱动的缓存预热
// 缓存预热监听器
@Component
public class CachePreheater implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {// 缓存预热System.out.println("缓存预热开始");// 加载数据到缓存// ...System.out.println("缓存预热完成");}
}// 资源释放监听器
@Component
public class ResourceReleaser implements ApplicationListener<ContextClosedEvent> {@Overridepublic void onApplicationEvent(ContextClosedEvent event) {// 资源释放System.out.println("资源释放开始");// 关闭数据库连接等// ...System.out.println("资源释放完成");}
}
面试考点:
- Spring事件机制如何工作?
- 如何监听容器启动和关闭事件?
- 如何实现基于事件的Bean生命周期控制?
7.3 基于作用域代理的Bean生命周期管理
定义:作用域代理允许非单例作用域的Bean(如原型、request、session)支持销毁方法,通过代理对象管理Bean的生命周期。
关键点:
- 代理模式:使用
ProxyMode.TARGET
或ProxyMode.动静态
创建代理对象 - 支持销毁方法:通过代理对象触发销毁方法
- 适用场景:需要在Bean销毁时执行特定操作的非单例Bean
配置方式:
// 启用作用域代理
@Component
@Scope(value = "prototype", proxyMode = ProxyMode.TARGET)
public class prototypeBean {@PostConstructpublic void init() {System.out.println("原型Bean初始化完成");}@PreDestroypublic void destroy() {System.out.println("原型Bean销毁完成");}
}
源码解析:在ScopeProxyFactory
类中,createProxy()
方法负责创建作用域代理:
// ScopeProxyFactory.java
public Object createProxy(String beanName, Object target, BeanFactory beanFactory) {// 创建代理对象return ProxyFactory.getProxy(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new invokerHandler (beanName, target, beanFactory));
}// invokerHandler.java
public class invokerHandler implements MethodInterceptor {private String beanName;private Object target;private BeanFactory beanFactory;@Overridepublic Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) {// 拦截方法调用if (method.getName().equals("destroy")) {// 触发销毁方法destroyBean beanName, target);return null;}// 调用目标方法return methodProxy.invoke(target, args);}private void destroyBean(String beanName, Object target) {// 从容器中移除BeanbeanFactory.destroyBean beanName, target);}
}
面试考点:
- 作用域代理如何工作?
- 如何为原型Bean启用销毁方法?
- 作用域代理对Bean性能的影响?
7.4 基于作用域的Bean生命周期管理
定义:根据不同作用域(如单例、原型、request、session)管理Bean的生命周期。
关键策略:
- 单例Bean:使用
@PreDestroy
或disposableBean
接口,确保容器关闭时释放资源 - 原型Bean:使用作用域代理,或手动调用销毁方法
- request作用域Bean:使用
RequestContextListener
,确保请求结束后释放资源 - session作用域Bean:使用
SessionContextListener
,确保会话过期后释放资源
代码示例:不同作用域的Bean配置
// 单例Bean
@Component
public class SingletonBean {@PostConstructpublic void init() {System.out.println("单例Bean初始化完成");}@PreDestroypublic void destroy() {System.out.println("单例Bean销毁完成");}
}// 原型Bean(启用作用域代理)
@Component
@Scope(value = "prototype", proxyMode = ProxyMode.TARGET)
public class prototypeBean {@PostConstructpublic void init() {System.out.println("原型Bean初始化完成");}@PreDestroypublic void destroy() {System.out.println("原型Bean销毁完成");}
}// request作用域Bean
@Component
@Scope("request")
public class RequestScopeBean {@PostConstructpublic void init() {System.out.println("request作用域Bean初始化完成");}@PreDestroypublic void destroy() {System.out.println("request作用域Bean销毁完成");}
}
面试考点:
- 不同作用域Bean的生命周期有何不同?
- 如何确保非单例Bean的销毁方法被调用?
- Web作用域Bean的销毁机制?