4
2
0
2

Spring源码理解

一、BeanFactoryFactoryBean区别

1.1 BeanFactory

- BeanFactory是一个负责生产和管理bean的一个工厂类(接口)。
- 在Spring中,BeanFactory是IOC容器的核心接口。职责:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
- 通过getBean()方法,传入参数 --> bean的名称或者类型,便可以从Spring容器中来获取bean。
- BeanFactory是用于访问Spring容器的根接口,是从Spring容器中获取Bean对象的基础接口,提供了IOC容器最基本的形式,给具体的IOC容器的实现提供了规范。
- BeanFactory只是个接口,并不是IOC容器的具体实现,Spring容器给出很多种BeanFactory的扩展实现。如: `DefaultListableBeanFactory`、`XmlBeanFactory`、`ApplicationContext`等。

BeanFactory的类图

image

image

- 从类图中可以看出来,我们常用的ApplicationContext就是一个BeanFactory.
- ApplicationContext接口:由BeanFactory接口派生而来,ApplicationContext包含BeanFactory的所有功能,还提供了以下更多的功能:
 - 1.MessageSource:提供国际化的消息访问
 - 2.资源访问,如URL和文件
 - 3.事件传播
- 比较BeanFactory,通常建议优先使用ApplicationContext。

1.2 FactoryBean

1. 什么是 FactoryBean

- 和BeanFactory一样,也是一个接口
- FactoryBean是为IOC容器中的Bean的实现提供了更加灵活的方式,FactoryBean在IOC容器的基础上,给Bean的实现加上了一个简单工厂模式和装饰模式。
- Spring提供的FactoryBean工厂类接口,`用户可以通过实现该接口`,然后在 `getObject()` 方法中来灵活配置,来定制实例化Bean的逻辑。
- 从Spring3.0开始,FactoryBean开始支持泛型,即接口声明改为 `FactoryBean<T>` 的形式。
- 从beanFactory及其实现类的 `getBean()`方法中获取到的Bean对象,实际上是 FactoryBean的 `getObject()`方法创建并返回的Bean对象,而不是FactoryBean本身。

2. FactoryBean的源码

public interface FactoryBean<T> {

	/**
	 * 可以在beandefinition上设置的属性的名称,这样当不能从工厂bean类中推导出对象类型时,工厂bean就可以发出信号
	 */
	String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";

	@Nullable
	T getObject() throws Exception;

	@Nullable
	Class<?> getObjectType();

	default boolean isSingleton() {
		return true;
	}
}

1. getObject()方法

- getObject(): 返回Bean对象
- 当通过getBean()方法获取到一个Bean时,返回的并不是xxFactoryBean本身,而是其创建的Bean对象
- 如果要获取xxFactoryBean对象本身,就在getBean()参数前面添加一个 `&`来获取,即:getBean(&BeanName);

例如:

image

image

- 从BeanFactory及其实现类的getBean()方法中获取到的Bean对象,实际上是 `FactoryBean`的`getObject()`方法创建并返回的Bean对象,而不是 `FactoryBean`本身

2. getObjectType(): 返回的是Bean的对象类型

3. isSingleton(): 是否是单例对象, true是单例, false是非单例

3. FactoryBean使用场景

- FactoryBean 用来生成某一类型Bean的实例,它最大的一个作用是:可以让我们自定义Bean的创建过程。
- 比如说:有一些同属于某一类型的Bean对象需要被创建,但是它们自己有各自的特点,我们只需要把它们的特点 `注入FactoryBean中`,就可以生产出属于该类型的实例。

4. 示例代码

实现FactoryBean,功能:用来自定义一个Bean对象(Car)的创建过程

1. 新建一个 Car实体类

/**
 * @Author: codertl
 * @Description:
 * @Date: 2023/1/31
 */
@Data
public class Car {

    /**
     * 汽车品牌
     */
    private String carBrand;

