mini-spring 学习笔记—扩展篇

最近在学习 mini-spring 项目,记录笔记以总结心得

IoC篇:mini-spring 学习笔记—IoC

AOP篇:mini-spring 学习笔记—AOP

高级篇:mini-spring 学习笔记—高级篇

PropertyPlaceholderConfigurer

将 bean 的属性信息统一写在 properties 文件中,本章实现解析 xml 文件中的占位符,通过占位符从 properties 文件中获取对应的信息。

本章的内容都在 PropertyPlaceholderConfigurer 类中,该类实现了 BeanFactoryPostProcessor 接口,可以看出来占位符的处理是在 bean 实例化之前完成。

包含三个成员变量

public static final String PLACEHOLDER_PREFIX = "${";
public static final String PLACEHOLDER_SUFFIX = "}";
private String location;

实现了 postProcessBeanFactory 方法

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
	//加载属性配置文件
	Properties properties = loadProperties();
	//属性值替换占位符
	processProperties(beanFactory, properties);
}

loadProperties 方法

读取 properties 文件的方式与读取 xml 文件类似,也是获取资源的输入流,使用 java 本身提供的工具读取输入流

processProperties 方法和 resolvePropertyValues 方法

processProperties 方法用于获取和遍历 bean 定义

private void processProperties(ConfigurableListableBeanFactory beanFactory, Properties properties) throws BeansException {
	// 获取所有的 bean 定义
	String[] beanDefinitionNames = beanFactory.getBeanDefinitionNames();
	// 遍历 bean 定义
	for (String beanName : beanDefinitionNames) {
		BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
		// 修改 bean 定义
		resolvePropertyValues(beanDefinition, properties);
	}
}

resolvePropertyValues 方法用于将读取出的 properties 文件中的内容修改 bean 定义,使用的方式与 xml 文档的处理类似

包扫描

@Component

关于自定义注解可以看看这篇博客

Componet 注解用于标记 bean,它又被三个注解所标记:

  • @Target(ElementType.TYPE):用于说明该注解所修饰对象的范围,ElementType.TYPE 表示用于描述类、接口或 Enum
  • @Retention(RetentionPolicy.RUNTIME):用于声明生命周期,RetentionPolicy.RUNTIME 表示在运行时注解仍然存在
  • @Documented:表示这个注解应该被 javadoc 记录

关于三个注解的详细解释可以看这篇博客

Component 注解仅有一个参数,表示 bean 的名称

String value() default "";

@Scope

Scope 注解被三个元注解修饰,表明它作用于方法、类、接口或 Enum,在运行时依然存在,并且可以被 javadoc 记录

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented

仅有一个参数,表示该 bean 的作用域,默认为单例 bean

String value() default "singleton";

ClassPathScanningCandidateComponentProvider 和 ClassPathBeanDefinitionScanner

ClassPathBeanDefinitionScanner 类用于扫描指定路径下带有 @Component 注解的类,并读取为 bean 定义。findCandidateComponents 为具体实现

public class ClassPathScanningCandidateComponentProvider {
	public Set<BeanDefinition> findCandidateComponents(String basePackage) {
		// 使用 LinkedHashSet 实现
		Set<BeanDefinition> candidates = new LinkedHashSet<>();
		// 扫描有 org.springframework.stereotype.Component 注解的类, 组成一个集合
		Set<Class<?>> classes = ClassUtil.scanPackageByAnnotation(basePackage, Component.class);
		for (Class<?> clazz : classes) {
			// 为带有 Component 注解的 bean 进行定义
			BeanDefinition beanDefinition = new BeanDefinition(clazz);
			candidates.add(beanDefinition);
		}
		return candidates;
	}
}

ClassPathBeanDefinitionScanner 继承自 ClassPathScanningCandidateComponentProvider,完成 bean 定义扫描完成后的解析定义域、改名和注册工作,仅有一个成员变量表示 bean 定义注册表

private BeanDefinitionRegistry registry;

doScan 方法

该方法接收一系列需要扫描的包路径,调用 findCandidateComponents 方法获得所有的 bean 定义之后解析 bean 的作用域和名称,最后向注册表内添加 bean 定义

public void doScan(String... basePackages) {
	for(String basePackage : basePackages) {
		// 获取这个包下所有的 bean 定义
		Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
		for(BeanDefinition candidate : candidates) {
			// 解析bean的作用域
			String beanScope = resolveBeanScope(candidate);
			if(StrUtil.isNotEmpty(beanScope)) {
				candidate.setScope(beanScope);
			}
			//生成bean的名称
			String beanName = determineBeanName(candidate);
			//注册BeanDefinition
			registry.registerBeanDefinition(beanName, candidate);
		}
	}
}

