个人博客同步发布,地址:http://yalunwang.com/2020/02/28/spring-BeanFactoryPostProcessors-PropertyPlaceholderConfigurer.html html
BeanFactoryPostProcessors完整定义:java
/** * Allows for custom modification of an application context's bean definitions, * adapting the bean property values of the context's underlying bean factory. * @see BeanPostProcessor * @see PropertyResourceConfigurer */ 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; }
咱们知道spring最大优势就是其可扩展性,BeanFactoryPostProcessor接口就是spring中提供给咱们用于扩展的一个地方。咱们看该接口上的javadoc其实很是的详细,这也是咱们看spring源码的一个技巧,就是看一个类是干吗的必定要先通读其注释。git
结合接口上的注释大体描述下BeanFactoryPostProcessor: 容许用户经过修改applicationContext 中的bean定义(就是xml中定义的bean的信息即:BeanDefinition是和xml有一对一的配置,好比是不是单利,以及propert 属性的赋值等) 来调整applicationContext中bean工厂中bean属性值。 也就是说执行到BeanFactoryPostProcessor时所有的BeanDefinition定义已经加载好了可是bean实例尚未被建立,咱们能够修补或者覆盖bean属性值。
咱们能够看一下ApplicationContext中BeanFactoryPostProcessor的调用位置来印证是否如此github
下面是ApplicationContext核心代码:spring
public void refresh() throws BeansException, IllegalStateException { synchronized (this.startupShutdownMonitor) { // Prepare this context for refreshing. prepareRefresh(); //获取beanFactory实例 ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); prepareBeanFactory(beanFactory); try { postProcessBeanFactory(beanFactory); //这里正是咱们的BeanFactoryPostProcessor执行的位置 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. //建立非懒加载的全部单例 这里是真正建立bean实例的地方 finishBeanFactoryInitialization(beanFactory); // Last step: publish corresponding event. finishRefresh(); } catch (BeansException ex) { // Destroy already created singletons to avoid dangling resources. destroyBeans(); // Reset 'active' flag. cancelRefresh(ex); // Propagate exception to caller. throw ex; } } }
通过app
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory);
这两步咱们已经拿到了beanFactory实例,也就是每个bean对应的BeanDefinition已经加载好了。下面才是执行invokeBeanFactoryPostProcessors(beanFactory),也就印证了咱们上面的结论。 下面咱们经过一个BeanFactoryPostProcessor的典型应用PropertyPlaceholderConfigurer来详细讲解BeanFactoryPostProcessor执行原理ide
PropertyPlaceholderConfigurer相信你们都使用过,咱们在配置bean的属性可使用占位符来赋值,而后经过调整properties文件中对应的属性值来修改。看一个使用PropertyPlaceholderConfigurer简单的例子:源码分析
public class Student { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } } <bean class="com.yalunwang.Student" id="student"> <property name="name" value="${student.name}"></property> <property name="age" value="${student.age}"></property> </bean> <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="location" value="classpath:bean.properties"></property> </bean>
bean.properties配置文件:post
student.name=anan student.age=2
单元测试:单元测试
@Test public void test_ioc_app(){ ApplicationContext ac = new ClassPathXmlApplicationContext("spring-ioc.xml"); Student student =(Student) ac.getBean("student"); System.out.println("name: "+student.getName()); System.out.println("age: "+student.getAge()); }
输出结果一切正常:
name: anan age: 2
先看一下PropertyPlaceholderConfigurer的类继承图:
能够看到PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessor和 PriorityOrdered。
咱们接着对上面的 invokeBeanFactoryPostProcessors(beanFactory)继续进行分析:
/** * Instantiate and invoke all registered BeanFactoryPostProcessor beans, * respecting explicit order if given. * 实例化并调用全部已注册的BeanFactoryPostProcessor Bean, * 若是继承了Order接口按顺序执行 * <p>Must be called before singleton instantiation. */ protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) { // Invoke BeanDefinitionRegistryPostProcessors first, if any. Set<String> processedBeans = new HashSet<String>(); //若是是beanFactory实现了BeanDefinitionRegistry if (beanFactory instanceof BeanDefinitionRegistry) { BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = new LinkedList<BeanFactoryPostProcessor>(); List<BeanDefinitionRegistryPostProcessor> registryPostProcessors = new LinkedList<BeanDefinitionRegistryPostProcessor>(); //遍历硬编码设置的beanFactory后置处理器 for (BeanFactoryPostProcessor postProcessor : getBeanFactoryPostProcessors()) { //若是是BeanDefinitionRegistryPostProcessor类型先执行postProcessBeanDefinitionRegistry方法再将其添加到registryPostProcessors集合中进行后续postProcessBeanFactory方法的执行 if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessor registryPostProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryPostProcessor.postProcessBeanDefinitionRegistry(registry); registryPostProcessors.add(registryPostProcessor); } else { //同理将正常的beanFactory后置处理器添加到regularPostProcessors集合中进行后续postProcessBeanFactory方法的执行 regularPostProcessors.add(postProcessor); } } //找出配置的BeanDefinitionRegistryPostProcessor后置处理器 Map<String, BeanDefinitionRegistryPostProcessor> beanMap = beanFactory.getBeansOfType(BeanDefinitionRegistryPostProcessor.class, true, false); List<BeanDefinitionRegistryPostProcessor> registryPostProcessorBeans = new ArrayList<BeanDefinitionRegistryPostProcessor>(beanMap.values()); OrderComparator.sort(registryPostProcessorBeans); //执行BeanDefinitionRegistryPostProcessor后置处理器的postProcessBeanDefinitionRegistry方法 for (BeanDefinitionRegistryPostProcessor postProcessor : registryPostProcessorBeans) { postProcessor.postProcessBeanDefinitionRegistry(registry); } //执行上面添加的beanFactory后置处理器的集合里的方法 invokeBeanFactoryPostProcessors(registryPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(registryPostProcessorBeans, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); //处理后的添加到集合里 防止后面重复执行 processedBeans.addAll(beanMap.keySet()); } else { // Invoke factory processors registered with the context instance. invokeBeanFactoryPostProcessors(getBeanFactoryPostProcessors(), beanFactory); } //获取配置的BeanFactoryPostProcessor //如下按实现了 PriorityOrdered Ordered 没有继承 三种进行优先级排序执行 String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); List<String> orderedPostProcessorNames = new ArrayList<String>(); List<String> nonOrderedPostProcessorNames = new ArrayList<String>(); for (String ppName : postProcessorNames) { //这个就是上面记录的若是已经处理了配置的BeanFactoryPostProcessors就跳过 if (processedBeans.contains(ppName)) { // skip - already processed in first phase above } else if (isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } else if (isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } // First, invoke the BeanFactoryPostProcessors that implement PriorityOrdered. OrderComparator.sort(priorityOrderedPostProcessors); //上面咱们说了PropertyPlaceholderConfigurer 实现了BeanFactoryPostProcessor和 PriorityOrdered,因此会在这一步执行调用 invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); // Next, invoke the BeanFactoryPostProcessors that implement Ordered. List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); for (String postProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class)); } OrderComparator.sort(orderedPostProcessors); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); // Finally, invoke all other BeanFactoryPostProcessors. List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanFactoryPostProcessor>(); for (String postProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(getBean(postProcessorName, BeanFactoryPostProcessor.class)); } invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); }
上面主要的执行逻辑我都添加了中文注释方便你们理解。 总结一下改方法主要作的事情:
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
会执行PropertyPlaceholderConfigurer父类PropertyResourceConfigurer中的方法
/** * {@linkplain #mergeProperties Merge}, {@linkplain #convertProperties convert} and * {@linkplain #processProperties process} properties against the given bean factory. * @throws BeanInitializationException if any properties cannot be loaded */ 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); } }
mergeProperties()方法会先将 <property name="location" value="classpath:bean.properties"></property> 配置的properties加载到mergedProps里 后面调用** processProperties(beanFactory, mergedProps)**;进行处理
protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { StringValueResolver valueResolver = new PlaceholderResolvingStringValueResolver(props); this.doProcessProperties(beanFactoryToProcess, valueResolver); }
这里只有两行代码,第一行是建立StringValueResolver实例(用于替换占位符的真正方法) 咱们跨过千山万水终于要到立刻要进行占位符替换了,继续分析
protected void doProcessProperties(ConfigurableListableBeanFactory beanFactoryToProcess, StringValueResolver valueResolver) { //将建立的valueResolver设置到BeanDefinitionVisitor里 用于最终替换逻辑 (替换占位符为对应properties里配置的值) BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); //拿出ioc容器里注册的beans String[] beanNames = beanFactoryToProcess.getBeanDefinitionNames(); for (String curName : beanNames) { //排除掉当前beanName也就是 PropertyPlaceholderConfigurer Bean 且beanFactoryToProcess必须是当前容器 if (!(curName.equals(this.beanName) && beanFactoryToProcess.equals(this.beanFactory))) { //获取一个bean对应的bean定义 BeanDefinition bd = beanFactoryToProcess.getBeanDefinition(curName); try { //进行bean定义元数据的替换操做 visitor.visitBeanDefinition(bd); } catch (Exception ex) { throw new BeanDefinitionStoreException(bd.getResourceDescription(), curName, ex.getMessage()); } } } // 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); }
上面我已经使用中文注释写的很清楚了接着进行分析
public void visitBeanDefinition(BeanDefinition beanDefinition) { visitParentName(beanDefinition); visitBeanClassName(beanDefinition); visitFactoryBeanName(beanDefinition); visitFactoryMethodName(beanDefinition); visitScope(beanDefinition); visitPropertyValues(beanDefinition.getPropertyValues()); ConstructorArgumentValues cas = beanDefinition.getConstructorArgumentValues(); visitIndexedArgumentValues(cas.getIndexedArgumentValues()); visitGenericArgumentValues(cas.getGenericArgumentValues()); }
这里能够对应 bean的parentName beanClassName property等进行替换操做咱们这里只关注属性的替换操做
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); } } }
@SuppressWarnings("rawtypes") protected Object resolveValue(Object value) { if (value instanceof BeanDefinition) { visitBeanDefinition((BeanDefinition) value); } else if (value instanceof BeanDefinitionHolder) { visitBeanDefinition(((BeanDefinitionHolder) value).getBeanDefinition()); } else if (value instanceof RuntimeBeanReference) { RuntimeBeanReference ref = (RuntimeBeanReference) value; String newBeanName = resolveStringValue(ref.getBeanName()); if (!newBeanName.equals(ref.getBeanName())) { return new RuntimeBeanReference(newBeanName); } } 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); } else if (value instanceof TypedStringValue) { TypedStringValue typedStringValue = (TypedStringValue) value; String stringValue = typedStringValue.getValue(); if (stringValue != null) { String visitedString = resolveStringValue(stringValue); typedStringValue.setValue(visitedString); } } else if (value instanceof String) { return resolveStringValue((String) value); } return value; }
这里有不少类型,是由于spring支持不少类型的配置好比property的值咱们能够配置为ref=xxxbean那么value就是RuntimeBeanReference类型, 若是配置
<list> <value>343</value> <value>45</value> </list>
那么value就是List类型等等。这里咱们例子中配置的类型是TypedStringValue,那么执行
else if (value instanceof TypedStringValue) { TypedStringValue typedStringValue = (TypedStringValue) value; //这里拿到的值是原始的带有占位符的好比例子里就是${student.name}、${student.age}这种 String stringValue = typedStringValue.getValue(); if (stringValue != null) { //这一步就是去进行替换 String visitedString = resolveStringValue(stringValue); typedStringValue.setValue(visitedString); } }
/** * Resolve the given String value, for example parsing placeholders. * @param strVal the original String value * @return the resolved String value */ 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"); } //调用咱们以前传进来的valueResolver也就是上面 (BeanDefinitionVisitor visitor = new BeanDefinitionVisitor(valueResolver); 这里传进来的) 进行替换操做 String resolvedValue = this.valueResolver.resolveStringValue(strVal); // Return original String if not modified. return (strVal.equals(resolvedValue) ? strVal : resolvedValue); }
valueResolver其实就是PlaceholderResolvingStringValueResolver实例,它又委托PropertyPlaceholderHelper进行操做
也就是
/** * Replaces all placeholders of format {@code ${name}} with the value returned * from the supplied {@link PlaceholderResolver}. * @param value the value containing the placeholders to be replaced. * @param placeholderResolver the {@code PlaceholderResolver} to use for replacement. * @return the supplied value with placeholders replaced inline. */ public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) { Assert.notNull(value, "Argument 'value' must not be null."); return parseStringValue(value, placeholderResolver, new HashSet<String>()); } protected String parseStringValue( String strVal, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) { StringBuilder buf = new StringBuilder(strVal); int startIndex = strVal.indexOf(this.placeholderPrefix); while (startIndex != -1) { int endIndex = findPlaceholderEndIndex(buf, startIndex); if (endIndex != -1) { //将ex. ${student.name} 转成 student.name String placeholder = buf.substring(startIndex + this.placeholderPrefix.length(), endIndex); String originalPlaceholder = placeholder; if (!visitedPlaceholders.add(originalPlaceholder)) { throw new IllegalArgumentException( "Circular placeholder reference '" + originalPlaceholder + "' in property definitions"); } // 递归调用直到没有占位符 placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders); // 获取properties配置文件对应的值 就是获取student.name 对应在 properties里的值 String propVal = placeholderResolver.resolvePlaceholder(placeholder); if (propVal == null && this.valueSeparator != null) { int separatorIndex = placeholder.indexOf(this.valueSeparator); if (separatorIndex != -1) { String actualPlaceholder = placeholder.substring(0, separatorIndex); String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length()); propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder); if (propVal == null) { propVal = defaultValue; } } } if (propVal != null) { //再次递归调用 确保最后的值没有占位符 propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders); //将原先的StringBuff的原始值替换为拿到的值 buf.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal); if (logger.isTraceEnabled()) { logger.trace("Resolved placeholder '" + placeholder + "'"); } //这里由于已经替换成真正的值 拿不到占位符(${)因此值就是-1 会跳出循环返回 startIndex = buf.indexOf(this.placeholderPrefix, startIndex + propVal.length()); } else if (this.ignoreUnresolvablePlaceholders) { // Proceed with unprocessed value. startIndex = buf.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length()); } else { throw new IllegalArgumentException("Could not resolve placeholder '" + placeholder + "'" + " in string value \"" + strVal + "\""); } visitedPlaceholders.remove(originalPlaceholder); } else { startIndex = -1; } } return buf.toString(); }
该方法是真正替换的操做所在,改方法已经添加中文注释应该很好理解了,总结就是作了一下两件事: 1.首先会将ex. ${student.name} 转成 student.name 2.将student.name经过 tring propVal = placeholderResolver.resolvePlaceholder(placeholder);获取真正的值而后返回。
protected String resolvePlaceholder(String placeholder, Properties props, int systemPropertiesMode) { String propVal = null; if (systemPropertiesMode == SYSTEM_PROPERTIES_MODE_OVERRIDE) { propVal = resolveSystemProperty(placeholder); } if (propVal == null) { propVal = resolvePlaceholder(placeholder, props); } if (propVal == null && systemPropertiesMode == SYSTEM_PROPERTIES_MODE_FALLBACK) { propVal = resolveSystemProperty(placeholder); } return propVal; }
该方法就比较简单了就是根据不一样的模式作处理,systemPropertiesMode默认是SYSTEM_PROPERTIES_MODE_FALLBACK
通过以上各个步骤最终BeanDefinition里的parentName beanClassName property中的占位符都会被咱们propertis配置文件中对应的值所替换掉,这就为后续实例化bean后作bean实例属性填充时作好了准备。 咱们再进行 Student student =(Student) ac.getBean("student"); 时就能够正常打印对应的值了。
至此本篇源码分析就结束了,后续继续spring源码分析的文章。加油!!!
原文出处:https://www.cnblogs.com/yalunwang/p/12380985.html