You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

482 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

BeanFactoryBeanPostProcessor是当BeanDefinition读取完元数据也就是从任意资源中定义的bean数据后还未实例化之前可以进行修改
抄录并翻译官方的语句
> `BeanFactoryPostProcessor` 操作 bean 的元数据配置. 也就是说,Spring IoC 容器允许 `BeanFactoryPostProcessor` 读取配置元数据, 并可能在容器实例化除 `BeanFactoryPostProcessor` 实例之外的任何bean *之前* 更改它
tip:
> 在 `BeanFactoryPostProcessor` (例如使用 `BeanFactory.getBean()`) 中使用这些 bean 的实例虽然在技术上是可行的,但这么来做会将bean过早实例化, 这违反了标准的容器生命周期. 同时也会引发一些副作用,例如绕过 bean 的后置处理.
```java
public interface BeanFactoryPostProcessor {
/**
*通过ConfigurableListableBeanFactory这个可配置的BeanFactory对我们的bean原数据进行修改
*/
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException;
}
```
#### BeanFactoryPostProcessor执行时期的探究
ApplicationContext的refresh()中的invokeBeanFactoryPostProcessors方法就开始创建我们的BFPP(BeanFactoryPostProcessor)了
具体执行方法invokeBeanFactoryPostProcessors虽然一百多行代码其实只需要特别了解的地方就几处
```java
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
public static void invokeBeanFactoryPostProcessors(
ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {
Set<String> processedBeans = new HashSet<>();
//由于我们的beanFactory是DefaultListableBeanFactory实例是BeanDefinitionRegistry的子类所以可以进来
if (beanFactory instanceof BeanDefinitionRegistry) {
BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
BeanDefinitionRegistryPostProcessor registryProcessor =
(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 = new ArrayList<>();
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);
}
}
sortPostProcessors(currentRegistryProcessors, beanFactory);
registryProcessors.addAll(currentRegistryProcessors);
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry, beanFactory.getApplicationStartup());
currentRegistryProcessors.clear();
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : 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();
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, 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 = new ArrayList<>();
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (processedBeans.contains(ppName)) {
}
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);
}
}
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
List<BeanFactoryPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String postProcessorName : orderedPostProcessorNames) {
orderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
sortPostProcessors(orderedPostProcessors, beanFactory);
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
List<BeanFactoryPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String postProcessorName : nonOrderedPostProcessorNames) {
nonOrderedPostProcessors.add(beanFactory.getBean(postProcessorName, BeanFactoryPostProcessor.class));
}
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);
beanFactory.clearMetadataCache();
}
```
我们可以具体分析一下BeanFactoryPostProcessor的子类CustomEditorConfigurer自定义属性编辑器来巩固一下执行流程
所谓属性编辑器是当你要自定义更改配置文件中的属性属性时如String类型转为Date或者其他下面的一个小例子展示如何String类型的属性怎么转化为Address属性
#### 简单工程Spirng-version-5.3.18)
Person类
```java
package cn.demo1;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
@ToString
public class Person {
private String name;
private Address address;
}
```
Address类
```java
package cn.demo1;
@Setter
@Getter
@ToString
public class Address {
private String city;
private String town;
}
```
AddressParse类
```java
package cn.demo1;
import java.beans.PropertyEditorSupport;
public class AddressParse extends PropertyEditorSupport {
@Override
public void setAsText(String text) throws IllegalArgumentException {
final String[] vals = text.split(",");
Address addr = new Address();
addr.setProvince(vals[0]);
addr.setCity(vals[1]);
setValue(addr);
}
}
```
MyCustomEditor类
```java
package cn.demo1;
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;
public class MyCustomEditor implements PropertyEditorRegistrar {
@Override
public void registerCustomEditors(PropertyEditorRegistry registry) {
registry.registerCustomEditor(Address.class, new AddressParse());
}
}
```
配置文件test1.xml
```java
<?xml version="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">
<!-- 待属性编辑的beanvalue代表的就是string类型-->
<bean class="cn.demo1.Person" id="person">
<property name="name" value="李华"/>
<property name="address" value="四川,成都"/>
</bean>
<!-- 注册属性编辑器-->
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer" id="configurer">
<property name="propertyEditorRegistrars">
<list>
<bean class="cn.demo1.MyCustomEditor"/>
</list>
</property>
</bean>
</beans>
```
测试类EdT
```java
package cn.test1;
import cn.demo1.Person;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class EdT {
@Test
public void test1() {
ApplicationContext context = new ClassPathXmlApplicationContext("test1.xml");
final Person bean = context.getBean(Person.class);
System.out.println(bean);
}
}
=====================测试结果
Person(name=李华, address=Address(province=四川, city=成都))
```
可以看见我们成功的将String类型转化为Address类型让我们来看看实现流程
- 首先实现PropertyEditorSupport来自定义属性编辑规则
- 其次将你的编辑规则给到PropertyEditorRegistrar子类里进行注册
- 最后在Spring中配置CustomEditorConfigurer类然后注入你的PropertyEditorRegistrar注册器
让我们debug走一遍
如果你已经耐心看完上面的```BeanFactoryPostProcessor执行时期的探究```那么你应该可以知道接下来我们的步骤应该是进入invokeBeanFactoryPostProcessors这个方法里了
```java
private static void invokeBeanFactoryPostProcessors(
Collection<? extends BeanFactoryPostProcessor> postProcessors, ConfigurableListableBeanFactory beanFactory) {
for (BeanFactoryPostProcessor postProcessor : postProcessors) {
StartupStep postProcessBeanFactory = beanFactory.getApplicationStartup().start("spring.context.bean-factory.post-process")
.tag("postProcessor", postProcessor::toString);
postProcessor.postProcessBeanFactory(beanFactory);
postProcessBeanFactory.end();
}
}
```
很明显它执行postProcessBeanFactory这个方法
我们探究的BFPP正是CustomEditorConfigurer所以这个是CustomEditorConfigurer对BFPP的postProcessBeanFactory实现
```java
//必然有个set方法让我们进行注入
public void setPropertyEditorRegistrars(PropertyEditorRegistrar[] propertyEditorRegistrars) {
this.propertyEditorRegistrars = propertyEditorRegistrars;
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
if (this.propertyEditorRegistrars != null) {
for (PropertyEditorRegistrar propertyEditorRegistrar : this.propertyEditorRegistrars) {
//把它加入Bean工厂里后面可以进行调用
private final Set<PropertyEditorRegistrar> propertyEditorRegistrars = new LinkedHashSet<>(4);
beanFactory.addPropertyEditorRegistrar(propertyEditorRegistrar);
}
}
if (this.customEditors != null) {
this.customEditors.forEach(beanFactory::registerCustomEditor);
}
}
```
关于这个注册器使用要到后面填充属性的时候才会用到,
> 我其实觉得这个有点瑕疵因为BFPP作用影响应该是当Spring还未创建bean的时候可以用BFPP进行修改操作可是这个属性编辑却影响了bean创建过后的修改操作那么它就替代了BPPBeanPostProcessor)的作用发挥了。(以上仅仅代表个人的观点,有可能是我想错了)
当我们debug到AbstractAutowireCapableBeanFactory的populateBean这个方法填充bean的属性的时候
让我们看看它的方法,其中我省略了大部分无关代码
```java
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
//这个是如果你配置的bean中有属性值的话
//也就是如下的配置那么pvs不会为空的
/**
<bean class="cn.demo1.Person" id="person">
<property name="name" value="李华"/>
<property name="address" value="四川,成都"/>
</bean>
*/
PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
if (pvs != null) {
//属性操作
applyPropertyValues(beanName, mbd, bw, pvs);
}
}
```
让我们继续看看applyPropertyValues这个方法无关的代码我也给省略了
```java
protected void applyPropertyValues(String beanName, BeanDefinition mbd, BeanWrapper bw, PropertyValues pvs) {
//PropertyValues接口的默认实现。允许对属性进行简单操作并提供构造函数以支持从 Map 进行深度复制和构造。
MutablePropertyValues mpvs = null;
List<PropertyValue> original;
//可以进去
if (pvs instanceof MutablePropertyValues) {
mpvs = (MutablePropertyValues) pvs;
//默认为false即我们需要类型转换
if (mpvs.isConverted()) {
// Shortcut: use the pre-converted values as-is.
try {
bw.setPropertyValues(mpvs);
return;
}
catch (BeansException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Error setting property values", ex);
}
}
//把bean的属性以列表的形式展示出来
original = mpvs.getPropertyValueList();
}
else {
original = Arrays.asList(pvs.getPropertyValues());
}
//默认为空
TypeConverter converter = getCustomTypeConverter();
if (converter == null) {
converter = bw;
}
//就一个组合类帮助更好的bean的属性的解析
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this, beanName, mbd, converter);
//深拷贝
List<PropertyValue> deepCopy = new ArrayList<>(original.size());
boolean resolveNecessary = false;
for (PropertyValue pv : original) {
if (pv.isConverted()) {
deepCopy.add(pv);
}
else {
//获取bean的属性名字
String propertyName = pv.getName();
//获取bean属性值的包装对象
Object originalValue = pv.getValue();
//自动装配的事情
if (originalValue == AutowiredPropertyMarker.INSTANCE) {
Method writeMethod = bw.getPropertyDescriptor(propertyName).getWriteMethod();
if (writeMethod == null) {
throw new IllegalArgumentException("Autowire marker for property without write method: " + pv);
}
originalValue = new DependencyDescriptor(new MethodParameter(writeMethod, 0), true);
}
//把bean的属性值从包装类中分离出来
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);
Object convertedValue = resolvedValue;
//一般为true
boolean convertible = bw.isWritableProperty(propertyName) &&
!PropertyAccessorUtils.isNestedOrIndexedProperty(propertyName);
if (convertible) {
//这个就是重点,对应我们的属性转化
convertedValue = convertForProperty(resolvedValue, propertyName, bw, converter);
}
}
```
继续追踪
```java
@Nullable
private Object convertForProperty(
@Nullable Object value, String propertyName, BeanWrapper bw, TypeConverter converter) {
//BeanWrapperImpl是继承TypeConverter的
if (converter instanceof BeanWrapperImpl) {
//所以执行下面的方法
return ((BeanWrapperImpl) converter).convertForProperty(value, propertyName);
}
else {
PropertyDescriptor pd = bw.getPropertyDescriptor(propertyName);
MethodParameter methodParam = BeanUtils.getWriteMethodParameter(pd);
return converter.convertIfNecessary(value, pd.getPropertyType(), methodParam);
}
}
```
```java
@Nullable
public Object convertForProperty(@Nullable Object value, String propertyName) throws TypeMismatchException {
CachedIntrospectionResults cachedIntrospectionResults = getCachedIntrospectionResults();
PropertyDescriptor pd = cachedIntrospectionResults.getPropertyDescriptor(propertyName);
if (pd == null) {
throw new InvalidPropertyException(getRootClass(), getNestedPath() + propertyName,
"No property '" + propertyName + "' found");
}
TypeDescriptor td = cachedIntrospectionResults.getTypeDescriptor(pd);
if (td == null) {
td = cachedIntrospectionResults.addTypeDescriptor(pd, new TypeDescriptor(property(pd)));
}
//上面的工作不用管,全是一些前戏工作,这个才是主题,至此我们的流程就到这里结束吧
//后面的流程太多了,大部分都是处理细节,你只需要知道大概的脉络就行,就是最终它肯定会
//走到AddressParse这个核心处理
return convertForProperty(propertyName, null, value, td);
}
```
你可以自己可以尝试debug一下看别人实践真的不如自己动手实践一下Spring的包装类实属太多但是可以抓住核心流程进行debug