    /**
     * 汽车价格
     */
    private String carPrice;
}

2. 新建一个自己的FactoryBean实现,自定义Car对象的生成过程

/**
 * @Author: codertl
 * @Description:
 * @Date: 2023/1/31
 */
@Component
public class MyFactoryBean01 implements FactoryBean<Car> {

    /**
     * 当通过getBean获取一个FactoryBean时,返回的并不是FactoryBean本身,而是其创建的对象;
     * 如果要获取FactoryBean对象本身,请在参数前面加一个&符号来获取。
     */
    @Override
    public Car getObject() throws Exception {
        Car car = new Car();
        car.setCarBrand("宝马");
        car.setCarPrice("900000");

        return car;
    }

    /**
     * 获取对象的类型
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }

    /**
     * 该Bean对象是否是单例模式
     * @return
     */
    @Override
    public boolean isSingleton() {
        return false;
    }
}

3. 测试

调用 getBean() 获取Bean对象

package com.example;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;

@SpringBootTest
class SpringSourceStudyApplicationTests {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    void test01() {
        // 调用 getBean() 获取Bean对象
        Object object = applicationContext.getBean("myFactoryBean01");
        System.out.println("该对象的类型 = " + object);
    }
    
}

打印结果:

image

获取xxxFactoryBean 对象本身

package com.example;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;

@SpringBootTest
class SpringSourceStudyApplicationTests {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    void test01() {
        // 调用 getBean() 参数前面添加& ,获取 MyFactoryBean01 对象本身
        Object object = applicationContext.getBean("&myFactoryBean01");
        System.out.println("该对象的类型 = " + object);
    }

}

打印结果:

image

获取Car的信息

package com.example;

import com.example.pojo.Car;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;

@SpringBootTest
class SpringSourceStudyApplicationTests {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    void test01() {
        // 调用 getBean() 获取Bean对象
        Object object = applicationContext.getBean("myFactoryBean01");
        System.out.println("该对象的类型 = " + object);

        // 将该Bean对象转成 Car
        Car car = (Car) object;
        
        // 打印car对象信息
        System.out.println("car.getCarBrand() = " + car.getCarBrand());
        System.out.println("car.getCarPrice() = " + car.getCarPrice());
    }

}

打印结果:

image

先获取xxxFactoryBean对象本身,再获取Car对象

package com.example;

import com.example.factory.MyFactoryBean01;
import com.example.pojo.Car;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;

import javax.annotation.Resource;

@SpringBootTest
class SpringSourceStudyApplicationTests {

    @Autowired
    private ApplicationContext applicationContext;

    @Test
    void test01() throws Exception {
        // 调用 getBean() 参数前面添加& ,获取 MyFactoryBean01 对象本身
        Object object = applicationContext.getBean("&myFactoryBean01");
        System.out.println("该对象的类型 = " + object);

        // 转为 MyFactoryBean01对象本身
        MyFactoryBean01 myFactoryBean01 = (MyFactoryBean01) object;

        // 获取Car对象
        Car car = myFactoryBean01.getObject();
        System.out.println("打印car对象信息 = " + car);

        // 获取对象类型
        Class<?> objectType = myFactoryBean01.getObjectType();
        System.out.println("打印对象类型 = " + objectType);

        // 获取Car对象是否是单例对象
        boolean singleton = myFactoryBean01.isSingleton();
        System.out.println("打印Car对象是否是单例对象 = " + singleton);

    }

}

打印结果:

image

二、BeanFactory深入理解

- Spring本质是一个bean工厂(beanFactory)或者说bean容器。
- 在生产bean的过程中,需要解决bean之间的依赖问题,才引入了 `依赖注入(DI)`这种技术,依赖注入是BeanFactory生产bean时,为了解决bean之间的依赖的一种技术。
- 在没有beanfactory之前,我们都是通过new来实例化各种对象,现在各种对象bean的生产都是通过beanFactory来实例化,所以beanFactory在实例化bean的过程中(实例化bean的各个阶段),做一些额外的处理
- BeanFactory会在bean的生命周期的各个阶段中对bean进行各种管理,并且spring将这些阶段通过各种接口暴露给我们,让我们可以对bean进行各种处理,我们只要让bean实现对应的接口,那么spring就会在bean的生命周期调用我们实现的接口来处理该bean。

