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


    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,然后执行对应的方法。

  • 相关阅读:
    oracle11g dataguard部署指南
    扩展Oracle表空间
    ORACLE SQLloader详细语法
    Oracle Data Guard
    struts2学习(4)struts2核心知识III
    struts2学习(3)struts2核心知识II
    struts2学习(2)struts2核心知识
    struts2学习(1)struts2 helloWorld
    java单例模式等一些程序的写法....持续更新...
    峰Spring4学习(8)spring对事务的支持
  • 原文地址:https://www.cnblogs.com/chengxuxiaoyuan/p/16278689.html
Copyright © 2020-2023  润新知