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源碼的一個技巧,就是看一個類是幹嗎的必定要先通讀其註釋。spring
結合接口上的註釋大體描述下BeanFactoryPostProcessor: 容許用戶經過修改applicationContext 中的bean定義(就是xml中定義的bean的信息即:BeanDefinition是和xml有一對一的配置,好比是不是單利,以及propert 屬性的賦值等) 來調整applicationContext中bean工廠中bean屬性值。 也就是說執行到BeanFactoryPostProcessor時所有的BeanDefinition定義已經加載好了可是bean實例尚未被建立,咱們能夠修補或者覆蓋bean屬性值。
咱們能夠看一下ApplicationContext中BeanFactoryPostProcessor的調用位置來印證是否如此app
下面是ApplicationContext核心代碼:ide
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; } } }
通過源碼分析
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); // Prepare the bean factory for use in this context. prepareBeanFactory(beanFactory);
這兩步咱們已經拿到了beanFactory實例,也就是每個bean對應的BeanDefinition已經加載好了。下面纔是執行invokeBeanFactoryPostProcessors(beanFactory),也就印證了咱們上面的結論。
下面咱們經過一個BeanFactoryPostProcessor的典型應用PropertyPlaceholderConfigurer來詳細講解BeanFactoryPostProcessor執行原理post
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配置文件:測試
student.name=anan student.age=2
單元測試:ui
@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()); }
輸出結果一切正常:this
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()方法會先將
後面調用** 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源碼分析的文章。加油!!!