spring源码系列04-refresh方法分析-BeanFactoryPostProcessor的执行

上一篇中分析了ClassPathXmlApplicationContext的启动过程的第一部分,内部BeanFactory的创建过程,这节接着来看下一部分,还是看refresh方法。

上一节分析了refresh中的 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

refresh源码

public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");

			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
            //创建内部BeanFactory
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
             //一些准备工作
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
                 //空方法,供子类实现
				postProcessBeanFactory(beanFactory);

				StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
				// Invoke factory processors registered as beans in the context.
                //执行BeanFactoryPostProcessor
				invokeBeanFactoryPostProcessors(beanFactory);

				...省略其余
			}

			catch (BeansException ex) {
				//省略
			}

			finally {
				//省略
			}
		}
	}

接着往下看,

postProcessBeanFactory在AbstractApplicationContext中是一个空方法,供子类实现的,子类可以在这个方法中对内部的beanFactory进行一些处理,ClassPathXmlApplicationContext中并没有实现此方法。

但如果只是为了对beanFactory做一些处理而去继承现有的容器类自定义自己的容器,有点太不方便了。所以spring还提供了BeanFactoryPostProcessor这个接口来提供扩展功能对beanFactory进行处理。

refresh方法中接下来的 invokeBeanFactoryPostProcessors(beanFactory);就是在执行已经添加到spring容器中的BeanFactoryPostProcessor

一、BeanFactoryPostProcessor介绍

这个接口又被叫做后处理器

下面是BeanFactoryPostProcessor的源码

public interface BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean factory after its standard
	 * initialization. All bean definitions will have been loaded, but no beans
	 * will have been instantiated yet. This allows for overriding or adding
	 * properties even to eager-initializing beans.
	 * @param beanFactory the bean factory used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;

}

一个简单的接口,其中只有一个postProcessBeanFactory方法,从源码的注释也可以看出来这个接口的作用就是

对ApplicationContext容器中的BeanFactory进行处理,在还没有对任何Bean进行实例化之前。

spring提供了许多这个接口的实现类,其中有两个的功能大家应该是比较熟悉的,

PropertySourcesPlaceholderConfigurer : 这个processor用来对xml配置文件中导入的properties文件进行解析,并替换bean定义中的占位符

	<bean id="person" class="com.lyy.vo.Person">
        <property name="name" value="${myname}"/>
        <property name="age" value="${myage}"/>
    </bean>

    <context:property-placeholder location="classpath*:test.properties"></context:property-placeholder>

ConfigurationClassPostProcessor :基于注解配置spring时,用来解析配置类。

以上描述的这两种功能,就是通过这两个实现类的postProcessBeanFactory方法实现的。ApplicationContext容器在启动的时候,通过refresh方法中invokeBeanFactoryPostProcessors(beanFactory);会执行提前配置到

内部benFactory中的BeanFactoryPostProcessor实现类,这样就实现了对应的功能。

二、AbstractApplicationContext#invokeBeanFactoryPostProcessors方法详解

先来看下AbstractApplicationContext#invokeBeanFactoryPostProcessors的源码

/**
	 * Instantiate and invoke all registered BeanFactoryPostProcessor beans,
	 * respecting explicit order if given.
	 * <p>Must be called before singleton instantiation.
	 */
	protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		//重点内容
        PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

		// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
		// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
		if (!NativeDetector.inNativeImage() && beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}
	}

这里的第一句是重点,通过PostProcessorRegistrationDelegate这个类来执行BeanFactoryPostProcessors。

PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors接收两个参数,第一个是容器内部的

beanFactory,第二个参数接收一个List<BeanFactoryPostProcessor>,所以通过方法调用getBeanFactoryPostProcessors()来获取,看看这个方法的源码

     /**
	 * Return the list of BeanFactoryPostProcessors that will get applied
	 * to the internal BeanFactory.
	 */
	public List<BeanFactoryPostProcessor> getBeanFactoryPostProcessors() {
		return this.beanFactoryPostProcessors;
	}

可以看到返回的是AbstractApplicationContext 类中的成员变量beanFactoryPostProcessors

	/** BeanFactoryPostProcessors to apply on refresh. */
	private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

那么这个变量是在什么时候赋值的呢?

如果直接这样去使用容器

ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");

这个变量是没有值的,此时PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors执行的是在配置文件中配置的后处理器。如果想要让这个变量有值,可以这样去使用容器。

