title: Spring 框架源码解读9
date: 2020/04/18 20:12
开场
今天我们先把昨天的 ConfigurationClassPostProcessor 仔细讲一讲,然后再开始今天要学的内容。
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor,
PriorityOrdered, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware {
...
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
...
processConfigBeanDefinitions(registry);
}
/**
* 拿出的所有bd,然后判断bd是否包含了@Configuration、@Import,@Compent....等注解
* Build and validate a configuration model based on the registry of
* {@link Configuration} classes.
*/
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
//获取所有的bd定义类spring的6个,还有自己定义的(也就是加了@configuration注解的)
String[] candidateNames = registry.getBeanDefinitionNames();
// FULL、LITE
for (String beanName : candidateNames) {
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
if (ConfigurationClassUtils.isFullConfigurationClass(beanDef) || ConfigurationClassUtils.isLiteConfigurationClass(beanDef)) {
//如果BeanDefinition中的ConfigurationClass为full 或者lite,证明已经处理过了,则跳过
//这里要根据后面的代码来理解
if (logger.isDebugEnabled()) {
logger.debug("Bean definition has already been processed as a configuration class: " + beanDef);
}
}
//判断是否加了Configration注解,加了则设定他的configrationclass 为full
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
//如果加了则放进我们定义的set<bd>集合中去
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//如果没有找到@Configration注解的类,则直接返回
// Return immediately if no @Configuration classes were found
if (configCandidates.isEmpty()) {
return;
}
//排序,根据order进行排序,不重要 (如果有多个配置类,则会根据配置中加的@Order注解内容进行排序)
// Sort by previously determined @Order value, if applicable
configCandidates.sort((bd1, bd2) -> {
int i1 = ConfigurationClassUtils.getOrder(bd1.getBeanDefinition());
int i2 = ConfigurationClassUtils.getOrder(bd2.getBeanDefinition());
return Integer.compare(i1, i2);
});
...
//初始化一个解析器
// Parse each @Configuration class
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry);
Set<BeanDefinitionHolder> candidates = new LinkedHashSet<>(configCandidates);
Set<ConfigurationClass> alreadyParsed = new HashSet<>(configCandidates.size());
/**
* 解析每一个加了@Configuration的类,
* 实际上我们这里只有一个(可能会有多个,比如加入SpringMvc的配置类),
* 也就是我们的配置类AppConfig
*/
do {
//这行代码就是具体的bd的解析过程;我们点进去 -> 1.1
parser.parse(candidates);
parser.validate();
//来看下parser.getConfigurationClasses()方法
/*
* public Set<ConfigurationClass> getConfigurationClasses() {
* return this.configurationClasses.keySet();
* }
*/
//configurationClasses这个集合是不是就是我们解析import类后,把import类放到这里面了?
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed);
// Read the model and create bean definitions based on its content
if (this.reader == null) {
this.reader = new ConfigurationClassBeanDefinitionReader(
registry, this.sourceExtractor, this.resourceLoader, this.environment,
this.importBeanNameGenerator, parser.getImportRegistry());
}
//这里是把我们通过Import(包括3种方法)进来的类注册到map中去
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
candidates.clear();
if (registry.getBeanDefinitionCount() > candidateNames.length) {
String[] newCandidateNames = registry.getBeanDefinitionNames();
Set<String> oldCandidateNames = new HashSet<>(Arrays.asList(candidateNames));
Set<String> alreadyParsedClasses = new HashSet<>();
for (ConfigurationClass configurationClass : alreadyParsed) {
alreadyParsedClasses.add(configurationClass.getMetadata().getClassName());
}
for (String candidateName : newCandidateNames) {
if (!oldCandidateNames.contains(candidateName)) {
BeanDefinition bd = registry.getBeanDefinition(candidateName);
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
// Register the ImportRegistry as a bean in order to support ImportAware @Configuration classes
if (sbr != null && !sbr.containsSingleton(IMPORT_REGISTRY_BEAN_NAME)) {
sbr.registerSingleton(IMPORT_REGISTRY_BEAN_NAME, parser.getImportRegistry());
}
if (this.metadataReaderFactory instanceof CachingMetadataReaderFactory) {
// Clear cache in externally provided MetadataReaderFactory; this is a no-op
// for a shared cache since it'll be cleared by the ApplicationContext.
((CachingMetadataReaderFactory) this.metadataReaderFactory).clearCache();
}
}
/**
* 1.1 ConfigurationClassParser#parse(),循环解析bd
*/
public void parse(Set<BeanDefinitionHolder> configCandidates) {
this.deferredImportSelectors = new LinkedList<>();
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
try {
// 这三个地方最终调的都是一个方法,只不过传入的东西不同 -> so,进入1.2
if (bd instanceof AnnotatedBeanDefinition) {
// 进行类型的封装
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
else if (bd instanceof AbstractBeanDefinition && ((AbstractBeanDefinition) bd).hasBeanClass()) {
//处理一些内部类,一般不会写内部类
parse(((AbstractBeanDefinition) bd).getBeanClass(), holder.getBeanName());
}
else {
parse(bd.getBeanClassName(), holder.getBeanName());
}
}
catch (BeanDefinitionStoreException ex) {
throw ex;
}
catch (Throwable ex) {
throw new BeanDefinitionStoreException(
"Failed to parse configuration class [" + bd.getBeanClassName() + "]", ex);
}
}
processDeferredImportSelectors();
}
然后进入了这个方法:
注:提前说一下 configClass.isImported() 是为了判断这个配置类是不是被其他配置类 Import 过了,避免重复的加载。
处理 @Bean 注解
然后就将解析好的 BeanMethod 信息放进了 ConfigurationClass 类中
后面注册 bd 部分代码如下:
这段代码很简单,大家想象就能想象到。
处理 @Import 注解
解析部分:
后面的上面(图a)已经讲过了,就不讲了。
ImportSelector 作用:根据启动的相关环境配置来决定让哪些类能够被Spring容器初始化。
总结
也就是说 ConfigurationClassPostProcessor 是解析 BeanFactory 中被标注了 @Configuration 注解的类中的注解,其中包括:
- @PropertySource - 用来引入 properties 配置文件的
- @Import - 实现了3个功能
- 动态的选择采用哪个类(ImportSelector)
- 通过注解的方式向 BF 注册 BD(ImportBeanDefinitionRegistrar)
- 引入配置类
- @ImportResource - 引入 Spring 的 xml 配置文件
- @ComponentScan - 扫描包
- @Bean - 将 @Bean 注解标注的方法返回值注入容器
- 接口的 default 方法 + 父类(这个不太懂)
本节内容
实现 @Import 注解
1、新增一些类
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
/**
* {@link Configuration}, {@link ImportSelector}, {@link ImportBeanDefinitionRegistrar}
* 或者普通的组件(Component)需要引入的
*/
Class<?>[] value();
}
/**
* 由类型决定的接口,这些类型根据给定的选择标准(通常是一个或多个注释属性)来确定应导入哪个@Configuration类。
*/
public interface ImportSelector {
/**
* @param importingClassMetadata 被 @Import 注解的类的注解元数据
*/
String[] selectImports(AnnotationMetadata importingClassMetadata);
}
public interface ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata 被 @Import 注解的类的注解元数据
* @param registry bd registry
*/
void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry);
}
public class AnnotationMetadata {
private Annotation[] annotations;
public AnnotationMetadata(Class<?> clazz) {
this.annotations = AnnotationUtil.getAnnotations(clazz, true);
}
public <T> T getAnnotation(Class<T> annotationClass) {
for (Annotation annotation : annotations) {
if (annotationClass.isAssignableFrom(annotation.annotationType())) {
return (T) annotation;
}
}
return null;
}
}
2、修改 ConfigurationClassPostProcessor
public class ConfigurationClassPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
ListableBeanFactory bf = (ListableBeanFactory) registry;
for (String bdName : bf.getBeanDefinitionNames()) {
BeanDefinition classBeanDefinition = registry.getBeanDefinition(bdName);
String className = classBeanDefinition.getClassName();
Class<?> clazz = ReflectUtils.getType(className);
// 找到类上携带 @Configuration 的
Configuration configuration = AnnotationUtil.getAnnotation(clazz, Configuration.class);
if (ObjectUtil.isNotEmpty(configuration)) {
// 处理 @Configuration 标注的类
this.processConfigurationClass(registry, classBeanDefinition, clazz);
}
}
}
private void processConfigurationClass(BeanDefinitionRegistry registry, BeanDefinition classBeanDefinition, Class<?> clazz) {
// 1、处理 @Import 注解
Import annotation = AnnotationUtil.getAnnotation(clazz, Import.class);
if (ObjectUtil.isNotEmpty(annotation) && ObjectUtil.isNotEmpty(annotation.value())) {
Class<?>[] importClasses = annotation.value();
// 获取被标注 @Import 注解类上的所有注解信息
AnnotationMetadata annotationMetadata = new AnnotationMetadata(clazz);
this.processImport(registry, importClasses, annotationMetadata);
}
// 2、处理 @Bean 注解
this.processBean(registry, classBeanDefinition, clazz);
}
private void processImport(BeanDefinitionRegistry registry, Class<?>[] importClasses, AnnotationMetadata annotationMetadata) {
for (Class<?> importClass : importClasses) {
// 1、将其 @Import 的类加入 bdMap 中
DefaultBeanDefinition bdDef = new DefaultBeanDefinition();
String beanName = StrUtil.lowerFirst(importClass.getSimpleName());
bdDef.setName(beanName);
bdDef.setClassName(importClass.getName());
registry.registerBeanDefinition(beanName, bdDef);
// 2、处理 Import 类型为 ImportSelector 的
if (ImportSelector.class.isAssignableFrom(importClass)) {
ImportSelector importSelector = (ImportSelector) ReflectUtil.newInstance(importClass);
// 根据注解信息选择 Import 哪个类
String[] selectors = importSelector.selectImports(annotationMetadata);
Class<?>[] selectorClasses = new Class<?>[selectors.length];
for (int i = 0; i < selectors.length; i++) {
selectorClasses[i] = ReflectUtils.getType(selectors[i]);
}
// 把 importSelector 选择的类当作 @Import 的,进行递归处理
this.processImport(registry, selectorClasses, annotationMetadata);
}
// 3、处理 Import 类型为 ImportBeanDefinitionRegistrar 的
else if (ImportBeanDefinitionRegistrar.class.isAssignableFrom(importClass)) {
ImportBeanDefinitionRegistrar importBeanDefinitionRegistrar = (ImportBeanDefinitionRegistrar) ReflectUtil.newInstance(importClass);
importBeanDefinitionRegistrar.registerBeanDefinitions(annotationMetadata, registry);
}
// 4、处理其他类型的,把它当作 @Configuration 注解标注的进行处理
else {
this.processConfigurationClass(registry, bdDef, importClass);
}
}
}
private void processBean(BeanDefinitionRegistry registry, BeanDefinition classBeanDefinition, Class<?> clazz) {
// 循环找方法中包含 @Bean 注解的
for (Method method : clazz.getMethods()) {
if (method.isAnnotationPresent(Bean.class)) {
BeanDefinition bdDef = new DefaultBeanDefinition();
Bean bean = method.getAnnotation(Bean.class);
String beanName = ObjectUtil.isNotEmpty(bean.value()) ? bean.value() : method.getName();
bdDef.setName(beanName);
bdDef.setFactoryBean(classBeanDefinition.getName());
bdDef.setFactoryMethod(method.getName());
bdDef.setInitMethod(bean.initMethod());
bdDef.setDestroyMethod(bean.destroyMethod());
// TODO: 2020/4/18 属性列表
registry.registerBeanDefinition(beanName, bdDef);
}
}
}
}