Bean在实例化之前,必须实在bean容器启动之后,所以就有了两个阶段:

  1. bean容器的启动阶段
  2. 容器中bean的实例化阶段

2.1 Bean容器的启动

1. 读取bean的各种定义

- 首先是读取bean的xml配置文件,然后解析xml文件中的各种bean的定义,将xml文件中的每一个<bean/>元素分别转换成 `BeanDefinition`对象,其中保存了从配置文件中读取到该bean的各种信息
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
		implements BeanDefinition, Cloneable {


	@Nullable
	private volatile Object beanClass;

	@Nullable
	private String scope = SCOPE_DEFAULT;

	private boolean abstractFlag = false;

	@Nullable
	private Boolean lazyInit;

	private int autowireMode = AUTOWIRE_NO;

	private int dependencyCheck = DEPENDENCY_CHECK_NONE;

	@Nullable
	private String[] dependsOn;

	private boolean autowireCandidate = true;

	private boolean primary = false;

	private final Map<String, AutowireCandidateQualifier> qualifiers = new LinkedHashMap<>();

	@Nullable
	private Supplier<?> instanceSupplier;

	private boolean nonPublicAccessAllowed = true;

	private boolean lenientConstructorResolution = true;

	@Nullable
	private String factoryBeanName;

	@Nullable
	private String factoryMethodName;

	@Nullable
	private ConstructorArgumentValues constructorArgumentValues;

	@Nullable
	private MutablePropertyValues propertyValues;

	private MethodOverrides methodOverrides = new MethodOverrides();

	@Nullable
	private String initMethodName;

	@Nullable
	private String destroyMethodName;
}
- beanClass: 保存bean的class属性
- scope: 保存bean是否单例
- abstractFlag: 保存该bean是否抽象
- lazyInit: 保存是否延迟初始化
- autowireMode: 保存是否自动装配
- dependencyCheck: 保存是否依赖检查
- dependsOn: 保存该bean依赖哪些bean(这些bean必须提前初始化)
- constructorArgumentValues: 保存通过构造器注入的依赖
- propertyValues: 保存通过setter方法注入的依赖
- factoryBeanName和factoryMethodName: 用于FactoryBean,也就是工厂类型的bean
- initMethodName和destroyMethodName: 分别对应 bean的init-method 和 destroy-method 属性,比如:

image

读取配置文件之后,会得到很多 BeanDefinition对象。

2. 将Bean注册到BeanFactory

通过BeanDefinitionRegistry注册

public interface BeanDefinitionRegistry extends AliasRegistry {
    // 注册beanDefinition
	void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException;
    
    // 删除beanDefinition
	void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
   
    // 获取beanDefinition
	BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    // 根据bean名称 是否在beanDefinition中存在
	boolean containsBeanDefinition(String beanName);
    
    // 获取beanDefinition中所有的名字
	String[] getBeanDefinitionNames();
	
    // 获取 beanDefinition的总数
	int getBeanDefinitionCount();

    // 根据bean名称判断是否被使用
	boolean isBeanNameInUse(String beanName);
}

BeanFactory的实现类,需要实现BeanDefinitionRegistry 接口