resolveBeanScope 方法

该方法用于获取 bean 的作用域,通过读取 @Scope 注解的值实现

private String resolveBeanScope(BeanDefinition beanDefinition) {
	Class<?> beanClass = beanDefinition.getBeanClass();
	Scope scope = beanClass.getAnnotation(Scope.class);
	if(scope != null) {
		return scope.value();
	}
	return StrUtil.EMPTY;
}

determineBeanName 方法

该方法读取类的名称,之后将首字母小写作为 bean 的名称

private String determineBeanName(BeanDefinition beanDefinition) {
	Class<?> beanClass = beanDefinition.getBeanClass();
	Component component = beanClass.getAnnotation(Component.class);
	String value = component.value();

	if(StrUtil.isEmpty(value)) {
		value = StrUtil.lowerFirst(beanClass.getSimpleName());
		System.out.println("value = " + value);
	}
	return value;
}

XmlBeanDefinitionReader

新增两个静态成员变量,用于判断 xml 文件中的标签

public static final String BASE_PACKAGE_ATTRIBUTE = "base-package";
public static final String COMPONENT_SCAN_ELEMENT = "component-scan";

新增 scanPackage 方法,用于调用 doScan 方法扫描包

private void scanPackage(String scanPath) {
	String[] basePackages = StrUtil.splitToArray(scanPath, ',');
	ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(getRegistry());
	scanner.doScan(basePackages);
}

doLoadBeanDefinitions 方法中新增对 context:component-scan 标签的判断

Element componentScan = root.element(COMPONENT_SCAN_ELEMENT);
if (componentScan != null) {
	String scanPath = componentScan.attributeValue(BASE_PACKAGE_ATTRIBUTE);
	if (StrUtil.isEmpty(scanPath)) {
		throw new BeansException("The value of base-package attribute can not be empty or null");
	}
	scanPackage(scanPath);
}

BeanDefinition

重写了 equals 方法和 hashCode 方法,重写后根据 beanClass 来判断 true 或者 false

public boolean equals(Object o) {
	if (this == o) return true;
	if (o == null || getClass() != o.getClass()) return false;
	BeanDefinition that = (BeanDefinition) o;
	return beanClass.equals(that.beanClass);
}

@Value 注解

@Value

@Value 被两个个元注解修饰,表明它作用于字段、方法、参数,且在运行时依然存在

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER})

只有一个参数,代表要赋予的值

String value();

InstantiationAwareBeanPostProcessor 和 AutowiredAnnotationBeanPostProcessor

InstantiationAwareBeanPostProcessor 接口增加方法 postProcessPropertyValuesbean 实例化之后,设置属性之前执行

PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException;

AutowiredAnnotationBeanPostProcessor 类实现了 InstantiationAwareBeanPostProcessor 接口和 BeanFactoryAware 接口,能够在 bean 实例化之后,设置属性之前为 bean 填入 @Value 注解中的值,同时它包含一个成员变量用于感知 bean 工厂

private ConfigurableListableBeanFactory beanFactory;

主要方法为 postProcessPropertyValues

public PropertyValues postProcessPropertyValues(PropertyValues pvs, Object bean, String beanName) throws BeansException {
	// 处理@Value注解
	Class<?> clazz = bean.getClass();
	// 获取所有字段
	Field[] fields = clazz.getDeclaredFields();
	// 遍历字段数组
	for (Field field : fields) {
		// 获取每个字段的 Value 注解
		Value valueAnnotation = field.getAnnotation(Value.class);
		if (valueAnnotation != null) {
			String value = valueAnnotation.value();
			value = beanFactory.resolveEmbeddedValue(value);
			BeanUtil.setFieldValue(bean, field.getName(), value);
		}
	}

	//处理@Autowired注解(下一节实现)

	return pvs;
}

其中

value = beanFactory.resolveEmbeddedValue(value)

resolveEmbeddedValue 函数用于对 @Value 注解中的值做预处理(比如注解的值为 "#{name}" 这种变量,需要替换为真实值),该函数位于 AbstractBeanFactory 类中

public String resolveEmbeddedValue(String value) {
	String result = value;
	for (StringValueResolver resolver : this.embeddedValueResolvers) {
		result = resolver.resolveStringValue(result);
	}
	return result;
}

