1. 普通java对象创建过程

举例:BusinessService businessService=new BusinessService();

编译:将.java文件编译成class文件

加载:等到类需要被初始化时(比如new) class文件被虚拟机通过类加载器加载到jvm(类加载过程参考https://www.cnblogs.com/enhance/p/10986340.html)

初始化:初始化阶段为类变量赋值为代码期望的值,供我们使用

简单来说,普通java环境创建对象是用Class对象作为模板进来创造出具体的实例

 

2. Spring管理Bean实例化过程

 

protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException {
    BeanWrapper instanceWrapper = null;
    if (mbd.isSingleton()) {
        instanceWrapper = (BeanWrapper)this.factoryBeanInstanceCache.remove(beanName);
    }

    if (instanceWrapper == null) {
        // 实例化阶段
        instanceWrapper = this.createBeanInstance(beanName, mbd, args);
    }

    ...

    Object exposedObject = bean;

    try {
        // 属性赋值阶段
        this.populateBean(beanName, mbd, instanceWrapper);
        // 初始化阶段
        exposedObject = this.initializeBean(beanName, exposedObject, mbd);
    } catch (Throwable var18) {
        ...
    }

    ...
}

 

 

 

如上图所示,spring bean的生命周期可以分为:实例化-》属性注入-》初始化-》使用-》销毁5个阶段. 

2.1实例化:

调用createBeanInstance()方法,Spring IOC容器读取元数据(bean的作用域)创建bean实例。但此时bean成员变量尚未初始化,仅完成内存空间分配和构造器执行

2.2属性赋值:

populateBean();为bean内注入依赖的属性,比如使用@Autowired @Resource @Value等注解

三级缓存解决循环依赖就是发生在这一阶段

// DefaultSingletonBeanRegistry.java
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 检查一级缓存(完整Bean)
    Object singletonObject = this.singletonObjects.get(beanName);
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
        synchronized (this.singletonObjects) {
            // 检查二级缓存(早期引用)
            singletonObject = this.earlySingletonObjects.get(beanName);
            if (singletonObject == null && allowEarlyReference) {
                // 检查三级缓存(ObjectFactory)
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

 

2.3初始化:

此阶段执行一些初始化方法:init-method @PostConstruct 或者通过实现InitializingBean接口的afterPropertiesSet()

2.3.1判断是否实现Aware相关接口,

Aware接口是一种标记接口,自定义bean通过实现不同Aware接口,可以向bean中注入ApplicationContext, ClassLoader,beanFactory等对象从而获取对应spring容器资源

Aware接口使用场景 参考https://blog.csdn.net/qusikao/article/details/136631127

  • 依赖注入:普通的依赖注入无法获取beanName,AppliationContext,BeanFactory,这时需要让bean实现对应aware接口
  • 环境感知:bean在不同环境可能做不同处理,此时bean implement EnvironmentAware,bean便可访问当前Environment根据环境感知操作
  • 资源访问:除了基本的依赖注入和环境感知外,Aware接口还可以用于访问Spring容器中的其他资源。例如,通过实现ResourceLoaderAware接口,Bean可以获得一个ResourceLoader的引用,用于加载类路径下的资源文件

 

Aware相关接口:

  • BeanNameAware: 实现此接口的bean可以获得其在Spring容器中的名称,当bean被创建并添加到容器中时,Spring会调用setBeanName(String name)方法。
  • BeanFactoryAware: 实现此接口的bean可以获得对其所在的BeanFactory的引用,这允许bean直接访问容器以查找或操作其他bean,通过setBeanFactory(BeanFactory beanFactory)方法注入。
  • ApplicationContextAware: 与BeanFactoryAware类似,但是提供对更高级的ApplicationContext的访问,实现此接口的bean可以通过setApplicationContext(ApplicationContext context)方法获得ApplicationContext的引用。
  • MessageSourceAware: 实现此接口的bean可以获得对MessageSource的引用,这允许bean进行国际化消息的处理,通过setMessageSource(MessageSource messageSource)方法注入。
  • ApplicationEventPublisherAware: 实现此接口的bean可以获得一个ApplicationEventPublisher的引用,用于发布应用事件,Spring会在适当时刻调用setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher)方法。
  • ResourceLoaderAware: 实现此接口的bean可以获得对ResourceLoader的引用,这使得bean可以加载资源,如配置文件等,通过setResourceLoader(ResourceLoader resourceLoader)方法注入。
  • EnvironmentAware: 实现此接口的bean可以获得对当前应用环境的Environment对象的引用。这允许bean查询配置的属性、配置文件等,通过setEnvironment(Environment environment)方法注入。
  • EmbeddedValueResolverAware: 实现此接口的bean可以获得对字符串值解析器的引用,该解析器能够处理占位符(如${...}),通过setEmbeddedValueResolver(StringValueResolver resolver)方法注入。
  • SchedulingConfigurerAware (不直接属于Aware接口系列, 但类似): 允许配置计划任务,在Spring Boot应用中,可以通过实现SchedulingConfigurer接口和覆盖configureTasks(ScheduledTaskRegistrar taskRegistrar)方法来定义计划任务

2.3.2 初始化前 beanPostBeforeInitialization()

允许用户在初始化前对bean进行处理,如下图MyBeanPostProcess类实现BeanPostProcessor接口,在类中重写postProcessorBeforeInitilization()

 2.3.3 初始化

调用@PostConstruct,实现InitializingBean的afterPropertiesSet()和init-method这三种不同的初始化方法,其运行顺序也是按照前边排序依次进行的

import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
 
public class Foo implements InitializingBean {
 
    public void init(){
        System.out.println("执行了init生命周期的初始化回调");
    }
 
    @PostConstruct
    public void postConstruct(){
        System.out.println("执行了postConstruct生命周期的初始化回调");
    }
 
    @Override
    public void afterPropertiesSet() {
        System.out.println("执行了afterPropertiesSet生命周期的初始化回调");
    }
}

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
@Configuration
public class InitConfiguration {
    @Bean(initMethod = "init")
    public Foo getInitMethodBean() {
        return new Foo();
    }
}

 

 

其执行结果为

执行了postConstruct生命周期的初始化回调

执行了afterPropertiesSet生命周期的初始化回调

执行了init生命周期的初始化回调

 

2.3.4 初始化后

在初始化方法后,用户对bean进行处理,如2.3.2中postProcessorAfterInitialization()

2.4 bean使用

2.5 销毁

bean 实现DisposableBean,重写destroy()方法

 

BeanPostProcessor接口函数

通过自定义这些方法,开发者可以实现:

  • 动态代理(如AOP)
  • 属性值的动态修改(如加密字段解密)
  • Bean的延迟初始化(如@Lazy注解的支持)
  • 资源的预释放(如销毁前的缓存清理)

详细版bean生命周期如下

 

 

3.三级缓存解决循环依赖问题

 

a)假设先创建Aservice的bean。在bean实例化阶段,先创建出Aservice的bean,创建出Asercvice的对象后就创建Aservice对应的ObjectFactory放到三级缓存

b) 然后Aservice继续往下走,到了注入属性Bsercice阶段,开始处理@Autowired要注入Bservice对象,此时会从一级缓存到三级缓存开始依次查找有没有Bservice对应的bean,此时肯定是没有Bservice的。

