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...

相关推荐
xuxigifxfh8 分钟前
牛客:BISHI2 【模板】栈的操作
java·开发语言·windows·算法
房开民28 分钟前
通俗总结 Octree(八叉树)
java·服务器·数据库
豆角焖肉33 分钟前
SpringBoot 集成腾讯 AI 人脸识别
人工智能·spring boot·后端·人脸识别·腾讯 ai·base64 图片
付威20231 小时前
如果你想拥有自己的 Agent,为什么值得从 rpi 开始
后端
木头科技1 小时前
【AI 工程化第十五篇】Spring AI 流式输出高并发性能优化实战:SSE、背压、限流、缓存与灰度发布
人工智能·spring·性能优化
2302_805771071 小时前
Day23:POM设计模式(封装)
java·开发语言·设计模式
SL_staff1 小时前
APS降本增效的关键:在JVS中实现‘人-机-料-法-环’全要素耦合调度
java·github·全栈
十年Java程序媛1 小时前
Java String、StringBuilder、StringBuffer 底层原理|字符串拼接性能与线程安全
java·开发语言·spring boot·安全·面试
可乐ea1 小时前
2000 个智能体把 Agent 重写成 Rust:编排流水线拆解
开发语言·后端·rust·多智能体协作·ai编程助手·智能体编排·rust重写
用户72757483196501 小时前
02-变量、常量和字符串:len("Hello, 世界") 为什么不是 9?
后端