BeanFactoryPostProcessor 是当 BeanDefinition 读取完元数据(也就是从任意资源中定义的 bean 数据)后还未实例化之前可以进行修改
抄录并翻译官方的语句
BeanFactoryPostProcessor
操作 bean 的元数据配置. 也就是说,Spring IoC 容器允许BeanFactoryPostProcessor
读取配置元数据, 并可能在容器实例化除BeanFactoryPostProcessor
实例之外的任何 bean 之前 更改它
tip:
在
BeanFactoryPostProcessor
(例如使用BeanFactory.getBean()
) 中使用这些 bean 的实例虽然在技术上是可行的,但这么来做会将 bean 过早实例化, 这违反了标准的容器生命周期. 同时也会引发一些副作用,例如绕过 bean 的后置处理。
publicinterfaceBeanFactoryPostProcessor { /** *通过ConfigurableListableBeanFactory这个可配置的BeanFactory对我们的bean原数据进行修改 */voidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory) throwsBeansException; }
ApplicationContext 的 refresh() 中的 invokeBeanFactoryPostProcessors 方法就开始创建我们的 BFPP(BeanFactoryPostProcessor)了
具体执行方法 invokeBeanFactoryPostProcessors,虽然一百多行代码,其实只需要特别了解的地方就几处。
publicstaticvoidinvokeBeanFactoryPostProcessors( ConfigurableListableBeanFactorybeanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) { Set<String> processedBeans = newHashSet<>(); // 由于我们的beanFactory是DefaultListableBeanFactory实例是BeanDefinitionRegistry的子类所以可以进来if (beanFactoryinstanceofBeanDefinitionRegistry) { BeanDefinitionRegistryregistry = (BeanDefinitionRegistry) beanFactory; List<BeanFactoryPostProcessor> regularPostProcessors = newArrayList<>(); List<BeanDefinitionRegistryPostProcessor> registryProcessors = newArrayList<>(); for (BeanFactoryPostProcessorpostProcessor : beanFactoryPostProcessors) { if (postProcessorinstanceofBeanDefinitionRegistryPostProcessor) { BeanDefinitionRegistryPostProcessorregistryProcessor = (BeanDefinitionRegistryPostProcessor) postProcessor; registryProcessor.postProcessBeanDefinitionRegistry(registry); registryProcessors.add(registryProcessor); } else { regularPostProcessors.add(postProcessor); } } // BeanDefinitionRegistryPostProcessor是BFPP的子类但是比BFPP提前执行// 顺序实现PriorityOrdered接口先被执行,然后是Ordered接口,最后是什么都没实现的BeanDefinitionRegistryPostProcessor/** *都有beanFactory.getBean方法,证明BeanDefinitionRegistryPostProcessor这个bean现在已经被创建了 */List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = newArrayList<>(); String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (StringppName : postProcessorNames) { if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear(); postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (StringppName : postProcessorNames) { if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) { currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class)); processedBeans.add(ppName); } } sortPostProcessors(currentRegistryProcessors, beanFactory); registryProcessors.addAll(currentRegistryProcessors); invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear(); booleanreiterate = true; while (reiterate) { reiterate = false; postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false); for (StringppName : 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, beanFactory.getApplicationStartup()); currentRegistryProcessors.clear(); } invokeBeanFactoryPostProcessors(registryProcessors, beanFactory); invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory); } else { invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory); } // BFPP的执行顺序与上一样/** *都有beanFactory.getBean方法,证明BFPP这个bean现在已经被创建了 */String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false); List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = newArrayList<>(); List<String> orderedPostProcessorNames = newArrayList<>(); List<String> nonOrderedPostProcessorNames = newArrayList<>(); for (StringppName : postProcessorNames) { if (processedBeans.contains(ppName)) { } elseif (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) { priorityOrderedPostProcessors.add(beanFactory.getBean(ppName, BeanFactoryPostProcessor.class)); } elseif (beanFactory.isTypeMatch(ppName, Ordered.class)) { orderedPostProcessorNames.add(ppName); } else { nonOrderedPostProcessorNames.add(ppName); } } sortPostProcessors(priorityOrderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory); List<BeanFactoryPostProcessor> orderedPostProcessors = newArrayList<>(orderedPostProcessorNames.size()); for (StringpostProcessorName : orderedPostProcessorNames) { orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } sortPostProcessors(orderedPostProcessors, beanFactory); invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory); List<BeanFactoryPostProcessor> nonOrderedPostProcessors = newArrayList<>(nonOrderedPostProcessorNames.size()); for (StringpostProcessorName : nonOrderedPostProcessorNames) { nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class)); } invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory); beanFactory.clearMetadataCache(); }
我们可以具体分析一下 BeanFactoryPostProcessor 的子类 CustomEditorConfigurer 自定义属性编辑器来巩固一下执行流程
所谓属性编辑器是当你要自定义更改配置文件中的属性属性时,如 String 类型转为 Date 或者其他,下面的一个小例子展示如何 String 类型的属性怎么转化为 Address 属性
Person 类
packagecn.demo1; importlombok.Getter; importlombok.Setter; @Setter@Getter@ToStringpublicclassPerson { privateStringname; privateAddressaddress; }
Address 类
packagecn.demo1; @Setter@Getter@ToStringpublicclassAddress { privateStringprovince; privateStringcity; }
AddressParse 类
packagecn.demo1; importjava.beans.PropertyEditorSupport; publicclassAddressParseextendsPropertyEditorSupport { @OverridepublicvoidsetAsText(Stringtext) throwsIllegalArgumentException { finalString[] vals = text.split(","); Addressaddr = newAddress(); addr.setProvince(vals[0]); addr.setCity(vals[1]); setValue(addr); } }
MyCustomEditor 类
packagecn.demo1; importorg.springframework.beans.PropertyEditorRegistrar; importorg.springframework.beans.PropertyEditorRegistry; publicclassMyCustomEditorimplementsPropertyEditorRegistrar { @OverridepublicvoidregisterCustomEditors(PropertyEditorRegistryregistry) { registry.registerCustomEditor(Address.class, newAddressParse()); } }
配置文件 test1.xml
<?xmlversion="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <!-- 待属性编辑的bean,value代表的就是string类型--> <beanclass="cn.demo1.Person"id="person"> <propertyname="name"value="李华"/> <propertyname="address"value="四川,成都"/> </bean> <!-- 注册属性编辑器--> <beanclass="org.springframework.beans.factory.config.CustomEditorConfigurer"id="configurer"> <propertyname="propertyEditorRegistrars"> <list> <beanclass="cn.demo1.MyCustomEditor"/> </list> </property> </bean> </beans>
测试类 EdT
packagecn.test1; importcn.demo1.Person; importorg.junit.Test; importorg.springframework.context.ApplicationContext; importorg.springframework.context.support.ClassPathXmlApplicationContext; publicclassEdT { @Testpublicvoidtest1() { ApplicationContextcontext = newClassPathXmlApplicationContext("test1.xml"); finalPersonbean = context.getBean(Person.class); System.out.println(bean); } } =====================测试结果Person(name=李华, address=Address(province=四川, city=成都))
可以看见我们成功的将 String 类型转化为 Address 类型,让我们来看看实现流程,
- 首先实现 PropertyEditorSupport 来自定义属性编辑规则
- 其次将你的编辑规则给到 PropertyEditorRegistrar 子类里进行注册
- 最后在 Spring 中配置 CustomEditorConfigurer 类然后注入你的 PropertyEditorRegistrar 注册器
让我们 debug 走一遍
如果你已经耐心看完上面的BeanFactoryPostProcessor执行时期的探究
那么你应该可以知道接下来我们的步骤应该是进入 invokeBeanFactoryPostProcessors 这个方法里了
privatestaticvoidinvokeBeanFactoryPostProcessors( Collection<? extendsBeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactorybeanFactory) { for (BeanFactoryPostProcessorpostProcessor : postProcessors) { StartupSteppostProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process") .tag("postProcessor", postProcessor::toString); postProcessor.postProcessBeanFactory(beanFactory); postProcessBeanFactory.end(); } }
很明显它执行 postProcessBeanFactory 这个方法
我们探究的 BFPP 正是 CustomEditorConfigurer,所以这个是 CustomEditorConfigurer 对 BFPP 的 postProcessBeanFactory 实现
// 必然有个set方法让我们进行注入publicvoidsetPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) { this.propertyEditorRegistrars = propertyEditorRegistrars; } @OverridepublicvoidpostProcessBeanFactory(ConfigurableListableBeanFactorybeanFactory) throwsBeansException { if (this.propertyEditorRegistrars != null) { for (PropertyEditorRegistrarpropertyEditorRegistrar : this.propertyEditorRegistrars) { // 把它加入Bean工厂里后面可以进行调用privatefinalSet<PropertyEditorRegistrar> propertyEditorRegistrars = newLinkedHashSet<>(4); beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar); } } if (this.customEditors != null) { this.customEditors.forEach(beanFactory::registerCustomEditor); } }
关于这个注册器使用要到后面填充属性的时候才会用到,
我其实觉得这个有点瑕疵,因为 BFPP 作用影响应该是当 Spring 还未创建 bean 的时候,可以用 BFPP 进行修改操作,可是这个属性编辑却影响了 bean 创建过后的修改操作,那么它就替代了 BPP(BeanPostProcessor)的作用发挥了。(以上仅仅代表个人的观点,有可能是我想错了)
当我们 debug 到 AbstractAutowireCapableBeanFactory 的 populateBean 这个方法填充 bean 的属性的时候,
让我们看看它的方法,其中我省略了大部分无关代码
protectedvoidpopulateBean(StringbeanName, RootBeanDefinitionmbd, @NullableBeanWrapperbw) { // 这个是如果你配置的bean中有属性值的话// 也就是如下的配置,那么pvs不会为空的/** <bean class="cn.demo1.Person" id="person"> <property name="name" value="李华"/> <property name="address" value="四川,成都"/> </bean> */PropertyValuespvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null); if (pvs != null) { // 属性操作applyPropertyValues(beanName, mbd, bw, pvs); } }
让我们继续看看 applyPropertyValues 这个方法,无关的代码我也给省略了
protectedvoidapplyPropertyValues(StringbeanName, BeanDefinitionmbd, BeanWrapperbw, PropertyValuespvs) { // PropertyValues接口的默认实现。允许对属性进行简单操作,并提供构造函数以支持从 Map 进行深度复制和构造。MutablePropertyValuesmpvs = null; List<PropertyValue> original; // 可以进去if (pvsinstanceofMutablePropertyValues) { mpvs = (MutablePropertyValues) pvs; // 默认为false,即我们需要类型转换if (mpvs.isConverted()) { // Shortcut: use the pre-converted values as-is.try { bw.setPropertyValues(mpvs); return; } catch (BeansExceptionex) { thrownewBeanCreationException( mbd.getResourceDescription(), beanName, "Error setting property values", ex); } } // 把bean的属性以列表的形式展示出来original = mpvs.getPropertyValueList(); } else { original = Arrays.asList(pvs.getPropertyValues()); } // 默认为空TypeConverterconverter = getCustomTypeConverter(); if (converter == null) { converter = bw; } // 就一个组合类,帮助更好的bean的属性的解析BeanDefinitionValueResolvervalueResolver = newBeanDefinitionValueResolver(this, beanName, mbd, converter); // 深拷贝List<PropertyValue> deepCopy = newArrayList<>(original.size()); booleanresolveNecessary = false; for (PropertyValuepv : original) { if (pv.isConverted()) { deepCopy.add(pv); } else { // 获取bean的属性名字StringpropertyName = pv.getName(); //获取bean属性值的包装对象ObjectoriginalValue = pv.getValue(); // 自动装配的事情if (originalValue == AutowiredPropertyMarker.INSTANCE) { MethodwriteMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod(); if (writeMethod == null) { thrownewIllegalArgumentException("Autowire marker for property without write method: " + pv); } originalValue = newDependencyDescriptor(newMethodParameter(writeMethod, 0), true); } // 把bean的属性值从包装类中分离出来ObjectresolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue); ObjectconvertedValue = resolvedValue; // 一般为truebooleanconvertible = bw.isWritableProperty(propertyName) && !PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName); if (convertible) { // 这个就是重点,对应我们的属性转化convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter); } }
继续追踪
@NullableprivateObjectconvertForProperty( @NullableObjectvalue, StringpropertyName, BeanWrapperbw, TypeConverterconverter) { // BeanWrapperImpl是继承TypeConverter的if (converterinstanceofBeanWrapperImpl) { // 所以执行下面的方法return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName); } else { PropertyDescriptorpd = bw.getPropertyDescriptor(propertyName); MethodParametermethodParam = BeanUtils.getWriteMethodParameter(pd); returnconverter.convertIfNecessary(value, pd.getPropertyType(), methodParam); } }
@NullablepublicObjectconvertForProperty(@NullableObjectvalue, StringpropertyName) throwsTypeMismatchException { CachedIntrospectionResultscachedIntrospectionResults = getCachedIntrospectionResults(); PropertyDescriptorpd = cachedIntrospectionResults.getPropertyDescriptor(propertyName); if (pd == null) { thrownewInvalidPropertyException(getRootClass(), getNestedPath() + propertyName, "No property '" + propertyName + "' found"); } TypeDescriptortd = cachedIntrospectionResults.getTypeDescriptor(pd); if (td == null) { td = cachedIntrospectionResults.addTypeDescriptor(pd, newTypeDescriptor(property(pd))); } // 上面的工作不用管,全是一些前戏工作,这个才是主题,至此我们的流程就到这里结束吧// 后面的流程太多了,大部分都是处理细节,你只需要知道大概的脉络就行,就是最终它肯定会// 走到AddressParse这个核心处理returnconvertForProperty(propertyName, null, value, td); }
你可以自己可以尝试 debug 一下,看别人实践真的不如自己动手实践一下,Spring 的包装类实属太多,但是可以抓住核心流程进行 debug。