day04-Spring之Bean的生命周期

前言:

Spring主要功能创建对象(俗称IOC),

Bean的生命周期流程图

1、生成BeanDefinition

spring启动会进行扫描执行如下方法

org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider#scanCandidateComponents

Spring的扫描流程图

  • 根据ResourcePatternResolver 获取指定路径下所有的.class文件【最终生成 Resource 对象】
  • 遍历 Resource 集合
  • 利用MetadataReaderFactory 解析 Resource 获取metadateReader
  • 对metadataReader 进行 excludeFilters和 includeFilters ,
  • 若excludeFilters 匹配直接返回false,
  • 若 includeFiletes 匹配还要判断,是否有@Conditional ,如果有则需要判断@Conditional 注解筛选是否筛选过,不能筛选 直接false
  • 筛选通过后,还要判断
  • 是否独立、【不是接口或抽象】、如果是抽象,类上面是否添加@Lookup注解 【三个条件缺一不可】
  • 最终将 ScannedGenericBeanDefinition 生成BeanDefinition 对象返回

其中 @Conditional 的注解的作用

@Conditional 是 Spring 4.0 引入的核心注解,用于条件化地创建 Bean。它允许根据特定条件决定是否注册 Bean 到 Spring 容器中。

除了自定义条件,Spring 还提供了一些内置的条件注解,这些注解都是 @Conditional 的扩展,使用起来更加方便:

  • @ConditionalOnBean:当容器中存在指定 Bean 时。
  • @ConditionalOnMissingBean:当容器中不存在指定 Bean 时。
  • @ConditionalOnClass:当类路径中存在指定类时。
  • @ConditionalOnMissingClass:当类路径中不存在指定类时。
  • @ConditionalOnProperty:当指定的属性有指定的值时。
  • @ConditionalOnResource:当类路径中存在指定资源时。
  • @ConditionalOnWebApplication:当是 Web 应用时。
  • @ConditionalOnNotWebApplication:当不是 Web 应用时。
  • @ConditionalOnExpression:当 SpEL 表达式为 true 时。

@Conditional 注解 demo案例:

StuService Bean的创建 要依赖于 StuServiceCondition

c 复制代码
@Component
@Conditional(StuServiceCondition.class)
public class StuService {

    public void test(){
       System.out.println("stu test ...");
    }
}
c 复制代码
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class StuServiceCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
       // 检查某个属性是否存在

       return context.getEnvironment()
             .containsProperty("stu.service.enabled");
    }
}

这时获取bean 为stuService 找不到异常。

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'stuService' available...

MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);

创建MetadataReader 注意点:

org.springframework.core.type.classreading.CachingMetadataReaderFactory#getMetadataReader

CachingMetadataReaderFactory解析某个.class文件得到 MetadataReader对象,利用的是ASM技术,并没有加载这个类到JVM。最终得到的ScannedGenericBeanDefinition对象,beanClass属性存储当前的类的名称,而不是class对象。

2、合并BeanDefinition

在通过BeanDefinition之后,就可以根据BeanDefinition创建Bean对象。在spring中支持父子BeanDefinition,和Java中继承相似

比如:

spring.xml

c 复制代码
<bean id="parent" class="com.dx.service.Parent" scope="prototype"/>
<bean id="child" class="com.dx.service.Child"  />

测试:

c 复制代码
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
xmlBeanDefinitionReader.loadBeanDefinitions("spring.xml");
System.out.println(applicationContext.getBean("child"));
System.out.println(applicationContext.getBean("child"));
System.out.println(applicationContext.getBean("child"));

测试结果:

com.dx.service.Child@ef9296d

com.dx.service.Child@ef9296d

com.dx.service.Child@ef9296d

如果将xml修改为:

c 复制代码
<bean id="parent" class="com.dx.service.Parent" scope="prototype"/>
<bean id="child" class="com.dx.service.Child" parent="parent" />

