首页 > 其他分享 >Spring IOC原理

Spring IOC原理

时间:2024-05-17 17:52:53浏览次数:26  
标签:初始化 BeanPostProcessor Spring beanName Bean bean spring 原理 IOC

1、IOC的理解

IOC也叫控制反转,是将对象的创建和管理交给spring来做。

了解spring IOC,先了解几个相关类:

(1)IOC容器-BeanFactory

BeanFactory是IOC容器的顶层接口,定义一些基础功能,ApplicationContext是IOC容器的高级接口,功能更多,如资源的访问(XML文件、Java配置类)等;他们都是负责生产和管理bean的工厂。

(2)Bean和BeanDefinition

BeanDefinition是spring对bean的定义信息,spring将XML配置文件或注解解析成BeanDefinition,然后根据BeanDefinition可以实例化为Bean。

spring的bean有两种:一种是普通bean,一种是工厂bean(FactoryBean),FactoryBean可以生成并返回某一个类型的bean实例,可以借助于它自定义Bean的创建过程,它在spring框架的一些组件中常用。

(3)后置处理器

spring提供了两种后置处理器:BeanPostProcessor和BeanFactoryPostProcessor。

  • BeanPostProcessor是针对bean级别的处理器,如果一个类实现了BeanPostProcessor,默认对spring容器中所有的bean进行处理。可以通过参数对某个bean进行处理。第一个参数是bean实例,第二个参数是bean的name。

注意:BeanPostProcessor的两个方法分别是在初始化方法(init-method)前后执行,也就是在bean实例化和依赖注入之后执行。

其实常用的@PostConstruct注解也是利用BeanPostProcessor实现的,InitDestroyAnnotationBeanPostProcessor 后置处理器的 postProcessBeforeInitialization() 方法会判断每个Bean是否有方法被@PostConstruct注解标注,标注了就执行。(也就是@PostConstruct也只对使用了它的bean生效)

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;
    }
}
  • BeanFactoryPostProcessor是针对BeanFactory级别的处理。

@FunctionalInterface
public interface BeanFactoryPostProcessor {
    void postProcessBeanFactory(ConfigurableListableBeanFactory var1) throws BeansException;
}

此接口只提供了一个方法,方法参数为ConfigurableListableBeanFactory,根据该参数的getBeanDefinition()可以获取BeanDefinition对定义的bean属性进行修改。

注意:调用 BeanFactoryPostProcessor 方法时,这时候bean还没有实例化,此时 bean 刚被解析成 BeanDefinition对象。

(4)初始化Bean—InitializingBean

此接口只有一个方法,在初始化方法init()执行前调用

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

注意:BeanPostProcessor 是对容器所有Bean都会执行,也就是只要有接口实现了BeanPostProcessor,就会作用于所有Bean;InitializingBean 不一样,它只作用于实现了该接口的Bean

2、bean的生命周期

  • 实例化:这个阶段就是Spring加载XML配置文件或扫描注解,将类解析为BeanDefinition,然后通过反射机制创建Bean对象的过程。

  • 依赖注入:实例化完成之后,Spring就会调用Bean对应的setXxx()方法、或者构造方法给相应的属性赋值。

  • 初始化:在Bean实例化完成并且依赖注入之后,就会调用Bean的初始化方法,进行一些额外的处理操作,默认初始化方法一般叫做【init()】。

  • 使用阶段:处于这个阶段的Bean对象,就可以真正的被使用啦。

  • 销毁阶段:当某个Bean对象不再被使用时候,此时会首先调用销毁方法(默认销毁方法我们习惯叫做【destory()】),用于释放一些系统资源,然后将Bean对象进行垃圾回收

               

3、spring源码

3.1、spring IOC容器启动主流程

spring IOC初始化的关键环节在 AbstractApplicationContext#refresh() 方法中。

@Override
  public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
      // 第1步:刷新前预处理.
      prepareRefresh();
​
      // 第2步:获取BeanFactory,默认实现是DefaultListableBeanFactory;加载BeanDefition 并注册到 BeanDefitionRegistry.
      ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
​
      // 第3步:BeanFactory的预准备工作(BeanFactory进行一些设置,比如context的类加 载器等).
      prepareBeanFactory(beanFactory);
​
      try {
        // 第4步:BeanFactory准备工作完成后进行的后置处理工作.
        postProcessBeanFactory(beanFactory);
​
        // 第5步:实例化并调用实现了BeanFactoryPostProcessor接口的Bean.
        invokeBeanFactoryPostProcessors(beanFactory);
​
        // 第6步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执 .
        registerBeanPostProcessors(beanFactory);
​
        // 第7步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析).
        initMessageSource();
​
        // 第8步:初始化事件派发器.
        initApplicationEventMulticaster();
​
        // 第9步:子类重写这个方法,在容器刷新的时候可以自定义逻辑.
        onRefresh();
​
        // 第10步:注册应用的监听器。就是注册实现了ApplicationListener接口的监听器Bean.
        registerListeners();
​
        /** 
        第11步:初始化所有剩下的非懒加载的单例bean 初始化创建非懒加载方式的单例Bean实例(未设置属性).
        填充属性 
        初始化方法调用(比如调用afterPropertiesSet方法、init-method方法) 调用BeanPostProcessor(后置处理器)对实例bean进行后置处        
        **/
        finishBeanFactoryInitialization(beanFactory);
​
        // 第12步:完成Context的刷新。主要是调用LifecycleProcessor的onRefresh()方法,并且发布事件(ContextRefreshedEvent).
        finishRefresh();
      }
      。。。。。
    }