AbstractBeanFactory 类新增了变量 embeddedValueResolvers 存储所有的解析器

private final List<StringValueResolver> embeddedValueResolvers = new ArrayList<>();

resolveStringValue 函数由 StringValueResolver 接口规定,用于实现字符串值的解析

String resolveStringValue(String strVal);

一个实现位于 PropertyPlaceholderConfigurer 类中,直接传入占位符解析替换方法进行处理

public String resolveStringValue(String strVal) throws BeansException {
	return PropertyPlaceholderConfigurer.this.resolvePlaceholder(strVal, properties);
}

AbstractAutowireCapableBeanFactory

doCreateBean 方法中新增 applyBeanPostprocessorsBeforeApplyingPropertyValues 方法调用,在设置 bean 属性之前修改属性值

// doCreateBean 方法
bean = createBeanInstance(beanDefinition);
//在设置bean属性之前,允许BeanPostProcessor修改属性值
applyBeanPostprocessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
//为bean填充属性
applyPropertyValues(beanName, bean, beanDefinition);
//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法
initializeBean(beanName, bean, beanDefinition);

applyBeanPostprocessorsBeforeApplyingPropertyValues 方法的实现与其他 BeanPostProcessor 的方法实现大同小异

protected void applyBeanPostprocessorsBeforeApplyingPropertyValues(String beanName, Object bean, BeanDefinition beanDefinition) {
	for (BeanPostProcessor beanPostProcessor : getBeanPostProcessors()) {
		if (beanPostProcessor instanceof InstantiationAwareBeanPostProcessor) {
			// Value 注解注入
			PropertyValues pvs = ((InstantiationAwareBeanPostProcessor) beanPostProcessor).postProcessPropertyValues(beanDefinition.getPropertyValues(), bean, beanName);
			if (pvs != null) {
				for (PropertyValue propertyValue : pvs.getPropertyValues()) {
					beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
				}
			}
		}
	}
}

ClassPathBeanDefinitionScanner

新增静态成员常量 AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME,记录注入注解处理类的名称

public static final String AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME = "org.springframework.context.annotation.internalAutowiredAnnotationProcessor";

doScan 方法中新增对注入注解处理类的注册

// doScan 方法
registry.registerBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME, new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));

@Autowired 注解

@Autowired 和 @Qualifier

@Autowired 被两个元注解修饰,表明它作用于字段、方法、构造器,且在运行时依然存在

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
public @interface Autowired {}

@Qualifier 被四个元注解修饰,仅有一个参数

@Retention(RetentionPolicy.RUNTIME)
// 作用范围为字段、方法、参数、类、注解类型声明
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE})
// 子类可以继承被 Inherited 修饰的注解
@Inherited
// 这个注解会被 javadoc 显示
@Documented
public @interface Qualifier {
	String value() default "";
}

AutowiredAnnotationBeanPostProcessor

新增处理 @Autowired 注解代码,在 postProcessPropertyValues 方法中

// postProcessPropertyValues 方法
for (Field field : fields) {
	// 获取 Autowired 注解
	Autowired autowiredAnnotation = field.getAnnotation(Autowired.class);
	// 如果这个字段被 Autowired 修饰
	if (autowiredAnnotation != null) {
		// 获取字段类型
		Class<?> fieldType = field.getType();
		// 所依赖的 bean 的名称
		String dependentBeanName;
		// 获取 Qualifier 注解
		Qualifier qualifierAnnotation = field.getAnnotation(Qualifier.class);
		Object dependentBean;
		if (qualifierAnnotation != null) {
			dependentBeanName = qualifierAnnotation.value();
			dependentBean = beanFactory.getBean(dependentBeanName, fieldType);
		} else {
			dependentBean = beanFactory.getBean(fieldType);
		}
		BeanUtil.setFieldValue(bean, field.getName(), dependentBean);
	}
}

此处可以看到 @Qualifier 注解的作用:判断该字段是不是 bean

BeanFactory 和 DefaultListableBeanFactory

为了实现 postProcessPropertyValues 中根据字段类型获取字段值的调用,BeanFactory 接口重载方法 getBean

<T> T getBean(Class<T> requiredType) throws BeansException;

DefaultListableBeanFactory 类中实现了该方法