测试的结果是

com.dx.service.Child@ef9296d

com.dx.service.Child@36c88a32

com.dx.service.Child@7880cdf3

child可以继承parent的 scope,

  • 子如果有scope 则使用自己的
  • 子没有scope,继承父类scope,父类若没有scope有parent的属性,同样的继承逻辑
    源码的大概如下:
  • 根据beanName判断是否合并过,合并过直接退出
  • 判断当前的bean是否有父类,
  • 如果没有设置 当前bean为RootBeanDefinition
  • 如果有循环获取 bean的父bean
  • 覆盖父定义属性(子覆盖父)
c 复制代码
protected RootBeanDefinition getMergedBeanDefinition(
        String beanName, BeanDefinition bd, @Nullable BeanDefinition containingBd)
        throws BeanDefinitionStoreException {
    
    synchronized (this.mergedBeanDefinitions) {
        // 1. 检查是否已经合并过
        RootBeanDefinition mbd = this.mergedBeanDefinitions.get(beanName);
        
        if (mbd == null) {
            // 2. 如果没有父定义,直接转换为RootBeanDefinition
            if (bd.getParentName() == null) {
                mbd = new RootBeanDefinition(bd);
            } else {
                // 3. 递归合并父定义
                BeanDefinition pbd;
                try {
                    String parentBeanName = transformedBeanName(bd.getParentName());
                    pbd = getMergedBeanDefinition(parentBeanName);
                }
                // ...
                
                // 4. 深度拷贝父定义
                mbd = new RootBeanDefinition(pbd);
                
                // 5. 覆盖父定义属性(子覆盖父)
                mbd.overrideFrom(bd);
            }
            
            // 6. 缓存合并结果
            this.mergedBeanDefinitions.put(beanName, mbd);
        }
        return mbd;
    }
}

3、加载类

BeanDefinition合并之后,就可以创建Bean的对象执行的方法是

org.springframework.beans.factory.support.AbstractBeanFactory#resolveBeanClass

创建bean就必须实例化对象,实例化要先加载类所对应class

c 复制代码
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);

方法的主要实现是:

c 复制代码
// 如果是beanClass就直接返回
if (mbd.hasBeanClass()) {
    return mbd.getBeanClass();
}

// 如果beanClass没有被加载,会根据doResolveBeanClass 
if (System.getSecurityManager() != null) {
    return AccessController.doPrivileged((PrivilegedExceptionAction<Class<?>>)
          () -> doResolveBeanClass(mbd, typesToMatch), getAccessControlContext());
}
else {
    return doResolveBeanClass(mbd, typesToMatch);
}

如果beanClass 属性的类型是Class 直接返回,不是则根据类名加载(doResolveBeanClass(mbd, typesToMatch))

会利用BeanFactory所设置的类加载器加载类,如果没有设置,则默认使用ClassUtils.getDefaultClassLoader()类加载

ClassUtils.getDefaultClassLoader()类加载方法:

  • 优先获取当前线程的类加载器
  • 当前线程类加载为空,返回ClassUtils.class.getClassLoader()
  • 如果ClassUtils.class.getClassLoader() 也为空,则ClassLoader.getSystemClassLoader()

4、实例化前

BeanDefinition 对应的类加载成功后,实例化对象前 Spring提供一个扩展点允许某个对象、某些对象实例化前做些额外的工作

org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation

c 复制代码
import com.zhouyu.service.StuService;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class DxBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
       if ("stuService".equals(beanName)){
          System.out.println("加载 stuService 初始化之前");
          // Spring将直接使用这个对象
          return new StuService();
       }
       // 返回null则走正常流程
       return null;
    }
}

InstantiationAwareBeanPostProcessor 的

postProcessBeforeInstantiation 除了常见的创建代理对象外,还有以下重要作用:

1,完全绕过spring的生命周期