public static void main(String[] args) {
        ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext();
        // 创建BeanFactoryPostProcessor的实例
        BeanFactoryPostProcessor processor = new MyBeanFactroyPostProcessor();
        //调用AbstractApplicationContext.addBeanFactoryPostProcessor来添加
        app.addBeanFactoryPostProcessor(processor);
        app.setConfigLocation("applicationContext.xml");
        app.refresh();
        Person person = app.getBean(Person.class);
        System.out.println(person);
    }

先手动添加processor,再手动调用refresh,当然实际中很少这样去调用,通常采用的是把后处理器配置到spring容器中,也就是在配置文件中当做一个普通的bean来进行配置。

<bean id="person" class="com.lyy.vo.Person">
    </bean>

    <bean class="com.lyy.vo.processor.MyBeanFactroyPostProcessor"/>

那么这种情况下这个PostProcessor是如何被执行的呢?这就需要去看下

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors这个方法了。

三、PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors方法详解

这个方法整体就是在执行BeanFactoryPostProcessor的实现类,这些实现类会被以bean的形式配置在spring容器中。这个方法的源码比较长,但源码注释写的很好,完整描述了这个方法是如何执行的,可以概括成下边的步骤。

执行传进来的第二个参数 beanFactoryPostProcessors

执行BeanDefinitionRegistryPostProcessor#postProcessBeanDefinitionRegistry

执行BeanDefinitionRegistryPostProcessor#postProcessBeanFactory

执行BeanFactoryPostProcessor#postProcessBeanFactory

执行的时候会根据是否实现了某些接口来决定执行的先后顺序。

这里就引出了一个新接口BeanDefinitionRegistryPostProcessor,它是BeanFactoryPostProcessor的子接口,对这个接口的功能进行了扩展,从名字看它就是为了动态的注册bean到spring容器中

public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor {

	/**
	 * Modify the application context's internal bean definition registry after its
	 * standard initialization. All regular bean definitions will have been loaded,
	 * but no beans will have been instantiated yet. This allows for adding further
	 * bean definitions before the next post-processing phase kicks in.
	 * @param registry the bean definition registry used by the application context
	 * @throws org.springframework.beans.BeansException in case of errors
	 */
	void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException;

}

所以概括下上边的步骤,就是先处理传进来的参数,再执行子接口BeanDefinitionRegistryPostProcessor的方法,然后再执行子接口继承自父接口的方法,最后在执行直接实现了父接口的processor的方法。经过这一些步骤,就完成了对 BeanFactoryPostProcessor这个扩展机制的执行。

注意点

这里不贴源码,先思考一个问题,针对后处理器,我们配到配置文件中的是bean的描述信息,而要执行一个类的实例方法,你必须有一个对象才能执行对吧,那么上边这个PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors在执行后处理器的方法的时候,是从哪里来的对象的呢?带着这个问题看下方法源码,会发现这么一段代码

// First, invoke the BeanDefinitionRegistryPostProcessors that implement PriorityOrdered.
			String[] postProcessorNames =
					beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
			for (String ppName : postProcessorNames) {
				if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
					processedBeans.add(ppName);
				}
			}

这里的beanFactory.getBeanNamesForType方法会拿到配置到beanFactory里的所有指定类型的bean名称,然后

beanFactory.getBean方法会根据名称和类型去beanFactory里拿对象,这个拿对象的过程实际上就是在创建bean,如果当前没有就会去创建一个,如果有就直接返回已存在的。在这里还在启动容器的第一个阶段,beanFactory里一个bean都没有,当然是去要创建新的了。顺便说一句,refresh方法接着往下走到创建单例bean的时候,也是针对每一个bean名称去调用getBean方法来创建bean的,这个后边再仔细看。

最后再说一句这个方法的源码注释很全,也比较好理解,大家可以自己仔细研究下,相信会有不少的收获。

四、总结

上边的内容总结起来就是从AbstractApplicationContext#refresh开始,跳转到

AbstractApplicationContext#invokeBeanFactoryPostProcessors,再跳转到

PostProcessorRegistrationDelegate#invokeBeanFactoryPostProcessors

这个方法内部会从spring容器内部的beanFactroy中获取所有已配置的BeanFactoryPostProcessor接口和它的子接口BeanDefinitionRegistryPostProcessor类型的bean,然后执行对应的方法。