第1章:Spring Bean生命周期概述

1.1 什么是Spring Bean生命周期?

定义:Spring Bean生命周期是指从Bean的创建、初始化、使用到销毁的完整过程,由Spring容器严格管理 。核心思想是Spring容器通过IoC(控制反转)和DI(依赖注入)机制,控制Bean的创建、配置和销毁,开发者可通过扩展点(如BeanPostProcessorAware接口)插入自定义逻辑。

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初始化方法(如@PostConstructInitializingBean.afterPropertiesSet()或自定义init-method之前,Spring容器调用所有BeanPostProcessorpostProcessBeforeInitialization()方法,允许开发者修改Bean属性或状态 。

关键点

  • 全局性:对容器中的所有Bean生效
  • 执行顺序:由BeanPostProcessor的实现类决定,可通过实现PriorityOrderedOrdered接口控制执行顺序 
  • 可修改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的初始化方法,包括以下三种方式:

  1. 注解方式

    • @PostConstruct:标注在方法上,方法执行在属性赋值之后、BeanPostProcessor的postProcessAfterInitialization()之前
    • @PreDestroy:标注在方法上,方法执行在Bean销毁之前
  2. 接口方式

    • InitializingBean:实现afterPropertiesSet()方法
    • DisposableBean:实现destroy()方法
  3. 配置方式

    • XML配置中的init-method属性
    • Java配置中的@Bean(initMethod="...")

关键点

  • 执行顺序@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容器调用所有BeanPostProcessorpostProcessAfterInitialization()方法,允许开发者对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()方法负责调用BeanPostProcessorpostProcessAfterInitialization()

// 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的销毁回调方法,包括以下三种方式:

  1. 注解方式

    • @PreDestroy:标注在方法上,方法执行在Bean销毁之前
  2. 接口方式

    • DisposableBean:实现destroy()方法
  3. 配置方式

    • XML配置中的destroy-method属性
    • Java配置中的@Bean(destroyMethod="...")

关键点

  • 单例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方法时,遵循以下顺序:

  1. 实现PriorityOrdered接口的处理器(按优先级排序)
  2. 实现Ordered接口的处理器(按顺序排序)
  3. 未实现排序接口的处理器(按注册顺序排序)

代码示例:自定义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);
}

销毁方法触发方式

  1. 手动调用:在使用完原型Bean后,手动调用其销毁方法
  2. 作用域代理:通过@Scope(proxyMode=TargetClass)启用代理,使原型Bean支持销毁方法 
  3. 第三方工具:如使用对象池管理原型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;
}

销毁机制

  1. request作用域:通过RequestContextListener监听HTTP请求结束,自动销毁Bean 
  2. 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通过三级缓存(singletonObjectsearlySingletonObjectssingletonFactories)解决循环依赖问题。

三级缓存作用

  • 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中关闭网络连接

排查工具

  1. YourKit Java Profiler:实时监控内存使用情况,创建多个堆快照进行对比分析 
  2. Eclipse Memory Analyzer (MAT):分析堆转储文件,找出未释放的资源
  3. lsof命令:检查进程打开的文件句柄数 

解决方案

  1. 确保销毁方法被调用:对于单例Bean,确保容器正常关闭;对于原型Bean,手动调用销毁方法或启用作用域代理 
  2. 使用try-with-resources:确保资源在使用后自动关闭 
  3. 实现 DisposableBean接口:在destroy()方法中释放资源 
  4. 使用@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或注解配置错误
  • 资源访问失败:如无法连接数据库

调试技巧

  1. 日志分析:启用Spring的DEBUG级别日志,查看Bean初始化的详细过程
  2. 断点调试:在IDE中设置断点,跟踪Bean初始化的执行流程
  3. 异常堆栈分析:查看抛出的异常信息,定位具体问题
  4. 使用@DependsOn:明确指定Bean的依赖顺序
  5. 使用@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,因为它们代码侵入性低
  • 避免实现接口:如InitializingBeanDisposableBean,因为它们代码侵入性高
  • 慎用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 避免在构造函数中访问未注入的依赖

问题描述:在构造函数中访问未注入的依赖会导致NullPointerExceptionBeanCurrentlyInCreationException异常 。

原因分析:依赖注入在构造函数之后进行,因此在构造函数中无法访问通过依赖注入的字段。

解决方案

  1. 避免在构造函数中访问依赖:将依赖访问逻辑移到初始化方法中
  2. 使用构造器注入:通过@Autowired注解在构造函数参数上,确保依赖在实例化时注入
  3. 使用@PostConstruct方法:在初始化方法中访问依赖
  4. 使用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

配置方式

  1. XML配置<bean lazy-init="true">
  2. 注解配置@Bean(lazyInit = true)
  3. 全局配置<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的生命周期管理需要考虑模块之间的依赖关系和作用域。