c 复制代码
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // 如果返回非null对象,Spring将:
    // 1. 跳过默认构造函数调用
    // 2. 跳过后置处理器链的后续处理
    // 3. 跳过属性注入
    if (beanName.equals("specialBean")) {
        return new SpecialBean();  // Spring将直接使用这个对象
    }
    return null;  // 返回null则走正常流程
}

2、根据条件Bean创建

c 复制代码
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // 根据条件决定是否创建Bean
    if (shouldSkipCreation(beanClass, beanName)) {
        return new NoOpBean();  // 返回一个占位对象
    }
    
    // 根据环境变量/配置决定实现类
    if (beanClass.isAssignableFrom(Service.class)) {
        return isProduction() ? 
            new ProductionService() : 
            new MockService();
    }
    
    return null;
}

3、对象池/缓存管理

c 复制代码
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    if (beanClass.isAnnotationPresent(Poolable.class)) {
        // 从对象池获取实例,而不是新建
        Object pooledInstance = objectPool.acquire(beanClass);
        if (pooledInstance != null) {
            return pooledInstance;  // 返回池中对象
        }
    }
    return null;
}

4、性能优化场景

c 复制代码
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    // 对于频繁创建的原型Bean,使用对象复用策略
    if (isHighFrequencyPrototype(beanClass)) {
        return prototypeReuseStrategy.createOrReuse(beanClass);
    }
    
    // 对于已知的无状态Bean,直接返回共享实例
    if (isStateless(beanClass)) {
        return getSharedInstance(beanClass);
    }
    
    return null;
}

postProcessBeforeInstantiation 使用注意点

1、跳过正常的生命周期 :返回null 会跳过

  • postProcessAfterInstantiation
  • 属性注入 (populateBean)
  • 初始化回调 (afterPropertiesSet, init-method)
  • postProcessBeforeInitialization
  • postProcessAfterInitialization
    2、需要手动处理依赖
c 复制代码
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
    MyBean bean = new MyBean();
    // 需要手动注入依赖
    bean.setDependency(manualLookup());
    // 手动调用初始化
    bean.init();
    return bean;
}

3、与 AOP 的协调:如果在此创建代理,需要确保与其他 AOP 配置协调一致

5、实例化

会根据 BeanDefinition 创建一个对象。

5.1 Supplier创建对象

判断Beandefinition 中是否设置Supplier,如果设置了 则调用Supplier的get() 设置 Supplier

c 复制代码
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(Person.class);

// 设置 supplier
beanDefinition.setInstanceSupplier(new Supplier<Object>() {
    @Override
    public Object get() {
       // 这里可以编写创建逻辑
       Person person = new Person();
       person.setAge(18);
       person.setName("张三");
       return person;
    }
});
// 注册bean
applicationContext.registerBeanDefinition("person",beanDefinition);
System.out.println(applicationContext.getBean("person"));

====== 执行结果=====
Person{age=18, name='张三'}

Supplier 基础概念和作用

1,Supplier 是什么

是 Java 8 引入的函数式接口,表示一个结果的提供者:

c 复制代码
@FunctionalInterface
public interface Supplier<T> {

    /**
     * Gets a result.
     *
     * @return a result
     */
    T get();
}

1.2 在Spring中作用:

1.延迟实例化:将 Bean 的创建逻辑封装起来,按需调用

2.灵活性:允许运行时动态决定如何创建 Bean

3.与 BeanDefinition 解耦:将创建逻辑从 BeanDefinition 中分离

2、工厂方法创建对象

如果没有设置Supplier,检查是否BeanDefinition中是否设置 factory-method

sprin.xml

c 复制代码
<bean id="stuService" class="com.zhouyu.service.StuService" factory-method="createStuServiceFactory"/>
c 复制代码
public class StuService {
    public static StuService createStuServiceFactory(){
       System.out.println("this StuService createFactory");
       return new StuService();
    }