public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    
    /** bean定义对象的映射,以bean名称为键 */
	private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    
    //---------------------------------------------------------------------
	// BeanDefinitionRegistry接口的实现
	//---------------------------------------------------------------------

	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
			throws BeanDefinitionStoreException {

		if (beanDefinition instanceof AbstractBeanDefinition) {
			// ..........
			this.beanDefinitionMap.put(beanName, beanDefinition);
		}
		else {	
            // ........
	    }
}
- 我们看到 BeanDefinition 被注册到了 DefaultListableBeanFactory, 保存在它的一个 ConcurrentHashMap 中。
- 将 BeanDefinition注册到了 BeanFactory之后,在这里Spring为我们提供了一个扩展的接口,允许我们通过实现该接口 BeanFactoryPostProcessor 来插入我们自定的代码
@FunctionalInterface
public interface BeanFactoryPostProcessor {
	/**
     * 在标准初始化后修改应用程序上下文的内部bean工厂。所有的bean定义都将被加载,但是还没有bean被实例化。这允许重写或添加属性,甚至可以直接初始化bean。
     * 形参: beanFactory—应用程序上下文使用的bean工厂 
     *  抛出: BeansException—在错误的情况
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
- 典型的例子就是: `PropertyResourceConfigurer`,我们一般在配置数据库的 dataSource时使用到的占位符的值(在xml中配置的${url}),就是它注入进去的:
public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
		implements BeanFactoryPostProcessor, PriorityOrdered {
 
    /**
     * 合并、转换和处理给定bean工厂的属性
     */
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		try {
			Properties mergedProps = mergeProperties();

			// Convert the merged properties, if necessary.
			convertProperties(mergedProps);

			// Let the subclass process the properties.
			processProperties(beanFactory, mergedProps);
		}
		catch (IOException ex) {
			throw new BeanInitializationException("Could not load properties", ex);
		}
	}
    
    /**
	 * 将给定的属性应用到给定的BeanFactory
	 * @param 应用程序上下文使用的beanFactory
	 * @param 要应用的属性
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	protected abstract void processProperties(ConfigurableListableBeanFactory beanFactory, Properties props)
			throws BeansException;
}
- processProperties(ConfigurableListableBeanFactory beanFactory, Properties props);在子类`PropertyPlaceholderConfigurer`中实现的功能就是将 {$jdbc_username}等等这些替换成实际值。
<bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" 
         init-method="init" destroy-method="close">
        <property name="url" value="${jdbc_url}" />
        <property name="username" value="${jdbc_username}" />
        <property name="password" value="${jdbc_password}" />
</bean>
/**
 * 访问给定bean工厂中的每个bean定义,并尝试替换${…}属性占位符,其值来自给定属性
 */
@Override
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props)
      throws BeansException {

   StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props);
   doProcessProperties(beanFactoryToProcess, valueResolver);
}

2.2 Bean的实例化阶段

- 实例化阶段:主要通过反射或者Cglib对bean进行实例化,在这个阶段Spring又给我们暴露了很多的扩展点

1. 各种Aware接口

- 比如: BeanFactoryAware、MessageSourceAware、ApplicationContextAware
- 对于实现了这些Aware接口的bean,在实例化bean时Spring会帮我们注入对应的: BeanFactory、MessageSource、ApplicationContext的实例:
public interface BeanFactoryAware extends Aware {

	/**
	 * 向bean实例提供所属工厂的回调。 
	 * 在普通bean属性填充之后,但在初始化回调(如InitializingBean.afterPropertiesSet()或自定义初始化方法之前调用)
	 * beanFactory: 拥有beanFactory(从不为空)。bean可以立即调用工厂上的方法
	 */
	void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
public interface MessageSourceAware extends Aware {

	/**
	 * 设置运行此对象的MessageSource。 
	 * 在填充普通bean属性之后,但在初始化回调之前(如InitializingBean的afterPropertiesSet或自定义初始化方法)调用。     
     * 在ApplicationContextAware的setApplicationContext之前调用。
     * messageSource: 该对象使用的消息源
	 */
	void setMessageSource(MessageSource messageSource);
}
public interface ApplicationContextAware extends Aware {