public <T> T getBean(Class<T> requiredType) throws BeansException {
	List<String> beanNames = new ArrayList<>();
	for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
		Class beanClass = entry.getValue().getBeanClass();
		if (requiredType.isAssignableFrom(beanClass)) {
			beanNames.add(entry.getKey());
		}
	}
	if (beanNames.size() == 1) {
		return getBean(beanNames.get(0), requiredType);
	}

	throw new BeansException(requiredType + "expected single bean but found " + beanNames.size() + ": " + beanNames);
}

AbstractApplicationContext

该类中同样新增重载方法 getBean

public <T> T getBean(Class<T> requiredType) throws BeansException {
	return getBeanFactory().getBean(requiredType);
}

bug fix:没有为代理bean设置属性

这章我也没大看懂

查看更改代码需要查看“为AOP代理对象注入属性”提交,修订号为 9e2b1e451e9ea465aa48b0e0e5f026c4d5185a56

DefaultAdvisorAutoProxyCreator

主要改动为将 postProcessBeforeInstantiation 方法中的内容放入 postProcessAfterInitialization

本章小结

目前 bean 的生命周期

image

类型转换(一)

Converter

Converter 接口规范了类型转换的行为规范,它是泛型接口,将 S 类型转化为 T 类型

public interface Converter<S, T> {
	T convert(S source);
}

ConverterFactory 和 ConverterRegistry

ConverterFactory 接口规范了类型转换工厂,用于生产出指定的类型转换器

public interface ConverterFactory<S, R> {
	<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}

ConverterRegistry 接口规范了注册转换器和转换工厂的行为,此处所有出现泛型通配符的地方,都用 ?,用于代表任何类型

public interface ConverterRegistry {
	void addConverter(Converter<?, ?> converter);
	void addConverterFactory(ConverterFactory<?, ?> converterFactory);
	void addConverter(GenericConverter converter);
}

GenericConverter

GenericConverter 接口中定义了静态类 ConvertiblePair

ConvertiblePair 类有两个成员变量,分别表示源类型和目标类型

private final Class<?> sourceType;
private final Class<?> targetType;

GenericConverter 接口中可以获得一系列的 ConvertiblePair

Set<ConvertiblePair> getConvertibleTypes();

ConversionService

ConversionService 接口是类型转换体系的核心,规范了转换服务的行为,有两个方法

boolean canConvert(Class<?> sourceType, Class<?> targetType);
<T> T convert(Object source, Class<T> targetType);

GenericConversionService

GenericConversionService 类实现了 ConversionServiceConverterRegistry 两个接口,具有提供类型转换服务注册转换器的功能,具有一个 Map 类型的成员变量 converters,用于记录 <转换类型,转换器对象>

private Map<ConvertiblePair, GenericConverter> converters = new HashMap<>();

这里挑部分方法和内部类进行讲解

getClassHierarchy 方法

英文单词 hierarchy 直译为“等级制度”,在这里可以理解为“层次结构”,所以该方法用于获取传入类型变量 clazz 的所有父类,方法内部使用类似于遍历链表的方法,遍历 clazz 的所有父类并放入列表 hierarchy

private List<Class<?>> getClassHierarchy(Class<?> clazz) {
	List<Class<?>> hierarchy = new ArrayList<>();
	while (clazz != null) {
		hierarchy.add(clazz);
		clazz = clazz.getSuperclass();
	}
	return hierarchy;
}

getConverter 方法

该方法用于获取从 sourceTypetargetType 之间的转换器。具体实现为,先获取两个类型的所有父类集合,遍历两个集合的笛卡尔积,看看有没有对应两个类型的转换器,如果有的话则返回该转换器;遍历结束都没有的话,返回 null

protected GenericConverter getConverter(Class<?> sourceType, Class<?> targetType) {
	List<Class<?>> sourceCandidates = getClassHierarchy(sourceType);
	List<Class<?>> targetCandidates = getClassHierarchy(targetType);
	for (Class<?> sourceCandidate : sourceCandidates) {
		for (Class<?> targetCandidate : targetCandidates) {
			ConvertiblePair convertiblePair = new ConvertiblePair(sourceCandidate, targetCandidate);
			GenericConverter converter = converters.get(convertiblePair);
			if (converter != null) {
				return converter;
			}
		}
	}
	return null;
}

getRequiredTypeInfo 方法

getGenericInterfaces 方法与 getInterfaces 相似,都是用于返回类型的接口,但是前者同时也会返回接口中的泛型信息,并且前者返回类型为 Type 数组,后者为 Class 数组。之后使用 ParameterizedType 类型包裹泛型接口,调用 getActualTypeArguments 方法获取其中的泛型类信息(比如 Response<Person> 中返回 Person.class)关于ParameterizedType 类型的更多信息,可以看这篇博客