    public void test(){
       System.out.println("stu test ...");
    }
}
c 复制代码
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
new XmlBeanDefinitionReader(applicationContext).loadBeanDefinitions("spring.xml");
System.out.println(applicationContext.getBean("stuService"));

3、推断方法 @Lookup注解

c 复制代码
import org.springframework.stereotype.Component;

@Component
public class StuService {

    public void test(){
       System.out.println("stu test ...");
    }
}
c 复制代码
创建一个Spring容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
StuService stuService = (StuService) applicationContext.getBean("stuService");
stuService.test();

执行结果

stu test ...

测试@Conditional注解

c 复制代码
import org.springframework.context.annotation.Conditional;
import org.springframework.stereotype.Component;

@Component
@Conditional(StuServiceCondition.class)
public class StuService {

    public void test(){
       System.out.println("stu test ...");
    }
}
c 复制代码
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;

public class StuServiceCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
       // 检查某个属性是否存在

       return context.getEnvironment()
             .containsProperty("stu.service.enabled");
    }
}

执行结果报:

Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'stuService' available...

6、BeanDefinition的后置处理器

比如Spring中使用

c 复制代码
@Component
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
       MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {


    @Override
    public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
       System.out.println(" AutowiredAnnotationBeanPostProcessor postProcessMergedBeanDefinition method ");
    }
}

7、实例化后

postProcessAfterInstantiation 作用

  • 在Bean的实例化后、属性注入前执行
  • 可以返回false阻止Spring对该Bean进行属性注入
  • 适合用于自定义初始化逻辑或条件判断
    典型应用场景:
  • 动态控制属性注入
  • 实现延迟注入
  • 属性值验证和转换
  • 特殊Bean的预处理
    属性填充案例:
c 复制代码
@Component
public class DxInstanceAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {

       if ("stuService".equals(beanName)) {
          PerSon perSon = new PerSon();
          perSon.setAge(12);
          perSon.setName("张三");
          System.out.println(perSon);
       }
       return true;
    }

}

8、自动注入

9、处理属性

InstantiationAwareBeanPostProcessor.postProcessProperties() 是Spring框架中一个非常重要的扩展点,它在Bean的生命周期中扮演着关键角色。

主要作用包括:

1.处理注解驱动的依赖注入:例如,@Autowired、@Value、@Inject、@Resource等注解的解析和注入。

2.属性值的后处理:可以对属性值进行转换、验证、加密/解密等操作。

3.动态添加属性:根据某些条件动态添加属性。

4.跳过某些属性的注入:通过返回null或修改PropertyValues来控制哪些属性需要注入。

比如Spring内置实现

AutowiredAnnotationBeanPostProcessor

c 复制代码
// 主要职责:处理 @Autowired、@Value、@Inject 注解
public class AutowiredAnnotationBeanPostProcessor {
    
    @Override
    public PropertyValues postProcessProperties(
            PropertyValues pvs, Object bean, String beanName) {
        
        // 1. 获取或构建注入元数据
        InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
        
        try {
            // 2. 执行实际的注入操作
            metadata.inject(bean, beanName, pvs);
        } catch (Throwable ex) {
            throw new BeanCreationException(beanName, "Injection failed", ex);
        }
        
        // 3. 返回可能被修改的 PropertyValues
        return pvs;
    }
    
    private void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) {
        // 字段注入
        for (AutowiredFieldElement field : this.autowiredFields) {
            field.inject(bean, beanName, pvs);
        }
        
        // 方法注入
        for (AutowiredMethodElement method : this.autowiredMethods) {
            method.inject(bean, beanName, pvs);
        }
    }
}

注解解析

处理各种依赖注入注解属性处理

修改、添加、删除属性值值转换

类型转换、占位符解析、SpEL计算

条件控制:根据条件决定是否注入某些属性

验证检查:属性值验证和约束检查

10、执行Aware

1.获取Bean在容器中的名称:通过实现BeanNameAware接口,Bean可以知道自己在容器中配置的名称。