	/**
     * 设置该对象运行的ApplicationContext。
     * 通常,此调用将用于初始化对象。
     * 在填充普通bean属性之后,但在初始化回调(如org.springframework.beans.factory.InitializingBean.afterPropertiesSet()或自定义初始化方法之      * 前调用。
	 */
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}

2. BeanPostProcessor接口

- 实现了 BeanPostProcessor接口的bean,在实例化bean时Spring会帮我们调用接口中的方法:
public interface BeanPostProcessor {

	/**
     * 在任何bean初始化回调(如InitializingBean的afterPropertiesSet或自定义初始化方法)之前,
     * 将这个BeanPostProcessor应用到给定的新bean实例。
     * bean将已经被属性值填充。返回的bean实例可能是原始bean实例的包装器。 默认实现按原样返回给定的bean。
     * @param bean 新的bean实例
     * @param beanName bean的名称
     * @return 要使用的bean实例,可以是原始的,也可以是封装后的;如果为null,则不会调用后续的BeanPostProcessors
     * @throws BeansException
     */
	@Nullable
	default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}

	/**
     * 在任何bean初始化回调(如InitializingBean的afterPropertiesSet或自定义初始化方法)之后
     * 将这个BeanPostProcessor应用到给定的新bean实例。
     * bean将已经被属性值填充。
     * 返回的bean实例可能是原始bean实例的包装器。 
     * 对于FactoryBean,这个回调将同时为FactoryBean实例和由FactoryBean创建的对象调用(从Spring 2.0开始)。
     * 后处理程序可以通过相应的bean instanceof FactoryBean检查来决定是否应用于FactoryBean或已创建的对象,或者两者都应用。 该
     * 回调也将在由InstantiationAwareBeanPostProcessor触发的短路后被调用。
     * 方法,与所有其他BeanPostProcessor回调相反。 默认实现按原样返回给定的bean。
     * @param bean 新的bean实例
     * @param beanName bean的名称
     * @return 要使用的bean实例,可以是原始的,也可以是封装后的;如果为null,则不会调用后续的BeanPostProcessors
     * @throws BeansException
     */
	@Nullable
	default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		return bean;
	}
}
- `postProcessBeforeInitialization`: 方法在 `InitializingBean`接口的 `afterPropertiesSet`方法之前执行
- `postProcessAfterInitialization`: 方法在 `InitializingBean`接口的 `afterPropertiesSet`方法之后执行

3. InitializingBean接口

- 实现了 InitializingBean 接口的bean,在实例化bean时Spring会帮我们调用接口中的方法:
public interface InitializingBean {

	/**
     * 在包含它的BeanFactory设置了所有bean属性并满足了BeanFactoryAware、ApplicationContextAware等之后,由它调用。 
     * 此方法允许bean实例在设置完所有bean属性后执行其总体配置验证和最终初始化
     * @throws Exception
     */
	void afterPropertiesSet() throws Exception;
}

4. DisposableBean接口

- 实现了 DisposableBean 接口的bean,在该bean死亡时Spring会帮我们调用接口中的方法:
public interface DisposableBean {

	/**
     * 在销毁bean时由包含bean的BeanFactory调用
     * @throws Exception
     */
	void destroy() throws Exception;
}
- `InitializingBean接口` 和 `DisposableBean`接口对应<bean />的 init-method 和 destory-method属性。
- <bean name="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close" />
- 所以在Spring初始化 DataSource 这个bean之后会调用 DruidDataSource的init方法
// 基本就是初始化数据库连接池
public void init() throws SQLException {
      // .........
}
- 在 DataSource 这个bean死亡时会调用 DruidDataSource的close方法:
// 关闭连接池中的连接
public void close() {
    // .....
}
- 另外注解 `@PostConstruct` 和 `@PreDestroy` 也能达到 InitializingBean接口 和 DisposableBean接口的效果。

2.3 总结