解决方案

  1. 模块化配置:将每个模块的Bean配置放在独立的配置类中
  2. 作用域管理:根据模块需求选择合适的作用域
  3. 依赖管理:使用@Import@ComponentScan明确指定模块之间的依赖关系
  4. 初始化顺序控制:使用@DependsOn@Order控制Bean的初始化顺序
  5. 销毁顺序控制:使用@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。

实现方式

  1. @Conditional注解:根据条件决定是否创建Bean
  2. 环境变量检查:在初始化方法中检查环境变量
  3. 属性文件配置:通过属性文件决定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.TARGETProxyMode.动静态创建代理对象
  • 支持销毁方法:通过代理对象触发销毁方法
  • 适用场景:需要在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的生命周期。

关键策略

  1. 单例Bean:使用@PreDestroy disposableBean接口,确保容器关闭时释放资源
  2. 原型Bean:使用作用域代理,或手动调用销毁方法
  3. request作用域Bean:使用RequestContextListener,确保请求结束后释放资源
  4. 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的销毁机制?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/91640.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/91640.shtml
英文地址,请注明出处:http://en.pswp.cn/web/91640.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【51单片机6位数码管密码锁】2022-10-15

缘由六位密码器设计连接LED-嵌入式-CSDN问答 矩阵51单片机密码锁,回复:https://bbs.csdn.net/topics/392713242_智者知已应修善业的博客-CSDN博客 #include "REG52.h" unsigned char code smgduan[]{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x…

‌我的第一个开源项目:跃动的心

还是一个编程初学者时&#xff0c;我怀着激动的心情完成了人生第一个开源项目——一个用HTML5 Canvas制作的动态跳动爱心效果。这个项目虽然简单&#xff0c;却让我深刻体会到了开源分享的快乐和技术创造的魅力。 壹、项目灵感 这个项目的灵感来源于浏览网页时&#xff0c;被各…

技术演进中的开发沉思-53 DELPHI VCL系列:windows的消息(下):TApplication窗体

今天我们梳理下关于TApplication的窗体消息下半部分的内容。前面也说过&#xff0c;在 Delphi 的世界里&#xff0c;TApplication 就像一位经验丰富的总工程师&#xff0c;而主窗体则是它倾注心血打造的核心建筑。如果你第一次在实验室里敲出 Delphi 代码时&#xff0c;屏幕上弹…

cesium FBO(四)自定义相机渲染到Canvas(离屏渲染)

前面几节的例子是将Cesium默认的相机渲染到纹理&#xff08;RTT&#xff09;或Canvas&#xff0c;这片文章讲解如何将自定义的一个camera的画面渲染到Canvas上&#xff0c;有了前面几篇的基础了&#xff0c;也能将自定义的画面渲染纹理、也可以灰度处理&#xff0c;原理是一样的…

双机并联无功环流抑制虚拟阻抗VSG控制【simulink仿真模型实现】

双机并联虚拟同步发电机&#xff08;VSG&#xff09;系统中&#xff0c;因线路阻抗不匹配及参数差异&#xff0c;易引发无功环流。本方案在传统VSG控制基础上&#xff0c;引入自适应虚拟阻抗环节。其核心在于&#xff1a;实时检测两机间无功环流分量&#xff0c;据此动态调节各…

python测试总结

测试题的基础知识点总结 1.循环求和 for循环步长&#xff08;range(2,101,2)&#xff09; while循环条件判断&#xff08;i%20&#xff09; 生成器表达式&#xff08;sum(i for i in range )&#xff09; 所以&#xff1a;sum(range(1,101,2))&#xff08;奇数和&#xff09;和…

识别和分类恶意软件样本的工具YARA

YARA 是一个用于识别和分类恶意软件样本的工具,广泛应用于恶意软件分析、威胁情报、入侵检测等领域。它通过编写规则(YARA Rules)来匹配文件中的特定字符串、十六进制模式、正则表达式等特征。 一、YARA 的基本使用方法 1. 安装 YARA Linux(Ubuntu/Debian) sudo apt-ge…

GaussDB 约束的语法

1 约束的作用约束是作用于数据表中列上的规则&#xff0c;用于限制表中数据的类型。约束的存在保证了数据库中数据的精确性和可靠性。约束有列级和表级之分&#xff0c;列级约束作用于单一的列&#xff0c;而表级约束作用于整张数据表。下面是 GaussDB SQL 中常用的约束。NOT …

SecurityContextHolder 管理安全上下文的核心组件详解

SecurityContextHolder 管理安全上下文的核心组件详解在 Spring Security 中&#xff0c;SecurityContextHolder 是​​安全上下文&#xff08;Security Context&#xff09;的核心存储容器​​&#xff0c;其核心作用是​​在当前线程中保存当前用户的认证信息&#xff08;如用…