最后通过两个泛型类信息,构建一个 ConvertiblePair 对象。

这个方法我也不大懂

private ConvertiblePair getRequiredTypeInfo(Object object) {
	// 获取带有泛型的实现的接口信息
	Type[] types = object.getClass().getGenericInterfaces();
	// 使用 ParameterizedType 包裹
	ParameterizedType parameterized = (ParameterizedType) types[0];
	// 获取包装类中的泛型类(比如 Response<Person> 中返回 Person.class)
	Type[] actualTypeArguments = parameterized.getActualTypeArguments();
	Class sourceType = (Class) actualTypeArguments[0];
	Class targetType = (Class) actualTypeArguments[1];
	return new ConvertiblePair(sourceType, targetType);
}

类型转换(二)

本章按 log 中两个类型转换的时机来讲解:为 bean 填充属性时、处理 @Value 注解时

为 bean 填充属性时

AbstractAutowireCapableBeanFactory

applyPropertyValues 方法中增加如下代码

// applyPropertyValues 方法
Class<?> sourceType = value.getClass();
Class<?> targetType = (Class<?>) TypeUtil.getFieldType(bean.getClass(), name);
ConversionService conversionService = getConversionService();
if (conversionService != null) {
	if (conversionService.canConvert(sourceType, targetType)) {
		value = conversionService.convert(value, targetType);
	}
}

处理 @Value 注解时

AutowiredAnnotationBeanPostProcessor

postProcessPropertyValues 方法中增加如下代码

// postProcessPropertyValues 方法
Object value = valueAnnotation.value();
value = beanFactory.resolveEmbeddedValue((String) value);
//类型转换
Class<?> sourceType = value.getClass();
Class<?> targetType = (Class<?>) TypeUtil.getType(field);
ConversionService conversionService = beanFactory.getConversionService();
if (conversionService != null) {
	if (conversionService.canConvert(sourceType, targetType)) {
		value = conversionService.convert(value, targetType);
	}
}

注册类型转换器

同样,要使用类型转换器就要先注册类型转换器,这项功能在 ConversionServiceFactoryBean 类中提供。该类包含两个成员变量

private Set<?> converters;
private GenericConversionService conversionService;

使用 registerConverters 方法注册转换器

private void registerConverters(Set<?> converters, ConverterRegistry registry) {
	if (converters != null) {
		for (Object converter : converters) {
			if (converter instanceof GenericConverter) {
				registry.addConverter((GenericConverter) converter);
			} else if (converter instanceof Converter<?, ?>) {
				registry.addConverter((Converter<?, ?>) converter);
			} else if (converter instanceof ConverterFactory<?, ?>) {
				registry.addConverterFactory((ConverterFactory<?, ?>) converter);
			} else {
				throw new IllegalArgumentException("Each converter object must implement one of the " +
												   "Converter, ConverterFactory, or GenericConverter interfaces");
			}
		}
	}
}

然后再 xml 文件中写入该工厂 bean

<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
	<property name="converters" ref="converters"/>
</bean>

<bean id="converters" class="org.springframework.test.common.ConvertersFactoryBean"/>

融入生命周期

最后在 AbstractApplicationContext 类中加入类型转换服务的使用,融入 bean 的生命周期

refresh 方法中,将 beanFactory.preInstantiateSingletons(); 放入 finishBeanFactoryInitialization(beanFactory); 方法中,即先设置类型转换服务,再进行 bean 的实例化

protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	//设置类型转换服务
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
		Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);
		if (conversionService instanceof ConversionService) {
			beanFactory.setConversionService((ConversionService) conversionService);
		}
	}
	//提前实例化单例bean
	beanFactory.preInstantiateSingletons();
}

而类型转换器的注册,发生在 bean 的初始化阶段,具体看 AbstractAutowireCapableBeanFactoryinvokeInitMethods 方法

// invokeInitMethods 方法
if (bean instanceof InitializingBean) {
	((InitializingBean) bean).afterPropertiesSet();
}

通过调用 bean 的 afterPropertiesSet 方法进入到转换器注册方法中

public void afterPropertiesSet() throws Exception {
	conversionService = new DefaultConversionService();
	registerConverters(converters, conversionService);
}
posted @ 2023-12-09 12:26  Frodo1124  阅读(39)  评论(0编辑  收藏  举报