3.2、bean的创建:

finishBeanFactoryInitialization(beanFactory)—>

DefaultListableBeanFactory类的preInstantiateSingletons()方法—>

AbstractBeanFactory类的getBean(String beanName),普通bean和工厂bean都是通过getBean创建的—>

AbstractBeanFactory类的doGetBean(String beanName)—>

AbstractAutowireCapableBeanFactory类的createBean(String beanName)—>doCreateBean(String beanName)

在doCreatBean()中:创建Bean实例、属性填充、调用初始化方法、执行后置处理器

 // 创建Bean实例,但是还未设置属性
    if (instanceWrapper == null) {
      instanceWrapper = createBeanInstance(beanName, mbd, args);
    }
    。。。
    //初始化Bean
    Object exposedObject = bean;
    try {
      //属性注入
      populateBean(beanName, mbd, instanceWrapper);
      //调用初始化方法,执行BeanPostProcessor后置处理器
      exposedObject = initializeBean(beanName, exposedObject, mbd);
    }

再看下初始化方法中的具体操作 initializeBean()

Object wrappedBean = bean;
    //执行 BeanPostProcessor 的 postProcessBeforeInitialization
    if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
    }
​
    try {
      //执行初始化方法,如果Bean实现了 InitializingBean,会先调用其 afterPropertiesSet()方法
      //再调用初始化方法 init()
      invokeInitMethods(beanName, wrappedBean, mbd);
    }
    //执行 BeanPostProcessor 的 postProcessAfterInitialization 方法
    if (mbd == null || !mbd.isSynthetic()) {
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
    }

对于Bean懒加载机制,就是在spring IOC容器初始化时不做处理,而是在第一次context.getBean()是进行初始化。

标签:初始化,BeanPostProcessor,Spring,beanName,Bean,bean,spring,原理,IOC
From: https://www.cnblogs.com/jing-yi/p/18198247

相关文章

  • springboot2 - 请求相关的兼容配置
    StandardServletMultipartResolverStandardServletMultipartResolver在spring4和spring5代码是不一样的。在低版本spring环境下,文件只能通过POST请求提交。对程序的影响可能不大,因为现在的做法,基本形成统一的定式:文件表单和业务表单分离,先将文件上传,返回一段url,再将......
  • 使用Spring HttpExchange时数据对象遇LocalDateTime字段类型json反序列化失败的解决方
    方法:重写MessageConverter,使得yyyy-MM-ddHH:mm:ss的字符串能反序列化到LocalDateTime类型上。@ConfigurationpublicclassHttpClientConfig{@Value("${service.host}")privateStringhost;@BeanRestClient.BuilderrestClientBuilder(){r......
  • 二极管和三极管导通原理
    二极管导通原理二极管一般是由P型半导体和N型半导体结合而成,如下所示P型半导体掺入大量3价原子,形成大量空穴,N型半导体掺入大量5价原子,形成大量电子。所以P型半导体和N型半导体结合时在结合处会发生电子和空穴的扩散运动(本质是电子扩散运动)N区电子向P区扩散移动,所以会在中间......
  • SpringCloud解决feign调用token丢失问题
    背景讨论feign请求在微服务环境中,完成一个http请求,经常需要调用其他好几个服务才可以完成其功能,这种情况非常普遍,无法避免。那么就需要服务之间的通过feignClient发起请求,获取需要的资源。认证和鉴权一般而言,微服务项目部署环境中,各个微服务都是运行在内网环境,网关服务负责请......
  • SpringMVC中的异常处理机制
    1.概述SpringMVC提供了基于xml和基于注解的异常处理机制,一般情况下两者都要进行配置,xml异常处理机制主要用于处理xml方式产生的异常,注解异常处理机制主要用于处理基于注解方式产生的异常。2.基于xml方式的异常处理机制<!--配置基于xml的异常映射--><beanid="simpleMapp......
  • spring security 使用过滤器认证登录时,抛出自定义异常
    前情提要最近在做项目的改造,涉及到新增用户的离职冻结状态,当被离职/冻结后,尝试登录系统,则抛出不同的异常代码给前端,前端依据不同的异常代码提示不同的文本。所以需要对项目的认证逻辑简单调整,增加按照不同的登录用户的状态(离职/冻结)判断,如果满足指定状态,则抛出对应的异常代码。......
  • Spring Boot的常用注解
    在SpringBoot中,注解(Annotation)是核心特性之一,广泛用于配置和简化开发。以下是SpringBoot中一些常用的注解及其示例:1.@SpringBootApplication@SpringBootApplication是一个组合注解,包括了@Configuration、@EnableAutoConfiguration和@ComponentScan。它通常用在主类上,标识一个......
  • SpringBoot给所有的 Model添加属性
    添加全局数据@ControllerAdvice是一个全局数据处理组件,因此也可以在@ControllerAdvice中配置全局数据,使用@ModelAttribute注解进行配置,代码如下: 运行测试结果:  ......
  • Springcloud学习笔记67--springboot 整合 任务调度框架Quartz
    1.背景定时任务Job的作业类中无法注入Service等由Spring容器所管理的Bean。例如下面这种情况,TaskCronJobService就无法成功注入。importjava.util.Iterator;importjavax.annotation.Resource;importorg.quartz.Job;importorg.quartz.JobExecutionContext;importor......
  • springboot集成@DS注解实现数据源切换(转载)
    springboot集成@DS注解实现数据源切换启用@DS实现数据源切换POM内添加核心jar包yml配置"核心"-使用@DS注解最后启用@DS实现数据源切换POM内添加核心jar包 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-start......