- Spring容器接管了bean的实例化,不仅仅是通过依赖注入打到了松耦合的效果,同时给我们提供了各种的扩展接口,来在bean的生命周期的各个时期插入我们自己的代码:
 - 0.BeanFactoryPostProcessor接口(在容器启动阶段)
 - 1.各种的Aware接口
 - 2.beanPostProcessor接口
 - 3.initializingBean接口(@PostConstruct, init-method)
 - 4.DisposableBean接口(@PreDestroy, destory-method)

三、Bean的生命周期

3.1 Bean生命周期的基本流程

1. 实例化 (通过反射创建对象)
2. 属性填充 (属性值非自动装配)
3. 初始化 (如:数据源复制、校验属性)
4. 销毁 (ioc容器销毁关闭、关闭数据源)

3.2 流程细节

1. 初始化方法和销毁方法

public class Book {
    public void init(){
        System.out.println("初始化方法");
    }
    public void destroy(){
        System.out.println("销毁方法");
    }
}

xml方式

<bean id="book" class="com.xc.enity.Book" init-method="init" destroy-method="destroy" />

@Bean的方式

@Bean(initMethod = "init",destroyMethod = "destroy")
public Book book(){
    return new Book();
}

InitializingBean (初始化接口),DisposableBean(销毁接口) 实现其方法即可

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

声明式注解 @PostConstruct (初始化) 、@PreDestory (销毁)

结论:

- 初始化销毁顺序: 声明式 -> 接口式 -> 自定义式
- 单例:容器关闭时销毁。
- 多例:容器关闭时不销毁。

2. BeanPostProcessor后置处理器