c++详解系列(引用指针)

目录 1.什么是引用 2.引用的定义 3.引用的特性 4.引用的使用 4.1引用传参 4.2传引用返回 5.const引用&#xff08;在引用的定义前用const修饰&#xff09; 5.1对于引用 5.2对于指针 6.引用&指针 总结 1.什么是引用 引用就是给变量起别名&#xff0c;一个变量可以…

深度学习loss总结(二)

对于目前深度学习主流任务学习,loss的设置至关重要。下面就不同任务的loss设置进行如下总结: (1)目标检测 2D/3D目标检测中的 Loss(损失函数)是训练模型时优化目标的核心,通常包括位置、类别、尺寸、方向等多个方面。以下是目前 常见的 2D 和 3D 目标检测 Loss 分类与…

【Linux网络】netstat 的 -anptu 各个参数各自表示什么意思?

netstat 是一个网络统计工具&#xff0c;它可以显示网络连接、路由表、接口统计、伪装连接和多播成员资格。在 netstat 命令中&#xff0c;不同的参数可以用来定制输出的内容。 你提到的 -anptu 参数组合各自的功能如下&#xff1a; -a (all): 显示所有活动的连接和监听端口。它…

[硬件电路-115]:模拟电路 - 信号处理电路 - 功能放大器工作分类、工作原理、常见芯片

功能放大器是以特定功能为核心的集成化放大电路&#xff0c;通过将运算放大器与外围电阻、电容等元件集成在单一芯片中&#xff0c;实现标准化、高性能的信号放大功能。其核心优势在于简化设计流程、提升系统稳定性&#xff0c;并针对特定应用场景优化性能参数。以下从定义、分…

双网卡UDP广播通信机制详解

UDP广播通信机制详解 一、通信流程分析 发送阶段 通过Client.Bind(192.168.0.3, 60000)将UDP套接字绑定到指定网卡和端口设置RemoteHost "255.255.255.255"实现全网段广播数据流向&#xff1a;192.168.0.3:60000 → 255.255.255.255:50000 接收阶段 设备响应数据应返…

从遮挡难题到精准测量:激光频率梳技术如何实现深孔 3D 轮廓的 2um 级重复精度?

一、深孔 3D 轮廓测量的遮挡困境深孔结构&#xff08;如航空发动机燃油喷嘴孔、模具冷却孔&#xff09;因孔深大&#xff08;常超 100mm&#xff09;、深径比高&#xff08;&#xff1e;10:1&#xff09;&#xff0c;其 3D 轮廓测量长期受限于光学遮挡难题。传统光学测量技术&a…

.NET 依赖注入(DI)全面解析

文章目录一、依赖注入核心原理1. 控制反转(IoC)与DI关系2. .NET DI核心组件二、服务生命周期1. 三种生命周期类型三、DI容器实现原理1. 服务注册流程2. 服务解析流程四、高级实现方法1. 工厂模式注册2. 泛型服务注册3. 多实现解决方案五、ASP.NET Core中的DI集成1. 控制器注入2…

K8S部署ELK(二):部署Kafka消息队列

目录 1. Kafka 简介 1.1 Kafka 核心概念 &#xff08;1&#xff09;消息系统 vs. 流处理平台 &#xff08;2&#xff09;核心组件 1.2 Kafka 核心特性 &#xff08;1&#xff09;高吞吐 & 低延迟 &#xff08;2&#xff09;持久化存储 &#xff08;3&#xff09;分…

Rust进阶-part1-智能指针概述-box指针

Rust进阶[part1]_智能指针概述&box指针 智能指针概述 在Rust中,智能指针是一类特殊的数据结构,它们不仅像普通指针一样可以引用数据,还带有额外的元数据和功能。与普通指针不同,智能指针通常使用结构体实现,并且会实现 Deref 和 Drop 等特定的trait,以提供更强大的…

C++扩展 --- 并发支持库(补充1)

C扩展 --- 并发支持库&#xff08;下&#xff09;https://blog.csdn.net/Small_entreprene/article/details/149606406?fromshareblogdetail&sharetypeblogdetail&sharerId149606406&sharereferPC&sharesourceSmall_entreprene&sharefromfrom_link atom…

在Three.js中导入和添加自定义网格的最佳实践 - 综合指南

探索在Three.js中导入和添加自定义网格的最佳实践。本指南涵盖增强 3D 项目的技术、技巧和实际示例。 添加图片注释&#xff0c;不超过 140 字&#xff08;可选&#xff09; 强烈建议使用 GLTF 格式来集成 3D 几何体&#xff0c;提供简化的流程&#xff0c;并固有地支持动画、…