1. 普通java对象创建过程

举例:BusinessService businessService=new BusinessService();

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

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

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

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

 

2. Spring管理Bean实例化过程

2.1 容器初始化阶段

Spring启动时,spring按照bean声明方式(诸如注解@Component、@Configuration或者xml方式)去读取声明信息,并将这些声明信息解析成BeanDefinition注册到BeanDefinitionRegistry中,即对象管理信息收集。至此spring声明bean注册到IOC容器中;

同时进行各种处理器(BeanFactoryPostProcessor、BeanPostProcessor)的注册、上下文的初始化、事件广播的初始化等准备工作

 

服务通过SpringApplication.run(XiPApiCalcSpringBootApp.class, args);启动后跟踪run()到ApplicaitonContext,ApplicationContext在容器启动时会自动帮助我们构建所有的bean,所以当项目启动好之后,容器所有的对象都已经构建好。其主要逻辑都在refresh()函数中(注意refresh方法囊括容器初始化、bean实例化、bean初始化)

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            this.prepareRefresh(); //刷新上下文
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory(); //创建并初始化beanFacotry
            this.prepareBeanFactory(beanFactory); //填充BeanFacotry功能

            try {
                this.postProcessBeanFactory(beanFactory); //提供子类覆盖的额外功能,即通过postProcessorBeanFacotry在bean实例化前修改bean属性
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                this.invokeBeanFactoryPostProcessors(beanFactory); //激活各种beanFacotry
                this.registerBeanPostProcessors(beanFactory); //注册拦截bean创建的bean处理器,即注册beanPostProcessor(前置处理器后置处理器)
                beanPostProcess.end();
                this.initMessageSource(); //初始化上下文中的资源文件
                this.initApplicationEventMulticaster(); //初始化上下文事件广播器
                this.onRefresh(); //给子类扩展初始化其他bean
                this.registerListeners(); //在所有bean中查找listener bean,然后注册到广播器中
                this.finishBeanFactoryInitialization(beanFactory); //初始化剩下的单例bean,所有bean的实例化和初始化都在这里
                this.finishRefresh(); //刷新完成过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
            } catch (BeansException var10) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
                }

                this.destroyBeans();
                this.cancelRefresh(var10);
                throw var10;
            } finally {
                this.resetCommonCaches();
                contextRefresh.end();
            }

        }
    }

 

2.1.1 prepareRefresh()

初始化上下文,对系统环境变量或者系统属性进行校验

 

2.1.2 PostProcessBeanFactory、invokeBeanFactoryPostProcessor()

BeanFactoryPostProcssor接口中的函数

Spring提供BeanFactoryPostProcssor的容器扩展机制,这种机制可以让我们在bean实例化前对注册到容器的beanDefination中bean信息进行修改;执行BeanFactoryPostProcessor这个bean工厂后置处理逻辑,可以对bean元数据(@Scope @Lazy @DependsOn等)进行修改(比如@DependsOn会优先实例化其修饰的方法)

postprocessorBeanFactory、invokeBeanFactoryPostProcess这两个函数主要就是BeanFactoryPostProcesor的相关操作。值得一提的是我们经常在properties配置文件中配置一些属性值,然后通过${}配置xml中一些变量,这个过程就是BeanFactoryPostProcessor帮我们实现的

如下实例展示如果通过BeanFactoryPostProcessor来修改某些bean属性

@Data
@Component
public class Dog {
    private String name="旺财";
    private String color="黑色";
}

@Component
@Slf4j
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        log.info("com.fanfu.config.MyBeanFactoryPostProcessor.postProcessBeanFactory被执行");
        ScannedGenericBeanDefinition dog = ((ScannedGenericBeanDefinition) beanFactory.getBeanDefinition("dog"))  ; //beanFactory中定义了所有注册到容器bean,通过getBeanDefinition找到定义bean的BeanDefinition对象,然后对定义属性进行修改
        MutablePropertyValues propertyValues = dog.getPropertyValues();
        propertyValues.addPropertyValue("name", "狗蛋儿");
        log.info("修改Dog的BeanDefinition对象中的name属性为狗蛋儿");
    }


@SpringBootTest
@Slf4j
public class FanfuApplicationTests {
    @Test
    public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
        Dog dog = ((Dog) context.getBean("dog"));
        log.info(dog.getName());
        Assert.isTrue(dog.getName().equals("狗蛋儿"), "属性修改失败");
    }
}

 

验证结果表明,自定义的BeanFactoryPostProcessor接口的实现类(MyBeanFactoryPostProcessor),可以在容器读取到Bean的BeanDefinition数据之后,bean未实例化前,读取BeanDefiniion数据,并且根据需要进行修改