- 在所有初始化方法前后执行
- `spring所有bean初始化前后都会执行后置处理器`
- 可以定义多个后置处理器,一旦返回null,则跳过之后的处理器往下执行了
- 可以返回bean,也可以返回bean的包装对象 (aop动态代理)
/**
 * @Author: codertl
 * @Description:
 * @Date: 2023/1/31
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("前置处理器");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("后置处理器");
        return bean;
    }
}

3. xxAware接口

spring Aware 目的为了让bean获取spring容器中的服务。

- BeanNameAware: 获取容器中bean名称
- BeanFactoryAware: 获取BeanFactory容器
- ApplicationContextAware: 获取应用上下文
- `属性填充后,后置处理器前执行`
package com.example;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class BeanUtil implements ApplicationContextAware {
    private ApplicationContext context;
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
    }
    public Object getBean(String beanName){
        return context.getBean(beanName);
    }
}

源码解析:

class ApplicationContextAwareProcessor implements BeanPostProcessor {}

image

3.3 总结

1. 实例化
2. 属性填充
3. 三种方式初始化
4. 处理Aware接口
5. BeanPostProcessor子接口的处理,如 `AutowiredAnnotationBeanPostProcessor`扫描`@autowired`注解,完成自动注入。
6. 处理各种后置处理器,在初始化方法后的后置方法中会根据情况包装代理类,即AOP
7. 销毁

四、Spring后置处理器

后置处理器有两种

1. bean的后置处理器: 这种处理器会对容器中的bean进行后处理,对bean进行增强。
2. 容器的后置处理器: 针对IOC容器的后处理,对容器功能增强。

4.1 bean后置处理器

- Bean的后置处理器是一种特殊的bean,主要负责容器中的其他bean执行后处理,如代理类的生成等,这种bean称为bean的后置处理器。
- 它会在bean创建成功后队bean进行增强处理。
- bean的后置处理器必须实现 `BeanPostProcessor`接口,同时实现两个方法:
 - 1.`postProcessBeforeInitialization(Object bean, String beanName)`:前置处理,第一个参数是将进行处理的bean对象,第二个参数为该bean的id
 - 2.`postProcessAfterInitialization(Object bean, String beanName)`: 后置处理
- bean后置处理器在容器中注册后,会自动启动,容器中的每个bean在创建时会自动执行后置处理器,Bean后置处理器两个方法执行回调的时机如下图:

image

- 在Bean注入依赖关系之后,bean初始化过程中,进行回调 `BeanPostProcessor`接口的 `postProcessBeforeInitialization` 和 `postProcessAfterInitialization`两个方法,对bean进行增强。

bean的初始化过程如下:

- 容器启动
- 收集 BeanDefinition (解析xml定义的bean信息)
- 实例化之前可以对bean做一个启动动作 (Spring提供了 InstantiationAwareBeanPostProcessor的postProcessBeforeInstantion()进行扩展)
- 根据加载的BeanDefinition信息通过反射实例化bean
- 实例化首先判断是否设置了 `super`对象,如果有则调用`super`的get得到父类对象,根据 BeanDefinition的信息确认bean实例化的方式通过工厂bean进行实例化或构造方法
- 实例化后赋值之前 MergeBeanDefinitionPostProcessor的 postProcessMergedBeanDefinition() 进行加工(扩展)
- 为对象属性赋值
- 赋值之后也有扩展点 InstantiationAwareBeanPostProcessor的 postProcessAfterInstantiation()
- 进行依赖注入 (循环依赖)
- 处理属性如: @Autowired、@Resource、@Value 等注解,通过上面的扩展点实现
- 完成属性赋值后,Spring执行回调
- 进行初始化,初始化之前提供了扩展点: BeanPostProcessor的postProcessorBeforeInitialization方法,可以对完成依赖注入的bean进行增强处理
- 初始化,查看是否实现初始化方法,调用初始化方法
- 初始化后spring提供了扩展点: BeanPostProcessor的postProcessorAfterInitialization方法进行扩展,可以bean进行最终的增强处理。

总结:Spring中的AOP就是基于初始化后实现的,初始化后返回的对象才是最终的对象

【注意】:如果使用BeanFactory作为Spring容器,必须手动注册bean后置处理器才能生效。

4.2 容器的后置处理器

- 容器后置处理:负责容器本身的后置处理,必须实现 `BeanFactoryPostProcessor`接口,并实现方法 `postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)`对容器进行扩展。

五、SpringMvc的工作流程

image

- 浏览器的请求首先会经过 SpringMVC 里面的核心控制器 DispatcherServlet,它负责对请求进行分发到对应的 Controller。
- Controller 里面处理完业务逻辑之后,返回 ModeAndView。
- 然后 DispatcherServlet 寻找一个或者多个 ViewResolver 视图解析器,找到ModeAndView 指定的视图,并把数据显示到客户端。

六、Spring如何解决循环依赖

Spring的依赖注入方式分为:setter构造器注入。那么Spring可以解决掉setter类型的依赖注入,构造器形式的是不可以的。

回到spring的单例与多例模式,多例模式下的依赖注入也是解决不掉的。所以我们关注的范围为setter注入形式的循环依赖解决方案。

前置知识:SpringBean的生命周期概括为4大阶段:实例化->属性赋值->初始化->销毁

@Component
public class A {

    @Autowired
    private B b;
}

@Component
public class B {

    @Autowired
    private A a;
}

我们去定义这样两个类,一个是A,一个是B。但是A中有一个属性引用了B,B中有一个属性引用了A。那么这就是经典的循环依赖,形成一个圈,扩展到多个Bean,也可以是A依赖B,B依赖C,C依赖A。这样也是依赖循环的场景。

再理解一下之前说的声明周期,实例化A的时候,我们去属性赋值B。于是去找到B,B又进行实例化,B属性赋值A。于是A又找B,于是产生了死循环。

接下来看一下Spring是如何处理的。

/** Cache of shareable singleton objects: bean name to bean instance. */
/** 一级缓存:用于存放完全初始化好的 bean */
private final Map<String, Object> singletonObjects = new HashMap<>();

/** Cache of early singleton objects: bean name to bean instance. */
/** 二级缓存:存放原始的 bean 对象(尚未填充属性),用于解决循环依赖 */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);