2.获取BeanFactory:通过实现BeanFactoryAware接口,Bean可以获取到BeanFactory,从而可以手动获取其他Bean,或者进行一些高级操作。

3.获取ApplicationContext:通过实现ApplicationContextAware接口,Bean可以获取到ApplicationContext,从而可以访问容器上下文,例如获取其他Bean、发布事件、访问环境变量等。

4.获取环境配置:通过实现EnvironmentAware接口,Bean可以获取到Environment对象,从而可以访问配置属性、profiles等。

5.资源加载:通过实现ResourceLoaderAware接口,Bean可以获取到ResourceLoader,从而可以加载类路径或文件系统中的资源。

6.国际化:通过实现MessageSourceAware接口,Bean可以获取到MessageSource,从而可以进行国际化消息的解析。

7.应用事件发布:通过实现ApplicationEventPublisherAware接口,Bean可以获取到ApplicationEventPublisher,从而可以发布应用事件。

8.嵌入式值解析:通过实现EmbeddedValueResolverAware接口,Bean可以获取到StringValueResolver,从而可以解析嵌入式值(例如SpEL表达式)。

使用 Aware 的场景清单

c 复制代码
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.stereotype.Component;

@Component
public class BeanIdentityService implements BeanNameAware, BeanClassLoaderAware {

    private String beanName;
    private ClassLoader classLoader;

    @Override
    public void setBeanClassLoader(ClassLoader classLoader) {
       this.classLoader = classLoader;
       System.out.println("current classLoader :" + classLoader);
    }

    @Override
    public void setBeanName(String name) {
       // 场景:日志记录、监控、动态配置
       this.beanName = beanName;
       System.out.println("current bean name :" + beanName);
    }
}

11、初始化前

BeanPostProcessor.postProcessBeforeInitialization()

c 复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class DxPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
       if ("stuService".equals(beanName)){
          System.out.println("初始化之前");
       }
       return bean;
    }
}

12、初始化

c 复制代码
// 1. @PostConstruct 注解方法
@PostConstruct
public void initMethod1() {
    // JSR-250 标准,最先执行
}

// 2. InitializingBean 接口的 afterPropertiesSet 方法
@Override
public void afterPropertiesSet() throws Exception {
    // Spring 接口方式,第二执行
}

// 3. XML/@Bean 配置的 init-method
// XML: <bean id="demo" class="com.xx.xx.Demo" init-method="customInit"/>
// @Bean: @Bean(initMethod = "customInit")
public void customInit() {
    // 自定义方法,最后执行
}

13、初始化后

这个是bean创建的生命周期最后一步。

c 复制代码
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class DxPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
       if ("stuService".equals(beanName)){
          System.out.println("初始化之后");
       }
       return bean;
    }
}

喜欢我的文章记得点个在看,或者点赞,持续更新中ing...

相关推荐
代码笔耕2 小时前
面向对象开发实践之消息中心设计(二)
java·后端·架构
云水木石2 小时前
Rust 语言开发的 Linux 桌面来了
linux·运维·开发语言·后端·rust
法欧特斯卡雷特2 小时前
Kotlin 2.3.0 现已发布!又有什么好东西?
后端·架构·开源
要开心吖ZSH3 小时前
应用集成平台-系统之间的桥梁-思路分享
java·kafka·交互
TsengOnce3 小时前
阿里云ECS多版本JDK切换
java·python·阿里云
wearegogog1233 小时前
基于C#的FTP客户端实现方案
java·网络·c#
听风吟丶3 小时前
Java NIO 深度解析:从核心组件到高并发实战
java·开发语言·jvm
野生技术架构师3 小时前
Java面试题及答案总结(互联网大厂新版)
java·面试·状态模式
a努力。3 小时前
小红书Java面试被问:ThreadLocal 内存泄漏问题及解决方案
java·jvm·后端·算法·面试·架构