2.1.3 registerBeanPostProcessor

注册BeanPostProcessor(bean的增强器)。

BeanPostProcessor接口定义如下两个函数,通过这两个函数可以自己的实例化逻辑,比如想在spring完成实例化、配置、初始化后实现自己业务逻辑,可以通过实现BeanPostProcessor来完成

postProcessBeforeInitialization执行时机是spring管理bean实例化、属性注入完成后,自定义初始化(比如@PostConstruct 、implement InitializingBean、init-method)之前

postProcessAfterinitalization执行时机是在自定义方法之后完成

 

public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

 

如下实例展示BeanPostProcessor方法执行时机

@Getter
@Setter
@Slf4j
public class Dog implements InitializingBean {
    private String name = "旺财";
    private String color = "黑色";
    public Dog() {
        log.info("---dog的无参构造方法被执行");
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        log.info("---afterPropertiesSet被执行");
    }
    public void init() {
        log.info("---initMethod被执行");
    }
}


@Configuration
public class SpringConfig {
    @Bean(initMethod = "init")
    public Dog dog(){
        Dog dog = new Dog();
        return dog;
    }
}



@Component
@Slf4j
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("dog")) {
            log.info("postProcessBeforeInitialization---" + beanName);
            //如果特定的bean实例化完成后,还未执行InitializingBean.afterPropertiesSet()方法之前,有一些其他操作,可以在这里实现
        }
        return bean;
    }
 
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (beanName.equals("dog")) {
            log.info("postProcessAfterInitialization---" + beanName);
            //如果特定的bean实例化完成,InitializingBean.afterPropertiesSet()方法执行后,有一些其他操作,可以在这里实现
        }
        return bean;
    }



@SpringBootTest
@Slf4j
public class FanfuApplicationTests {
   @Test
    public void test3(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.fanfu");
        Dog dog = ((Dog) context.getBean("dog"));
        log.info(dog.getName());
    }

}

 

 

BeanPostProcess妙用:

某个接口多个实现类场景,可以使用BeanPostPorcess在bean初始化时侯指定某个实现类。具体参考示例如: https://blog.csdn.net/geekjoker/article/details/79868945

另外还可以将每个bean的初始化情况打印比如打印初始化时间

 

BeanPostProcess vs BeanFactoryPostProcess

BeanFactoryPostProcess是Factory级别的扩展接口,可以对bean配置信息进行操作,更确切的说Spring IOC容器允许BeanFactoryPostProcessor读取配置信息并且能够在容器实例化任何其他bean(所有的实现了BeanFactoryPostProcessor接口的类)之前改变配置信息;

而BeanPostProcessor是Bean级别的扩展接口,在spring初始化后实现自己的业务逻辑

 

2.1.4 finishBeanFactoryInitialization

我们定义的业务bean实例化和初始化都是在这个函数中实现的

 

2.2 bean实例化阶段

 主要是Bean的实例化,即bean对象的构造。不过此时构造出来的对象内部依赖并没有注入,只是通过反射(或Cglib)生成了具体对象的实例(执行构造函数),比如UserService依赖SendService,在这一步UserSerice中以来的SendService还是null

2.3 bean初始化阶段

 对实例化好之后bean进行依赖注入,同时执行用户定义一些初始化方法,注册bean的销毁方法等

bean实例化、初始化流程图如下

a) 属性注入;

b) 属性注入到对应bean后,判断该bean是否实现了Aware相关接口. Aware类型接口的作用就是让我们能拿到spring容器中的一些资源,Aware之前的名字就是可以拿到的资源,比如BeanNameAware可以拿到BeanName,比如

View Code

 c) 自定义初始化方法 

上边步骤bean对象已经被正确构造,但如果想要对象被使用前再进行一些自定义的处理,就可以通过beanpostprocessor接口实现。

BeanPostProcessor接口提供两个函数:postProcessBeforeInitialzation:这个函数先于InitialzationBean执行,称为前置处理

                postProcessAfterInitialzation:这个函数在InitialzationBean之后执行,称为后置处理

——>before方法执行完,则执行初始化相关方法比如@PostConstruct、实现了InitializingBean接口、init-method方法

——>执行BeanpostProcessor的after方法

——>基本流程走完后,可以获取到对象去使用

d) bean销毁

和init-method一样,通过给destroy-method指定函数就可以在bean销毁前执行指定的逻辑

 

 

实例化对象(只是把对象创建出来,但对象属性还没有注入)

——>把对象属性注入(比如@Autowired注解的生效就是这个阶段)

 

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。就这样解决循环依赖问题


参考文献

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  阅读(237)  评论(0编辑  收藏  举报