首页 > 编程语言 >Spring源码理解

Spring源码理解

时间:2023-01-31 15:45:51浏览次数:45  
标签:初始化 实例 Spring 理解 Bean 接口 bean 源码 public

一、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)`对容器进行扩展。

标签:初始化,实例,Spring,理解,Bean,接口,bean,源码,public
From: https://www.cnblogs.com/codertl/p/17079375.html

相关文章

  • 对IO输入输出的理解
    口诀:读书为输入流,写书为输出流结论:到内存的为输入流,出内存的为输出流InputStream:将数据读取到内存,所以为字节输入流Reader:将数据读取到内存,所以为字符输入流OutputSt......
  • spring 定时任务的 时间配置cron表达式
    单纯针对时间的设置规则org.springframework.scheduling.quartz.CronTriggerBean允许你更精确地控制任务的运行时间,只需要设置其cronExpression属性。一个cronExpression......
  • 【转载】【SSM】SpringBoot 统一功能处理,(*Spring 拦截器实现与原理)
    ✨1.用户登录权限效验1.1最初用户登录验证1.2SpringAOP用户统一登录验证的问题1.3Spring拦截器1. 自定义拦截器2.将自定义拦截器加入到系统配置1.4拦截器实......
  • 【转载】springboot上传+下载文件实例
     前言一次“上传文件”的点击蕴含着一轮请求,我们要做的就是针对每一次的请求进行i/o处理,并返回给前端用户 一.文件上传文件上传,也称为upload,是指将本地图片、视频......
  • 【转载】 spring 利用注解类添加日志到mysql
    一、前言我们写完一个项目,运维时,如果出现了bug,我们需要查看控制台的日志,但是那个日志无关方法太多,查找不是很方便,还有就是一个项目上线之后,我们需要记录谁操作了那些功能,......
  • SpringBoot集成webService
    我这里用的cxf框架来搭建webService服务我的SpringBoot版本为2.7.5查看项目springBoot版本的方法:1.写测试类,打印springBoot版本@Testvoidversion(){System.out.pr......
  • 扒一扒Bean注入到Spring的那些姿势,你会几种?
    大家好,我是三友~~这篇文章我准备来扒一扒Bean注入到Spring的那些姿势。其实关于Bean注入Spring容器的方式网上也有很多相关文章,但是很多文章可能会存在以下常见的问题......
  • 基于Spring Cache实现Caffeine、jimDB多级缓存实战
    作者:京东零售王震背景在早期参与涅槃氛围标签中台项目中,前台要求接口性能999要求50ms以下,通过设计Caffeine、ehcache堆外缓存、jimDB三级缓存,利用内存、堆外、jimDB缓存不......
  • 前端VUE+后端springboot实现导入返回excel校验结果demo
    vue代码<!--菜单导入对话框--><el-dialog:title="upload.title":visible.sync="upload.open":close-on-click-modal="false"width="400px"append-to-body>......
  • springboot 统一日志记录 - AOP日志
    参考学习:https://www.bilibili.com/video/BV1bf4y187KX/三步:1.使用日志注解。2.编写日志注解类。3.编写日志注解类的AOP实现。1.在需要记日志处,使用自定义的注解。pac......