• Spring源码系列 — 容器Extend Point(一)


    前言

    前文介绍了Spring中的BeanDefinition的细节,随着Spring的启动流程,这节我们介绍Spring的后续处理过程 — Spring的扩展点:

    • BeanFactoryPostProcessor - BeanFactory后置处理处理器
    • BeanPostProcessor - Bean后置处理器

    Spring扩展体系

    Spring框架的设计的优异自不用说,使用者应该都深有体会。作为应用开发者,通常需要扩展Spring的处理,但是不必实现ApplicationContext或者扩展其子实现,如:ClassPathXmlApplicationContext。Spring提供了多处容器扩展点,只要实现扩展点将其插入到Spring上下文中即可。开发者只需要关注自己扩展的逻辑,对于如何扩展完全是沙箱,不用关注,非常友好。

    上图展示了Spring的容器扩展体系,符合微内核 + 插件体系的设计。将ApplicationContext上下文作为Spring的内核,开放插件接口,只需要实现相应插件接口即可完成扩展,提升处理能力。

    BeanFactoryPostProcessor

    1.什么是BeanFactoryPostProcessor

    有时看接口有何种作用,具有什么能力的最好方式就是看javadoc:

    Allows for custom modification of an application context's bean definitions, adapting the bean property values of the context's underlying bean factory.
    Application contexts can auto-detect BeanFactoryPostProcessor beans in their bean definitions and apply them before any other beans get created.

    从javadoc中可以看出,BeanFactoryPostProcessor是用于自定义修改Bean定义,应用上下文可以自动检测上下文中的BeanFactoryPostProcessor,然后将其应用到其他的Bean定义上。

    BeanFactoryPostProcessor接口定义的能力:

    void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) 
    

    以ConfigurableListableBeanFactory作为方法参数,因为ConfigurableListableBeanFactory提供了获取BeanDefintion的能力。这样BeanFactoryPostProcessor的实现就可以自定义修改Bean定义。

    2.何处扩展及处理过程

    BeanFactoryPostProcessor的作用用于修改Bean定义,需要满足两点:

    1. Bean配置已经解析成Bean定义抽象并加载至BeanFactory中;
    2. 在Bean实例化之前触发,因为实例化后再修改Bean定义,没有任何意义;

    Spring中的实现也正如此,这里承接上文中详解的BeanDefinition,当所有的BeanDefinition载入进BeanFactory后,ApplicationContext上下文将提前实例化BeanDefinition中的BeanFactoryPostProcessor的定义,将其注册为ApplicationContext中的单例,用于后续的其他Bean实例化之前处理Bean定义。整个处理过程如下图:

    3.自动检测BeanFactoryPostProcessor

    在了解BeanFactoryPostProcessor是什么和处理过程后,接下来再看Spring中如何自动检测并唤醒BeanFactoryPostProcessor。

    Note:
    关于自动检测的机制非常多,如JAVA提供的SPI机制。但是BeanFactoryPostProcessor并不是使用该机制,因为对Spring上下文而言,一切皆是Bean。
    BeanFactoryPostProcessor也需要配置成Bean。

    @Override
    public void refresh() throws BeansException, IllegalStateException {
    	synchronized (this.startupShutdownMonitor) {
    		// Prepare this context for refreshing.
    		prepareRefresh();
    		// 前文介绍了这里的逻辑,资源的加载、Bean定义的加载
    		// Tell the subclass to refresh the internal bean factory.
    		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
    		// Prepare the bean factory for use in this context.
    		prepareBeanFactory(beanFactory);
    		try {
    			// 这里是一个扩展点,用于给上下文子类扩展,非应用扩展。上下文子类可以覆盖postProcessBeanFactory
    			// 用于定制上下文中的BeanFactory
    			// Allows post-processing of the bean factory in context subclasses.
    			postProcessBeanFactory(beanFactory);
    			// 主要负责Spring容器提前注册BeanFacotryPostProcessor并唤醒的逻辑
    			// Invoke factory processors registered as beans in the context.
    			invokeBeanFactoryPostProcessors(beanFactory);
    			// Register bean processors that intercept bean creation.
    			registerBeanPostProcessors(beanFactory);
    			// Initialize message source for this context.
    			initMessageSource();
    			// Initialize event multicaster for this context.
    			initApplicationEventMulticaster();
    			// Initialize other special beans in specific context subclasses.
    			onRefresh();
    			// Check for listener beans and register them.
    			registerListeners();
    			// Instantiate all remaining (non-lazy-init) singletons.
    			finishBeanFactoryInitialization(beanFactory);
    			// Last step: publish corresponding event.
    			finishRefresh();
    		}
    		catch (BeansException ex) {
    			... 省略
    		}
    		finally {
    			... 省略
    		}
    	}
    }
    

    refresh模板方法中的invokeBeanFactoryPostProcessors是本节讲述的重点。invokeBeanFactoryPostProcessors中的处理逻辑也非常单一:实例化BeanFacotryPostProcessor,并调用其实例执行Bean定义的定制逻辑。

    protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    	// 调用后置处理器注册委托器唤醒指定的BeanFactoryPostProcessor和BeanFactory中的BeanFactory的Bean定义
    	PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());
    	// 以下是处理load时进行aop织入处理,这里忽略
    	// Detect a LoadTimeWeaver and prepare for weaving, if found in the meantime
    	// (e.g. through an @Bean method registered by ConfigurationClassPostProcessor)
    	if (beanFactory.getTempClassLoader() == null && beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
    		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
    		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
    	}
    }
    

    PostProcessorRegistrationDelegate中是上下文对于后置处理的委托器,其中既包含BeanFactoryPostProcessor的后置处理,也包含BeanPostProcessor的注册。接下来主要分析invokeBeanFactoryPostProcessors的实现。

    Tips:
    在Spring中有一系列的排序和优先级接口,用于对于同类事物进行优先级和排序的设定。如:PriorityOrderedOrdered接口分别定义。Ordered抽象了排序能力,使其实现这具有优先级。而PriorityOrdered比Ordered具有更优先的级别。

    public static void invokeBeanFactoryPostProcessors(
    		ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
    	// 首先唤醒被给的beanFactoryPostProcessors
    	// Invoke BeanDefinitionRegistryPostProcessors first, if any.
    	Set<String> processedBeans = new HashSet<String>();
    	// 如果是BeanDefinitionRegistry实例
    	if (beanFactory instanceof BeanDefinitionRegistry) {
    		BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
    		List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>();
    		List<BeanDefinitionRegistryPostProcessor> registryProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>();
    		// 循环遍历每个BeanFactoryPostProcessor,如果是BeanDefinitionRegistryPostProcessor,则调用其后置处理方法
    		// 如果不是则加入regularPostProcessors中
    		for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
    			if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
    				BeanDefinitionRegistryPostProcessor registryProcessor =
    						(BeanDefinitionRegistryPostProcessor) postProcessor;
    				registryProcessor.postProcessBeanDefinitionRegistry(registry);
    				registryProcessors.add(registryProcessor);
    			}
    			else {
    				regularPostProcessors.add(postProcessor);
    			}
    		}
    		// Do not initialize FactoryBeans here: We need to leave all regular beans
    		// uninitialized to let the bean factory post-processors apply to them!
    		// Separate between BeanDefinitionRegistryPostProcessors that implement
    		// PriorityOrdered, Ordered, and the rest.
    		// 从beanFactory中获取BeanDefinitionRegistryPostProcessor类型且实现PriorityOrdered接口的Bean
    		List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<BeanDefinitionRegistryPostProcessor>();
    		// 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);
    			}
    		}
    		// 排序currentRegistryProcessors
    		sortPostProcessors(currentRegistryProcessors, beanFactory);
    		registryProcessors.addAll(currentRegistryProcessors);
    		// 唤醒BeanDefinitionRegistryPostProcessor
    		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    		currentRegistryProcessors.clear();
    
    		// 从beanFactory中获取BeanDefinitionRegistryPostProcessor类型且实现Ordered接口的Bean
    		// Next, invoke the BeanDefinitionRegistryPostProcessors that implement Ordered.
    		postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    		for (String ppName : postProcessorNames) {
    			// 这里排除已经被处理的BeanDefinitionRegistry
    			if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
    				currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    				processedBeans.add(ppName);
    			}
    		}
    		// 排序currentRegistryProcessors
    		sortPostProcessors(currentRegistryProcessors, beanFactory);
    		registryProcessors.addAll(currentRegistryProcessors);
    		// 唤醒BeanDefinitionRegistryPostProcessor
    		invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    		currentRegistryProcessors.clear();
    		// 最后唤醒所有的其他的非PriorityOrdered和Ordered实现的BeanDefinitionRegistryPostProcessor
    		// Finally, invoke all other BeanDefinitionRegistryPostProcessors until no further ones appear.
    		boolean reiterate = true;
    		while (reiterate) {
    			reiterate = false;
    			postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
    			for (String ppName : postProcessorNames) {
    				if (!processedBeans.contains(ppName)) {
    					currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
    					processedBeans.add(ppName);
    					reiterate = true;
    				}
    			}
    			sortPostProcessors(currentRegistryProcessors, beanFactory);
    			registryProcessors.addAll(currentRegistryProcessors);
    			invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
    			currentRegistryProcessors.clear();
    		}
    		// 唤醒BeanFactoryPostProcessor
    		// Now, invoke the postProcessBeanFactory callback of all processors handled so far.
    		invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
    		invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
    	}
    	else {
    		// 如果不是BeanDefinitionRegistry实例,则直接唤醒BeanFactoryPostProcessor
    		// Invoke factory processors registered with the context instance.
    		invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
    	}
    
    	//1. 按照BeanFactoryPostProcessor类型获取Bean工厂中的Bean名字
    	//2. 不过早的初始化,防止FactoryBeans被初始化
    	// Do not initialize FactoryBeans here: We need to leave all regular beans
    	// uninitialized to let the bean factory post-processors apply to them!
    	String[] postProcessorNames =
    			beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
    	// 以下逻辑就是按照bean名称逐个获取Bean,且将PriorityOrdered和Ordered分离
    	// PriorityOrdered优先级最高,其次是Ordered,最后是剩余部分
    	// Separate between BeanFactoryPostProcessors that implement PriorityOrdered,
    	// Ordered, and the rest.
    	List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
    	List<String> orderedPostProcessorNames = new ArrayList<String>();
    	List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
    	for (String ppName : postProcessorNames) {
    		// 跳过,在上述处理BeanDefinitionRegistryPostProcessor时,已经执行了该BeanFactoryPostProcessor
    		if (processedBeans.contains(ppName)) {
    			// skip - already processed in first phase above
    		}
    		else if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    			priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class));
    		}
    		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    			orderedPostProcessorNames.add(ppName);
    		}
    		else {
    			nonOrderedPostProcessorNames.add(ppName);
    		}
    	}
    	// 首先排序PriorityOrdered接口的试下,然后执行BeanFactoryPostProcessor
    	// First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered.
    	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    	invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
    	// 再排序Ordered接口的实现,然后执行BeanFactoryPostProcessor
    	// Next, invoke the BeanFactoryPostProcessors that implement Ordered.
    	List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
    	for (String postProcessorName : orderedPostProcessorNames) {
    		orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    	}
    	sortPostProcessors(orderedPostProcessors, beanFactory);
    	invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
    	// 最后唤醒执行剩下的其他的BeanFactoryPostProcessor
    	// Finally, invoke all other BeanFactoryPostProcessors.
    	List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>();
    	for (String postProcessorName : nonOrderedPostProcessorNames) {
    		nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
    	}
    	invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
    	// 清理缓存的元数据
    	// Clear cached merged bean definitions since the post-processors might have
    	// modified the original metadata, e.g. replacing placeholders in values...
    	beanFactory.clearMetadataCache();
    }
    

    上述的逻辑比较复杂,这里做下总结概括:

    1. 当前BeanFactory如果是BeanDefinitionRegistry实例,则获取BeanFactory中的所有BeanDefinitionRegistryPostProcessor的Bean定义并实例化,最后唤醒。其中BeanDefinitionRegistryPostProcessor具有优先级,按照PriorityOrdered、Ordered、rest(剩下)的级别划分,分别先后执行。然后再作为beanFactoryPostProcessor执行;如果不是BeanDefinitionRegistry实例,则直接当做beanFactoryPostProcessors执行
    2. 获取当前BeanFactory中的所有BeanFactoryPostProcessor的Bean定义,并按照PriorityOrdered、Ordered、rest(剩下)的级别划分,分别先后执行。

    Note:
    BeanDefinitionRegistryPostProcessor也是ApplicationContext的扩展点之一。它继承了BeanFactoryPostProcessor接口,但是又增强了其能力,添加了想BeanFactory中注册更多的Bean定义的能力。具体详见javadocs。

    至此,关于ApplicationContext的BeanFactoryPostProcessor的扩展点的原理也就非常清晰,在加载配置的Bean定义后和实例化Bean之前,触发载入BeanFactoryPostProcessor,并唤醒执行。从源码实现上更可以清晰的看到Spring的设计:

    1. 微内核ApplicationContext(负责Bean定义的注册/Bean的实例化/Bean的装配)
    2. 插件体系(BeanFactoryPostProcessor,可以扩展其修改Bean定义)

    4.典型案例

    虽然BeanFactoryPostProcessor是Spring为应用开放的扩张点,但是Spring框架本身也使用了该特征,内置了一些公共常用的BeanFactoryPostProcessor实现。本节就通过具体的BeanFactoryPostProcessor实现进一步认识它的能力。

    PropertySourcesPlaceholderConfigurer

    PropertySourcesPlaceholderConfigurer是Spring 3.1为提供属性资源占位解析功能而引入,它是BeanFactoryPostProcessor的标准实现。这里不再介绍其使用细节,更多关注其实现原理。使用细节请参考Spring Framework Reference Documentation

    PropertySourcesPlaceholderConfigurer具有两大能力:

    1. 解析属性资源(和Environment的非常类似)
    2. 解析Bean定义中的占位

    下面着重分析这两个特征。PropertySourcesPlaceholderConfigurer具有解析属性资源的能力和Environment非常相似。前文在介绍Environment时也稍微提到过,Spring中的Environment不负责解析所有的属性资源,主要是针对与环境相关的属性解析。这里再总结下:

    1. Environment负责解析JVM系统属性和操作系统环境变量
    2. Environment负责解析被PropertySource注解标注的资源
    3. Environment负责处理与环境相关的占位,如:配置中的文件路径占位

    但是Spring中还有很大一部分属性解析不在Environment的能力范畴内。如:@Value标注的属性,Bean定义中的${...}占位的属性解析替换。这些属性的解析主要由PropertySourcesPlaceholderConfigurer负责处理。

    PropertySourcesPlaceholderConfigurer的属性由两部分组成:

    1. Environment中的属性被包含在PropertySourcesPlaceholderConfigurer中
    2. PropertySourcesPlaceholderConfigurer自身提供属性文件路径的配置,可以加载属性资源
    public class PropertySourcesPlaceholderConfigurer extends PlaceholderConfigurerSupport implements EnvironmentAware {
    	/**
    	 * {@value} is the name given to the {@link PropertySource} for the set of
    	 * {@linkplain #mergeProperties() merged properties} supplied to this configurer.
    	 */
    	public static final String LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME = "localProperties";
    	/**
    	 * {@value} is the name given to the {@link PropertySource} that wraps the
    	 * {@linkplain #setEnvironment environment} supplied to this configurer.
    	 */
    	public static final String ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME = "environmentProperties";
    	// PropertySourcesPlaceholderConfigurer的属性集合
    	private MutablePropertySources propertySources;
    	// PropertySourcesPlaceholderConfigurer最终可以被使用的属性
    	private PropertySources appliedPropertySources;
    	// 环境对象
    	private Environment environment;
    }
    

    propertySources是PropertySourcesPlaceholderConfigurer中的所有属性容器,PropertySourcesPlaceholderConfigurer通过实现EnvironmentAware将ApplicationContext中的environment注入至PropertySourcesPlaceholderConfigurer。
    environment也是属性容器,PropertySourcesPlaceholderConfigurer将environment的属性转至propertySources中,propertySources即PropertySourcesPlaceholderConfigurer的所有属性集合。

    PropertySourcesPlaceholderConfigurer通过实现BeanFactoryPostProcessor接口,用于处理Bean定义中的占位解析和@Value注解中的占位。下面就上述属性解析和占位解析综合分析PropertySourcesPlaceholderConfigurer的具体实现。其中主要逻辑在BeanFactoryPostProcessor的接口实现中postProcessBeanFactory:

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    	// 如果propertySources集合为空
    	if (this.propertySources == null) {
    		// 创建propertySources
    		this.propertySources = new MutablePropertySources();
    		// 如果environment不为空
    		if (this.environment != null) {
    			// 将environment加入至propertySources结尾
    			this.propertySources.addLast(
    				new PropertySource<Environment>(ENVIRONMENT_PROPERTIES_PROPERTY_SOURCE_NAME, this.environment) {
    					@Override
    					public String getProperty(String key) {
    						return this.source.getProperty(key);
    					}
    				}
    			);
    		}
    		// 如果localProperties不为空,将其加入至propertySources中
    		try {
    			PropertySource<?> localPropertySource =
    					new PropertiesPropertySource(LOCAL_PROPERTIES_PROPERTY_SOURCE_NAME, mergeProperties());
    			// 如果是本地覆盖,则加载头部
    			if (this.localOverride) {
    				this.propertySources.addFirst(localPropertySource);
    			}
    			// 否则加载尾部
    			else {
    				this.propertySources.addLast(localPropertySource);
    			}
    		}
    		catch (IOException ex) {
    			throw new BeanInitializationException("Could not load properties", ex);
    		}
    	}
    	// 处理Bean定义和@Value中的占位
    	processProperties(beanFactory, new PropertySourcesPropertyResolver(this.propertySources));
    	// 记录实际被应用的属性
    	this.appliedPropertySources = this.propertySources;
    }
    

    从以上逻辑中可以看出,propertySources包含了environment的属性,localPropertySource主要是应用本地配置的属性,即在配置PropertySourcesPlaceholderConfigurer时指定的属性文件:

    // 将多个properties合并成单个properties
    protected Properties mergeProperties() throws IOException {
    	// 创建单个properties
    	Properties result = new Properties();
    	if (this.localOverride) {
    		// Load properties from file upfront, to let local properties override.
    		loadProperties(result);
    	}
    	// 将本地的多个properties合并到单个properties中
    	if (this.localProperties != null) {
    		for (Properties localProp : this.localProperties) {
    			CollectionUtils.mergePropertiesIntoMap(localProp, result);
    		}
    	}
    	if (!this.localOverride) {
    		// Load properties from file afterwards, to let those properties override.
    		loadProperties(result);
    	}
    	return result;
    }
    

    processProperties中主要负责解析Bean定义的占位。对于属性占位的解析由另一个组件PropertySourcesPropertyResolver负责,在Environment的文章中也介绍了,这里不再赘述。PropertySourcesPlaceholderConfigurer通过以工具的方式使用PropertySourcesPropertyResolver完成Bean定义中的占位解析。

    PropertySourcesPlaceholderConfigurer利用Bean定义访问器组件访问Bean定义中的占位,然后将占位交由PropertySourcesPropertyResolver解析替换:

    protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
    		final ConfigurablePropertyResolver propertyResolver) throws BeansException {
    	// 分别何止占位前缀(默认值:"${")、后缀(默认值:"}")和值分割符(默认值:":")
    	propertyResolver.setPlaceholderPrefix(this.placeholderPrefix);
    	propertyResolver.setPlaceholderSuffix(this.placeholderSuffix);
    	propertyResolver.setValueSeparator(this.valueSeparator);
    
    	// 创建String值解析器,因为占位的都是String类型
    	// 其中组合使用属性解析器实现
    	StringValueResolver valueResolver = new StringValueResolver() {
    		@Override
    		public String resolveStringValue(String strVal) {
    			String resolved = (ignoreUnresolvablePlaceholders ?
    					propertyResolver.resolvePlaceholders(strVal) :
    					propertyResolver.resolveRequiredPlaceholders(strVal));
    			if (trimValues) {
    				resolved = resolved.trim();
    			}
    			return (resolved.equals(nullValue) ? null : resolved);
    		}
    	};
    	// 处理占位属性
    	doProcessProperties(beanFactoryToProcess, valueResolver);
    }
    

    接下来在继续看doProcessProperties的逻辑:

    protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess,
    		StringValueResolver valueResolver) {
    	// 使用解析器构造Bean定义访问器
    	BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver);
    	// 获取Bean工厂中所有的Bean名字
    	String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames();
    	// 循环根据Bean名字遍历所有Bean定义,排除本身Bean定义
    	for (String curName : beanNames) {
    		// Check that we're not parsing our own bean definition,
    		// to avoid failing on unresolvable placeholders in properties file locations.
    		if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) {
    			BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName);
    			try {
    				// 访问Bean定义
    				visitor.visitBeanDefinition(bd);
    			}
    			catch (Exception ex) {
    				throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage(), ex);
    			}
    		}
    	}
    	// 兼容处理
    	// New in Spring 2.5: resolve placeholders in alias target names and aliases as well.
    	beanFactoryToProcess.resolveAliases(valueResolver);
    	// New in Spring 3.0: resolve placeholders in embedded values such as annotation attributes.
    	beanFactoryToProcess.addEmbeddedValueResolver(valueResolver);
    }
    

    主要是完成Bean定义的访问,其中访问时解析占位。需要注意的是,排除自身Bean定义,防止自身的属性文件路径中有不可解析的占位导致解析失败。PropertySourcesPlaceholderConfigurer的通过继承关系实现了BeanFactoryAware和BeanNameAware接口,从而将BeanFactory和Bean自身的名字加载进来。

    其中解析的占位的核心逻辑在visitor.visitBeanDefinition(bd)中实现,主要逻辑就是遍历bean定义中的各个属性。然后交由StringValueResolver负责解析:

    // 遍历访问Bean定义的各个属性,父bean名称、bean类型名称、属性值、构造参数值等等
    public void visitBeanDefinition(BeanDefinition beanDefinition) {
    	// 访问解析父bean名称
    	visitParentName(beanDefinition);
    	// 访问解析bean类型名称
    	visitBeanClassName(beanDefinition);
    	// 访问解析工厂bean名称
    	visitFactoryBeanName(beanDefinition);
    	// 访问解析工厂方法名称
    	visitFactoryMethodName(beanDefinition);
    	// 访问解析作用域
    	visitScope(beanDefinition);
    	// 访问解析属性值
    	visitPropertyValues(beanDefinition.getPropertyValues());
    	// 按照索引方式访问解析构造参数值
    	ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues();
    	visitIndexedArgumentValues(cas.getIndexedArgumentValues());
    	// 通用方式访问解析构造参数值
    	visitGenericArgumentValues(cas.getGenericArgumentValues());
    }
    

    以上逻辑非常简单,就是遍历访问Bean定义的各个属性,然后逐个解析占位。虽然情形比较多,但是大致原理都是一样,这里选择父Bean类型名称解析和属性值解析作为重点介绍,其他的读者可以自行阅读源码

    访问解析Bean类型名称

    // 访问解析Bean类型名称
    protected void visitBeanClassName(BeanDefinition beanDefinition) {
    	// 获取Bean定义的Bean类型名称
    	String beanClassName = beanDefinition.getBeanClassName();
    	// 如果Bean名称不为空
    	if (beanClassName != null) {
    		// 解析Bean名称
    		String resolvedName = resolveStringValue(beanClassName);
    		// 解析结果如果与原Bean类型名称不相等,则覆盖设置Bean类型名称
    		if (!beanClassName.equals(resolvedName)) {
    			beanDefinition.setBeanClassName(resolvedName);
    		}
    	}
    }
    
    protected String resolveStringValue(String strVal) {
    	if (this.valueResolver == null) {
    		throw new IllegalStateException("No StringValueResolver specified - pass a resolver " +
    				"object into the constructor or override the 'resolveStringValue' method");
    	}
    	// 使用解析器解析属性值
    	// 关于解析的细节,可以参考前篇文章中关于Environment的讲解
    	String resolvedValue = this.valueResolver.resolveStringValue(strVal);
    	// Return original String if not modified.
    	// 如果解析后与原值不等,则返回解析后的新值,否则返回原值
    	return (strVal.equals(resolvedValue) ? strVal : resolvedValue);
    }
    

    访问解析属性值

    // 访问解析属性值中的占位
    protected void visitPropertyValues(MutablePropertyValues pvs) {
    	// 获取属性值数组
    	PropertyValue[] pvArray = pvs.getPropertyValues();
    	// 遍历访问每个属性值
    	for (PropertyValue pv : pvArray) {
    		// 解析属性值
    		Object newVal = resolveValue(pv.getValue());
    		// 解析后结果与原值不等,则覆盖原值
    		if (!ObjectUtils.nullSafeEquals(newVal, pv.getValue())) {
    			pvs.add(pv.getName(), newVal);
    		}
    	}
    }
    
    protected Object resolveValue(Object value) {
    	// 如果属性值类型是BeanDefinition、BeanDefinitionHolder则简介递归调用访问bean定义方法
    	if (value instanceof BeanDefinition) {
    		visitBeanDefinition((BeanDefinition) value);
    	}
    	else if (value instanceof BeanDefinitionHolder) {
    		visitBeanDefinition(((BeanDefinitionHolder) value).getBeanDefinition());
    	}
    	// 如果是引用其他的Bean的属性值,直接获取引用的值,然后解析占位
    	// 如果解析后的值与原值不等,则重新创建新的引用属性值并返回
    	// 到这里,对Spring中的占位应该非常清晰了
    	else if (value instanceof RuntimeBeanReference) {
    		RuntimeBeanReference ref = (RuntimeBeanReference) value;
    		String newBeanName = resolveStringValue(ref.getBeanName());
    		if (!newBeanName.equals(ref.getBeanName())) {
    			return new RuntimeBeanReference(newBeanName);
    		}
    	}
    	// 如果是其他的Bean名称的引用的属性值,直接获取引用的bean名称,然后解析占位
    	// 如果解析后的值与原值不等,则重新创建新的并返回
    	else if (value instanceof RuntimeBeanNameReference) {
    		RuntimeBeanNameReference ref = (RuntimeBeanNameReference) value;
    		String newBeanName = resolveStringValue(ref.getBeanName());
    		if (!newBeanName.equals(ref.getBeanName())) {
    			return new RuntimeBeanNameReference(newBeanName);
    		}
    	}
    	// 如果是数组,则访问解析数组
    	else if (value instanceof Object[]) {
    		visitArray((Object[]) value);
    	}
    	// 如果是列表,则访问解析列表
    	else if (value instanceof List) {
    		visitList((List) value);
    	}
    	// 如果是集合,则访问解析集合
    	else if (value instanceof Set) {
    		visitSet((Set) value);
    	}
    	// 如果是映射表,则访问解析映射表
    	else if (value instanceof Map) {
    		visitMap((Map) value);
    	}
    	// TypedStringValue是针对Bean的String类型成员域的解析表示
    	// 如果是该类型,则获取对应的值,然后解析
    	// 然后覆盖旧值
    	else if (value instanceof TypedStringValue) {
    		TypedStringValue typedStringValue = (TypedStringValue) value;
    		String stringValue = typedStringValue.getValue();
    		if (stringValue != null) {
    			String visitedString = resolveStringValue(stringValue);
    			typedStringValue.setValue(visitedString);
    		}
    	}
    	// 如果是String类型,则直接解析
    	else if (value instanceof String) {
    		return resolveStringValue((String) value);
    	}
    	return value;
    }
    

    到这里,BeanFactoryPostProcessor的原理应该非常清楚了,且对于Spring中的常用占位处理的扩展点PropertySourcesPlaceholderConfigurer的原理应该也非常清晰。接下来的内容着重介绍Spring的另一个扩展点BeanPostProcessor。

    BeanPostProcessor

    1.什么是BeanPostProcessor

    BeanPostProcessor是Bean的后置处理器,顾名思义,用于后置处理容器中的Bean。那么定然是在Spring已经实例化了Bean之后,BeanPostProcessor才得以运用。根据官方文档的描述:

    The BeanPostProcessor interface defines callback methods that you can implement to provide your own (or override the container’s default) instantiation logic, dependency-resolution logic, and so forth. If you want to implement some custom logic after the Spring container finishes instantiating, configuring, and initializing a bean, you can plug in one or more BeanPostProcessor implementations.

    BeanPostProcessor的功能非常强大,能够覆盖默认的实例化逻辑,定制应用需要的实例化方式,实现依赖注入的策略,等等。也可以在Spring容器完成实例化、配置、初始化Bean之后,插入自定义的BeanPostProcessor实现。

    Note 1:
    BeanPostProcessor是具有容器层次的。一个Spring容器中的BeanPostProcessor是无法后置处理另一个容器的Bean的。

    Note 2:
    需要区分BeanPostProcessor和BeanFactoryPostProcessor的区别,前者是后置处理Bean,后者是后置处理Bean定义,作用的对象不同。

    Note 3:
    BeanPostProcessor作为Spring容器的另一个扩展点,被插在容器实例化Bean之后的点。从这里又再次感受到,Spring容器无处不扩展的特征,在各个关键地方都预留扩展口。

    2.何处扩展

    谈论何处扩展需要从两个点分析:

    • BeanPostProcessor自身的实例化
    • BeanPostProcessor的唤醒

    由于在Bean实例化之后需要唤醒BeanPostProcessor逻辑,所以需要在Bean实例化之前或者实例化中定要将BeanPostProcessor实例化和初始化完成。Spring中选择在实例化其他Bean之前实例化BeanPostProcessor。BeanFactory中有持有BeanPostProcessor的列表,将存储实例化的BeanPostProcessor。在Bean实例化后唤醒BeanPostProcessor逻辑。

    BeanPostProcessor中定义了两个接口:

    // 实例化Bean后,初始化Bean之前处理Bean
    Object postProcessBeforeInitialization(Object bean, String beanName)
    
    // 实例化Bean后,初始化Bean之后处理Bean
    Object postProcessAfterInitialization(Object bean, String beanName)
    

    3.源码分析

    这节就从BeanPostProcessor的注册和唤醒的源码实现角度分析,更进一步认识BeanPostProcessor设计。

    注册BeanPostProcessor

    Spring容器在实例化Bean之前需要实例化上下文中的BeanPostProcessor并将其注册至BeanFactory中,有些事Spring框架内置实现,有些事应用开发者自身的实现扩展。注册BeanPostProcessor在AbstractApplicationContext的模板方法refresh的流程中:

    ...省略
    postProcessBeanFactory(beanFactory);
    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);
    
    // 注册BeanPostProcessors至BeanFactory中
    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);
    
    // Initialize message source for this context.
    initMessageSource();
    
    // Initialize event multicaster for this context.
    initApplicationEventMulticaster();
    
    // Check for listener beans and register them.
    registerListeners();
    
    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);
    ...省略
    

    注册的主要逻辑由registerBeanPostProcessors实现,其中包括实例化容器中的BeanPostProcessor,并具有优先级能力。然后将其注册至BeanFactory:

    // 注册容器中的BeanPostProcessor
    protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    	// 委托PostProcessorRegistrationDelegate实现
    	PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
    }
    

    Spring中后置处理器的注册都是委托PostProcessorRegistrationDelegate的实现:

    // 注册BeanPostProcessor
    // 包括两部分逻辑:1. 实例化BeanFactory中的BeanPostProcessor的Bean定义;2. 注册BeanPostProcessor实例至BeanFactory
    // 仍然是三步骤:1.PriorityOrdered接口实现;2.Ordered的实现;3.rest部分
    public static void registerBeanPostProcessors(
    		ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
    	// 根据类型BeanPostProcessor获取容器中所有的Bean名称,使用false参数,禁止FactoryBean过早初始化
    	String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
    	// 注册BeanPostProcessor的实现BeanPostProcessorChecker记录在BeanPostProcessor实例化期间,被创建的Bean
    	// Register BeanPostProcessorChecker that logs an info message when
    	// a bean is created during BeanPostProcessor instantiation, i.e. when
    	// a bean is not eligible for getting processed by all BeanPostProcessors.
    	int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
    	beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
    	// 分三步实例化注册BeanPostProcessor。1. 实现了PriorityOrdered接口最优先实例化并注册;
    	// 2.再实例化并注册Ordered实现;3.最后实例化注册剩余的BeanPostProcessor
    	// 这里分别使用三个列表priorityOrderedPostProcessors、orderedPostProcessorNames、nonOrderedPostProcessorNames
    	// 来记录三种类型的BeanPostProcessor的Bean名称
    	// Separate between BeanPostProcessors that implement PriorityOrdered,
    	// Ordered, and the rest.
    	List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
    	List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
    	List<String> orderedPostProcessorNames = new ArrayList<String>();
    	List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
    	for (String ppName : postProcessorNames) {
    		// 实现了PriorityOrdered接口,记录到priorityOrderedPostProcessors列表中
    		if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
    			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    			priorityOrderedPostProcessors.add(pp);
    			// 如果是MergedBeanDefinitionPostProcessor实现,再记录internalPostProcessors中
    			if (pp instanceof MergedBeanDefinitionPostProcessor) {
    				internalPostProcessors.add(pp);
    			}
    		}
    		// 如果是Ordered的实现,则记录到orderedPostProcessorNames中
    		else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
    			orderedPostProcessorNames.add(ppName);
    		}
    		else {
    			// 剩余的记录到nonOrderedPostProcessorNames
    			nonOrderedPostProcessorNames.add(ppName);
    		}
    	}
    	// 分三步:fisrt -> PriorityOrdered, second -> Ordered, finally -> rest部分
    	// First, register the BeanPostProcessors that implement PriorityOrdered.
    	// 先排序
    	sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
    	// 注册到BeanFactory中
    	registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
    	// Next, register the BeanPostProcessors that implement Ordered.
    	// 排序,然后再注册Ordered的实现
    	List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
    	for (String ppName : orderedPostProcessorNames) {
    		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    		orderedPostProcessors.add(pp);
    		if (pp instanceof MergedBeanDefinitionPostProcessor) {
    			internalPostProcessors.add(pp);
    		}
    	}
    	sortPostProcessors(orderedPostProcessors, beanFactory);
    	registerBeanPostProcessors(beanFactory, orderedPostProcessors);
    	// 最后注册剩余部分的BeanPostProcessors
    	// Now, register all regular BeanPostProcessors.
    	List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
    	for (String ppName : nonOrderedPostProcessorNames) {
    		BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
    		nonOrderedPostProcessors.add(pp);
    		if (pp instanceof MergedBeanDefinitionPostProcessor) {
    			internalPostProcessors.add(pp);
    		}
    	}
    	registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
    	// Finally, re-register all internal BeanPostProcessors.
    	sortPostProcessors(internalPostProcessors, beanFactory);
    	registerBeanPostProcessors(beanFactory, internalPostProcessors);
    	// 最后在BeanPostProcessor的链尾再加入ApplicationListenerDetector
    	// Re-register post-processor for detecting inner beans as ApplicationListeners,
    	// moving it to the end of the processor chain (for picking up proxies etc).
    	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
    }
    

    以上的实例化注册BeanPostProcessor的策略基本和BeanFactoryPostProcessor一致,根据优先级都是分为三步骤。

    其中需要注意的两点是:

    • 内部的BeanPostProcessor internalPostProcessors
    • 链尾的BeanPostProcessor的实现ApplicationListenerDetector

    internalPostProcessors主要是针对MergedBeanDefinitionPostProcessor,该接口是BeanPostProcessor的子接口,对其进行了能力增强。这里不再详细介绍。

    ApplicationListenerDetector作用功能是用于检测容器中的ApplicationLisenter,将其注册到上下文中。后续再典型案例中将分析该实现原理。

    这里对registerBeanPostProcessors的逻辑再深入点介绍,该方法中主要实现BeanPostProcessor注册入BeanFactory中:

    // 注册BeanPostProcessor入BeanFactory中
    private static void registerBeanPostProcessors(
    		ConfigurableListableBeanFactory beanFactory, List<BeanPostProcessor> postProcessors) {
    	// 循环遍历加入BeanFactory中
    	for (BeanPostProcessor postProcessor : postProcessors) {
    		beanFactory.addBeanPostProcessor(postProcessor);
    	}
    }
    

    DefautListableBeanFactory中持有BeanFactory的列表:

    /** BeanPostProcessors to apply in createBean */
    private final List<BeanPostProcessor> beanPostProcessors = new ArrayList<BeanPostProcessor>();
    
    

    addBeanPostProcessor是BeanFactory顶层抽象的接口:

    void addBeanPostProcessor(BeanPostProcessor beanPostProcessor);
    

    ConfigurableBeanFactory定义了该接口,主要是为了添加BeanPostProcessor。到这里关于BeanPostProcessor的实现也介绍结束,它的逻辑本身并不复杂,关于何时唤醒BeanPostProcessor的逻辑,在下篇文章中填坑。这里不再赘述,因为BeanPostProcessor的调用执行涉及到Bean的创建过程,非常复杂,需要有对Bean的创建过程熟悉。

    4.典型案例

    类似PropertySourcesPlaceholderConfigurer这样的方式介绍案例。BeanPostProcessor的实现分为两部分:

    • Spring内建的实现
    • 应用开发者自行拓展的实现

    本篇文章主要以原理为主,这里笔者同样不再编写Demo介绍,仍以Spring中内建的实现作为案例介绍。

    ApplicationListenerDetector

    ApplicationListenerDetector是Spring中内置的BeanPostProcessor实现,主要是为了检测Spring容器中的的ApplicaiontListener,然后将其注册到Spring上下文中。

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
    	// 当上下文不为空时且该bean是ApplicationListener
    	if (this.applicationContext != null && bean instanceof ApplicationListener) {
    		// potentially not detected as a listener by getBeanNamesForType retrieval
    		// 如果是单例,则将该bean注册至上下文中
    		Boolean flag = this.singletonNames.get(beanName);
    		if (Boolean.TRUE.equals(flag)) {
    			// singleton bean (top-level or inner): register on the fly
    			this.applicationContext.addApplicationListener((ApplicationListener<?>) bean);
    		}
    		else if (Boolean.FALSE.equals(flag)) {
    			if (logger.isWarnEnabled() && !this.applicationContext.containsBean(beanName)) {
    				// inner bean with other scope - can't reliably process events
    				logger.warn("Inner bean '" + beanName + "' implements ApplicationListener interface " +
    						"but is not reachable for event multicasting by its containing ApplicationContext " +
    						"because it does not have singleton scope. Only top-level listener beans are allowed " +
    						"to be of non-singleton scope.");
    			}
    			this.singletonNames.remove(beanName);
    		}
    	}
    	return bean;
    }
    

    ApplicationListenerDetector实现了实例化后进行后置处理的逻辑,主要就是检测ApplicationListener,然后将其加入Spring上下文中。

    Note:
    无论是实例化前还是实例化后的后置处理,都需要return bean。否则上下文的后续逻辑将无法处理该Bean。

    总结

    本文主要介绍Spring容器中的两大扩展点,BeanFactoryPostProcessor和BeanPostProcessor。前者用于对Bean定义进行后置处理,后者用于对Spring容器中的Bean进行后置处理。虽然命名即为相似,但是作用上有根本的区别。

    关于Spring中的扩展点非常多,本篇文章也只在阅读源码过程中的发现的扩展点总结,后续会有更多扩张点文章呈现。

    参考

    Container Extension Points

  • 相关阅读:
    批处理系统中采用的调度算法
    机器学习(周志华西瓜书)参考答案总目录
    机器学习(周志华西瓜书)参考答案总目录
    主题模型LDA及在推荐系统中的应用
    常见的六大聚类算法
    大数据学习笔记·城市计算(1)
    数据预处理之数据规约(Data Reduction)
    高维数据稀疏表示-什么是字典学习(过完备词典)
    dev gridview columns代码管理
    mysql常用命令
  • 原文地址:https://www.cnblogs.com/lxyit/p/10108543.html
Copyright © 2020-2023  润新知