c)  此时Aservice的注入Bservice过程暂停,现在去创建Bservice,只有Bservice创建完后才能注入给Aservice

d) 于是Bservice开始创建,先实例化一个Bservice对象然后缓存到对应的一个ObjectFactory到第三季缓存,然后就到需要处理@Autowird注解注入Aservice时候,此时先去一级缓存找Aservice没有,再去二级缓存也没有Aservice,直到三级缓存找到Aservice,这样就拿到早期的Aservice对象。然后将早期的AService对象放到二级缓存,为什么需要放到二级缓存,主要是怕还有其他的循环依赖,如果还有的话,直接从二级缓存中就能拿到早期的AService对象。

e) 虽然Bservice注入的是早期的Aservice对象(仅仅是因为早期的Aservice对象可能有些bean创建的步骤没有完成),但跟最后完全创建好的Aservice bean是同一个对象

f) 此时Bservice中@Autowired Aservice步骤完成,经过其他springbean创建步骤后Bservice完全创建完成

g) Bservice创建完成后,将Bservice放到一级缓存,然后清空二三级缓存

h) 此时Aservice继续之前暂停@Autowired Bservice步骤。

i) 这样Bservice创建过程中注入早起三级缓存中Aservice,然后在Aservice注入一级缓存中Bservice。就这样解决循环依赖问题

 

一级缓存:存储已经完成实例化、属性注入和初始化后的bean

二级缓存:存储实例化完成的bean,此时属性并没有注入

三级缓存:存储bean的工厂对象


参考文献

https://blog.csdn.net/qq_15037231/article/details/105938673

https://blog.csdn.net/fox9916/article/details/128522598

 

https://blog.csdn.net/fox9916/article/details/128522598
posted on 2023-01-05 16:15  colorfulworld  阅读(249)  评论(0)    收藏  举报