/** Cache of singleton factories: bean name to ObjectFactory. */
/** 三级缓存:存放 bean 工厂对象,用于解决循环依赖 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

1. 一级缓存

- 假设没有三级缓存,只有一级缓存,那么会怎样处理呢?
 - 首先A对象进行实例化,A要进行属性填充B。但是B还没有创建,于是开始B进行实例化,同样的B也要进行属性填充,发现它需要A。然而我们的一级缓存的Map里面还没有A,所以它又创建A,于是就产生了死循环。循环往复,最后栈溢出。
- 那么我们能不能对A不进行属性填充,直接放到一级缓存中去,那不就行了吗?
 - 这样的话就会造成map里面的存的A是个假A,缺胳膊少腿,当真正用到它的时候,会出现空指针异常。而且我们的一级缓存规定是`存完全初始化好的bean`。给我们的程序进行使用。那么现在就应该知道了,只有一级缓存行不通。

2. 二级缓存

- 我们知道一级缓存的问题:在于它没法去存储半成品的对象,也就是未完全初始化好的对象,那么spring搞了一个二级缓存,来存这个东西。专门存储开始创建但是不完整的对象。
- 我们把一级缓存叫map1,二级缓存叫做map2.
- 首先我们还是从实例化A开始,注意这个地方,我们实例化后,还没有进行属性填充的时候,就把A对象的引用放入到了map2备用。然后进行属性填充,A去填充B,发现B没有实例化,于是B同样实例化后,把自己的半成品放入到map2中。B开始进行填充,发现Map1中没有A,又去Map2中寻找,发现map2中有。于是B直接拿到map2中的A使自己变得非常完整。这个时候B就把自己放入Map1中。并把Map2的半成品删除了。回到刚才A的阶段,A发现Map1中已经有B了。那么A也就完成了属性的创建。于是双方都完成了自己的创建。这就是二级缓存解决的问题。

二级缓存已经完美解决了循环依赖的问题,那么为啥又弄了一个三级缓存呢?

- 主要是因为Spring的Aop机制所产生的代理对象的问题。
- 首先要了解一个前置:Spring的代理对象产生阶段是在`填充属性后`才进行的。
- 原理通过后置处理器 `BeanPostProcessor`来实现。如果说我们用二级缓存来解决,那么就要在属性填充的时候,将代理对象生成好,放入二级缓存。
- 那么就与我们spring对象生命周期相悖。所以这种方式方式不好,于是引入了三级缓存。

3. 三级缓存

- 我们发现一级和二级放的是对象,三级放的是创建对象的工厂。
- 三级缓存主要针对的是动态代理类型的对象,我们通过工厂在真正需要动态代理对象的时候才来获取,这样可以提升我们的一些性能,因为创建动态代理对象是一个消耗比较大的过程。
- 我们来看一下总过程,三级缓存是起到了什么作用。
- 首先我们还是进行实例化A对象,这个时候,我们要将A的ObjectFactory对象放入Map3中。
- 同样的继续进行属性填充,这个时候B还没创建,于是去创建B。那么实例化B的过程中,也是一样先把B的ObjectFactory放入Map3中。将B对象放入Map2。继续执行到B的属性填充,去获取A对象,而此时Map1中没有A,因为A还没有创建完成,我们则发现Map3中有A的ObjectFactory对象,那么我们通过ObjectFactory对象获取A的早期对象,然后将这个早期对象放入Map2中,同时删除Map3中的A,然后我们将A的引用给了B,那么同样的B对象这个时候也已经完整了。
- 接下来我们再把B放入Map1中,然后从Map3中删除B。这个时候B已经创建完成,A继续执行b的属性填充可以拿到B对象,这样A也完成,最后我们把A对象也放入了Map1,删除掉Map2中的A。于是循环依赖就此解决。
posted @ 2023-01-31 15:38  CoderTL  阅读(43)  评论(0编辑  收藏  举报