前文传送门:

  1. Spring源码分析之预启动流程
  2. Spring源码分析之BeanFactory体系结构

本文内容:

  1. AbstractApplicationContext#refresh前部分的一点小内容
  2. BeanFactoryPostProcessor调用过程详解
  3. mybatis是如何使用本节知识整合spring的?

正文:

在Spring中,一共分为BeanFactoryPostProcessorBeanPostProcessor两类后置处理器,他们主要的职责如下:

  • BeanFactoryPostProcessor:负责beanClassbeanDefinition的过程,包括但不限于寻找合适的beanClass,创建beanDefinition,修改beanDefinition,将beanDefinition注册到BeanFactory
  • BeanPostProcessor:负责beanDefinitionbean的过程,包括但不限于bean的属性赋值,初始化

本次主要分析BeanFactoryPostProcessor的调用过程,下面是BeanFactoryPostProcessor调用过程的大体流程图,也是本文想要表述的大概内容,原图链接: BeanFactoryPostProcessor调用过程

refresh的前半段流程

// 启动前的准备工作
prepareRefresh();
// 由于web项目中并不会先引入DefaultListableBeanFactory,在这里通知子类刷新BeanFactory
// 而我们是使用new AnnotationConfigApplicationContext()的方式,就是直接返回之前引入的DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备工作,给DefaultListableBeanFactory填充属性
prepareBeanFactory(beanFactory);
// 留于子类调用的扩展方法
postProcessBeanFactory(beanFactory);
// 调用实现BeanFactoryPostProcessor的后置处理器,
// 其实就是我们在new AnnotatedBeanDefinitionReader时注册的解析配置类的后置处理器ConfigurationClassPostProcessor
// 这里会解析配置类以及处理解析配置类后所引入的所有BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);
// 注册上一步解析出来的所有的BeanPostProcessor
// 注册逻辑和上一步大致相同,PriorityOrdered-> Ordered -> 普通的
registerBeanPostProcessors(beanFactory);

prepareRefresh

// 设置容器状态
this.closed.set(false);
this.active.set(true);

prepareBeanFactory

// 添加一个ApplicationContextAwareProcessor,用于bean初始化前调用一系列的Aware接口回调
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
// 用于处理实现ApplicationListener接口的bean,bean初始化后添加监听
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

invokeBeanFactoryPostProcessors(重点)

此方法将解析配置类以及处理解析配置类后所引入的所有BeanFactoryPostProcessor

温馨提醒:内容较多,还请耐心阅读~

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
//由于之前注册的都是BeanDefinition,此时还并没有生产任何的BeanFactoryPostProcessor,所以getBeanFactoryPostProcessors是空的
PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors()); }

invokeBeanFactoryPostProcessors

前部分主要是寻找ConfigurationClassPostProcessor并将它实例化

//放置已处理的beanName
Set<String> processedBeans = new HashSet<>();
//放置常规的后置处理器,就是只实现了BeanFactoryPostProcessor接口的
List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
//放置实现了BeanDefinitionRegistryPostProcessor接口的,之前我们注册的后置处理器中只有ConfigurationClassPostProcessor实现了
List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();
//放置当前的RegistryProcessors
List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();
//查找实现了BeanDefinitionRegistryPostProcessor接口的BeanName,其实就只有一个ConfigurationClassPostProcessor
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//ConfigurationClassPostProcessor同样实现了PriorityOrdered接口
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
//注意这里调用了getBean方法,生产了ConfigurationClassPostProcessor,放到currentRegistryProcessors集合中
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//将生产出来的后置处理器放到集合中
registryProcessors.addAll(currentRegistryProcessors);

接下来就开始调用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法

//调用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry); private static void invokeBeanDefinitionRegistryPostProcessors(
Collection<? extends BeanDefinitionRegistryPostProcessor> postProcessors, BeanDefinitionRegistry registry) {
//循环BeanDefinitionRegistryPostProcessor进行调用
for (BeanDefinitionRegistryPostProcessor postProcessor : postProcessors) {
postProcessor.postProcessBeanDefinitionRegistry(registry);
}
}

postProcessBeanDefinitionRegistry

public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
processConfigBeanDefinitions(registry);
}
public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
//放置候选配置类
List<BeanDefinitionHolder> configCandidates = new ArrayList<>();
String[] candidateNames = registry.getBeanDefinitionNames();
//遍历之前注册的所有bean定义,找到其中的配置类,其实就是我们自己传进来的配置类
for (String beanName : candidateNames) {
//...省略校验过程...
BeanDefinition beanDef = registry.getBeanDefinition(beanName);
//检查是否是有@Configuration注解的BeanDifinition -> full类型的配置类 -> 会把配置类替换成动态代理类
//或者该类包含@Component @ComponentScan @Import @ImportResource @Bean 注解的其中之一 -> lite类型的配置类 -> 不会替换成动态代理类
else if (ConfigurationClassUtils.checkConfigurationClassCandidate(beanDef, this.metadataReaderFactory)) {
configCandidates.add(new BeanDefinitionHolder(beanDef, beanName));
}
}
//....省略片段....
//实例化一个配置类解析器
ConfigurationClassParser parser = new ConfigurationClassParser(
this.metadataReaderFactory, this.problemReporter, this.environment,
this.resourceLoader, this.componentScanBeanNameGenerator, registry); do {
//解析配置类
parser.parse(candidates);
parser.validate();
//parser.getConfigurationClasses()就是拿到刚刚解析完放到map中的配置类
Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
configClasses.removeAll(alreadyParsed); //这里处理@Import导入的beanDefintion和配置类中的@Bean
this.reader.loadBeanDefinitions(configClasses);
alreadyParsed.addAll(configClasses);
//以下逻辑是找出未解析的配置类,如@Bean和ImportBeanDefinitionRegistrar所引入的
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);
//将是配置类并且没有解析过的BeanDefinition放到候选集合中继续解析
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bd, this.metadataReaderFactory) &&
!alreadyParsedClasses.contains(bd.getBeanClassName())) {
candidates.add(new BeanDefinitionHolder(bd, candidateName));
}
}
}
candidateNames = newCandidateNames;
}
}
while (!candidates.isEmpty());
}

ConfigurationClassUtils.checkConfigurationClassCandidate中的摘取片段

//检查是否有标识@Configuration
Map<String, Object> config = metadata.getAnnotationAttributes(Configuration.class.getName());
if (config != null && !Boolean.FALSE.equals(config.get("proxyBeanMethods"))) {
//设置配置属性值为full
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_FULL);
}
//检查是否包含@Component @ComponentScan @Import @ImportResource @Bean
else if (config != null || isConfigurationCandidate(metadata)) {
//设置配置属性值为lite
beanDef.setAttribute(CONFIGURATION_CLASS_ATTRIBUTE, CONFIGURATION_CLASS_LITE);
}
else {
return false;
}

配置类解析流程(parser.parse(candidates))

public void parse(Set<BeanDefinitionHolder> configCandidates) {
for (BeanDefinitionHolder holder : configCandidates) {
BeanDefinition bd = holder.getBeanDefinition();
//配置类的beanDefinition为AnnotatedGenericBeanDefinition,true
if (bd instanceof AnnotatedBeanDefinition) {
//传入配置类的元数据与beanName
parse(((AnnotatedBeanDefinition) bd).getMetadata(), holder.getBeanName());
}
}
}
protected final void parse(AnnotationMetadata metadata, String beanName) throws IOException {
processConfigurationClass(new ConfigurationClass(metadata, beanName), DEFAULT_EXCLUSION_FILTER);
}

processConfigurationClass

protected void processConfigurationClass(ConfigurationClass configClass, Predicate<String> filter) throws IOException {
SourceClass sourceClass = asSourceClass(configClass, filter);
do {
//解析配置类,这里可能返回配置类的父类,需要继续处理
sourceClass = doProcessConfigurationClass(configClass, sourceClass, filter);
}
while (sourceClass != null);
//将配置类放入map中
this.configurationClasses.put(configClass, configClass);
}

doProcessConfigurationClass

//@Configuration 本身也是 @Component的组合注解
if (configClass.getMetadata().isAnnotated(Component.class.getName())) {
// 处理内置类,如果内置类也是个配置类,递归处理内置类
processMemberClasses(configClass, sourceClass, filter);
}

处理@ComponentScan

// Process any @ComponentScan annotations
// 找出配置类上的@ComponentScan注解属性
Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(
sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class); for (AnnotationAttributes componentScan : componentScans) {
//将@ComponentScan引入的所有类扫描成BeanDefinition并注册到容器中
Set<BeanDefinitionHolder> scannedBeanDefinitions =
this.componentScanParser.parse(componentScan, sourceClass.getMetadata().getClassName());
//这里循环是为了判断扫描出来的beanDefinition是否是配置类,如果是配置类的话需要递归解析
for (BeanDefinitionHolder holder : scannedBeanDefinitions) {
BeanDefinition bdCand = holder.getBeanDefinition().getOriginatingBeanDefinition();
//这里是必然为true, 能被扫描出来的必然有@Component注解,而@Component注解为lite配置类
//这里主要是为了在检查的同时设置一下full或者lite的类型
if (ConfigurationClassUtils.checkConfigurationClassCandidate(bdCand, this.metadataReaderFactory)) {
//配置类就继续递归解析
parse(bdCand.getBeanClassName(), holder.getBeanName());
}
}
}
this.componentScanParser.parse
public Set<BeanDefinitionHolder> parse(AnnotationAttributes componentScan, final String declaringClass) {
//重新new了一个classpath的bean定义扫描器,没用我们最开始创建的
// 这里添加了一个默认的过滤器,过滤@Component注解的
ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(this.registry,
componentScan.getBoolean("useDefaultFilters"), this.environment, this.resourceLoader);
//添加自己配置的过滤器
for (AnnotationAttributes filter : componentScan.getAnnotationArray("includeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addIncludeFilter(typeFilter);
}
}
for (AnnotationAttributes filter : componentScan.getAnnotationArray("excludeFilters")) {
for (TypeFilter typeFilter : typeFiltersFor(filter)) {
scanner.addExcludeFilter(typeFilter);
}
}
//如果配置的为懒加载,则扫描出来的所有BeanDefinition都默认为懒加载的
boolean lazyInit = componentScan.getBoolean("lazyInit");
if (lazyInit) {
scanner.getBeanDefinitionDefaults().setLazyInit(true);
}
//将配置的basePackages中所有的包路径放到set集合中,保证最终所有的包路径唯一
Set<String> basePackages = new LinkedHashSet<>();
String[] basePackagesArray = componentScan.getStringArray("basePackages");
for (String pkg : basePackagesArray) {
String[] tokenized = StringUtils.tokenizeToStringArray(this.environment.resolvePlaceholders(pkg),
ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
Collections.addAll(basePackages, tokenized);
}
//添加一个排除过滤器,排除该配置类
scanner.addExcludeFilter(new AbstractTypeHierarchyTraversingFilter(false, false) {
@Override
protected boolean matchClassName(String className) {
return declaringClass.equals(className);
}
});
//开始扫描
return scanner.doScan(StringUtils.toStringArray(basePackages));
}
doScan
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
Assert.notEmpty(basePackages, "At least one base package must be specified");
Set<BeanDefinitionHolder> beanDefinitions = new LinkedHashSet<>();
for (String basePackage : basePackages) {
//找到所有候选的bean -> 默认过滤器为过滤标识了@Component注解的class
Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
for (BeanDefinition candidate : candidates) {
String beanName = this.beanNameGenerator.generateBeanName(candidate, this.registry);
if (candidate instanceof AbstractBeanDefinition) {
//设置默认值,比如上一个方法刚刚设置的是否懒加载
postProcessBeanDefinition((AbstractBeanDefinition) candidate, beanName);
}
if (candidate instanceof AnnotatedBeanDefinition) {
//解析beanClass的所有注解填充到beanDefinition中,@Lazy @Primary @DependsOn @Role @Description
AnnotationConfigUtils.processCommonDefinitionAnnotations((AnnotatedBeanDefinition) candidate);
}
//检查之前是否注册过,未注册返回true
if (checkCandidate(beanName, candidate)) {
BeanDefinitionHolder definitionHolder = new BeanDefinitionHolder(candidate, beanName);
beanDefinitions.add(definitionHolder);
//将beanDefinition注册到容器中
registerBeanDefinition(definitionHolder, this.registry);
}
}
}
return beanDefinitions;
}
寻找候选组件#findCandidateComponents
public Set<BeanDefinition> findCandidateComponents(String basePackage) {
return scanCandidateComponents(basePackage);
}
private Set<BeanDefinition> scanCandidateComponents(String basePackage) {
Set<BeanDefinition> candidates = new LinkedHashSet<>();
//将类路径替换成绝对路径
String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX +
resolveBasePackage(basePackage) + '/' + this.resourcePattern;
//找出该路径下的所有类资源
Resource[] resources = getResourcePatternResolver().getResources(packageSearchPath);
for (Resource resource : resources) {
if (resource.isReadable()) {
MetadataReader metadataReader = getMetadataReaderFactory().getMetadataReader(resource);
//调用刚刚配置的过滤器进行匹配,
//默认过滤器逻辑:是否标识了@Component注解(包括组合的,如@Service)
if (isCandidateComponent(metadataReader)) {
//通过扫描方式创建的BeanDefintion为ScannedGenericBeanDefinition
ScannedGenericBeanDefinition sbd = new ScannedGenericBeanDefinition(metadataReader);
sbd.setSource(resource);
//不是接口和抽象类,或者是抽象类但标识了@Lookup
if (isCandidateComponent(sbd)) {
//将beanDefinition存到集合中
candidates.add(sbd);
}
}
}
}
return candidates;
}

处理@Import

processImports(configClass, sourceClass, getImports(sourceClass), filter, true);
private void processImports(ConfigurationClass configClass, SourceClass currentSourceClass,
Collection<SourceClass> importCandidates, Predicate<String> exclusionFilter,
boolean checkForCircularImports) {
//importCandidates为@Import中的value数组
for (SourceClass candidate : importCandidates) {
if (candidate.isAssignable(ImportSelector.class)) {
// Candidate class is an ImportSelector -> delegate to it to determine imports
Class<?> candidateClass = candidate.loadClass();
//实例化我们写的实现ImportSelector接口的类
ImportSelector selector = ParserStrategyUtils.instantiateClass(candidateClass, ImportSelector.class,
this.environment, this.resourceLoader, this.registry);
//调用selectImports方法返回我们需要注入到容器中bean数组
String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
//转为SourceClass集合
Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames, exclusionFilter);
//再次递归调用本方法,如果我们返回的数组是一些没有实现Import相关接口的类,
//就会走到最后的else逻辑,当成配置类处理
processImports(configClass, currentSourceClass, importSourceClasses, exclusionFilter, false);
}
//这里就走实现ImportBeanDefinitionRegistrar接口的逻辑
else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
// Candidate class is an ImportBeanDefinitionRegistrar ->
// delegate to it to register additional bean definitions
Class<?> candidateClass = candidate.loadClass();
//实例化
ImportBeanDefinitionRegistrar registrar =
ParserStrategyUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class,
this.environment, this.resourceLoader, this.registry);
//这里先把Registrar放到配置类的importBeanDefinitionRegistrars属性中,最后解析完调用loadBeanDefinition进行处理
configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
}
else {
//普通的bean当做配置类处理
processConfigurationClass(candidate.asConfigClass(configClass), exclusionFilter);
}
}
}

处理@Bean

// 将配置类中@Bean的方法解析成方法元数据放到配置类中
Set<MethodMetadata> beanMethods = retrieveBeanMethodMetadata(sourceClass);
for (MethodMetadata methodMetadata : beanMethods) {
configClass.addBeanMethod(new BeanMethod(methodMetadata, configClass));
}

到这里配置类的主要解析流程就已经结束了,接下来回到解析之后的流程

处理@Import导入的beanDefintion和配置类中的@Bean

this.reader.loadBeanDefinitions(configClasses);
public void loadBeanDefinitions(Set<ConfigurationClass> configurationModel) {
TrackedConditionEvaluator trackedConditionEvaluator = new TrackedConditionEvaluator();
//循环刚刚解析过的所有配置类
for (ConfigurationClass configClass : configurationModel) {
loadBeanDefinitionsForConfigurationClass(configClass, trackedConditionEvaluator);
}
}
private void loadBeanDefinitionsForConfigurationClass(
ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { if (trackedConditionEvaluator.shouldSkip(configClass)) {
String beanName = configClass.getBeanName();
if (StringUtils.hasLength(beanName) && this.registry.containsBeanDefinition(beanName)) {
this.registry.removeBeanDefinition(beanName);
}
this.importRegistry.removeImportingClass(configClass.getMetadata().getClassName());
return;
}
// 将Import注解引入的class注册到容器的BeanDefinitionMap中
if (configClass.isImported()) {
registerBeanDefinitionForImportedConfigurationClass(configClass);
}
for (BeanMethod beanMethod : configClass.getBeanMethods()) {
//将beanMethod转化成BeanDefinition注册到容器的beanDefinitionMap中
loadBeanDefinitionsForBeanMethod(beanMethod);
} loadBeanDefinitionsFromImportedResources(configClass.getImportedResources());
//调用在解析Import时放入的ImportBeanDefinitionRegistrar的registerBeanDefinitions方法
loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars());
}
摘取处理BeanMethod逻辑如下
private void loadBeanDefinitionsForBeanMethod(BeanMethod beanMethod) {
ConfigurationClass configClass = beanMethod.getConfigurationClass();
MethodMetadata metadata = beanMethod.getMetadata();
String methodName = metadata.getMethodName(); //解析出方法上@Bean注解的所有属性值
AnnotationAttributes bean = AnnotationConfigUtils.attributesFor(metadata, Bean.class);
//创建一个ConfigurationClassBeanDefinition,标识为通过@Bean注解注册的bean
ConfigurationClassBeanDefinition beanDef = new ConfigurationClassBeanDefinition(configClass, metadata);
beanDef.setSource(this.sourceExtractor.extractSource(metadata, configClass.getResource()));
//以下逻辑为拿出@Bean中的属性填充到BeanDefinition中,最后注册容器中
beanDef.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
//解析注解填充属性
AnnotationConfigUtils.processCommonDefinitionAnnotations(beanDef, metadata); Autowire autowire = bean.getEnum("autowire");
if (autowire.isAutowire()) {
beanDef.setAutowireMode(autowire.value());
}
boolean autowireCandidate = bean.getBoolean("autowireCandidate");
if (!autowireCandidate) {
beanDef.setAutowireCandidate(false);
}
String initMethodName = bean.getString("initMethod");
if (StringUtils.hasText(initMethodName)) {
beanDef.setInitMethodName(initMethodName);
}
String destroyMethodName = bean.getString("destroyMethod");
beanDef.setDestroyMethodName(destroyMethodName);
//将创建的BeanDefinition注册到容器中
this.registry.registerBeanDefinition(beanName, beanDefToRegister);
}

以上,ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法大致过程就这些了,接下来回到刚开始的invokeBeanFactoryPostProcessors方法

invokeBeanFactoryPostProcessors

处理实现了Ordered接口的BeanDefinitionRegistryPostProcessor

//...省略之前代码片段
//调用ConfigurationClassPostProcessor的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//清空,以便处理后面的后置处理器
currentRegistryProcessors.clear(); //再次查找实现了BeanDefinitionRegistryPostProcessor接口的BeanName,这里就是从配置类中解析出来的一些
postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
//不包括已经处理过的,并且先处理实现Ordered接口的
if (!processedBeans.contains(ppName) && beanFactory.isTypeMatch(ppName, Ordered.class)) {
currentRegistryProcessors.add(beanFactory.getBean(ppName, BeanDefinitionRegistryPostProcessor.class));
processedBeans.add(ppName);
}
}
//根据Ordered排序
sortPostProcessors(currentRegistryProcessors, beanFactory);
//将后置处理器放到已注册的集合中
registryProcessors.addAll(currentRegistryProcessors);
//调用所有后置处理器的postProcessBeanDefinitionRegistry方法
invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
//再次清理,因为后面还要处理未实现Ordered接口的
currentRegistryProcessors.clear();

最后需要循环处理剩下的所有后置处理器,因为可能从剩下的后置处理器中又解析出新的后置处理器

//下面的逻辑和上面的一模一样,while循环处理所有剩下的后置处理器,直到全部处理完毕
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);
currentRegistryProcessors.clear();
}

调用所有后置处理器的postProcessBeanFactory方法

/**
* 调用所有后置处理器的postProcessBeanFactory方法,
* 如果自己没实现的话,Spring中只有一个内置的ConfigurationClassPostProcessor
* ConfigurationClassPostProcessor中的postProcessBeanFactory方法主要是将配置类换成动态代理
*/
invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);

ConfigurationClassPostProcessor#postProcessBeanFactory

public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
//将所有配置类进行动态代理,这样@Bean中依赖其他的Bean就可以从容器中拿bean了
/**
* example:
* @Bean
* public Car car(){
* return new Car(wheel());
* }
* @Bean
* public Wheel wheel(){
* return new Wheel();
* }
* 如果配置类不换成动态代理的话,每次从容器中拿car都将new一个wheel
* 注意,这里只有full类型的配置类才会生成代理类,lite类型的不会,
* 所以lite类型的配置类每次获取car都会生成一个wheel
*/
enhanceConfigurationClasses(beanFactory);
//添加一个beanPostProcessor
beanFactory.addBeanPostProcessor(new ImportAwareBeanPostProcessor(beanFactory));
}

最后处理实现了BeanFactoryPostProcessor接口的后置处理器

//处理方式与BeanDefinitionRegistryPostProcessor相同
//找出所有实现了BeanDefinitionRegistryPostProcessor的后置处理器
String[] postProcessorNames =
beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
//先处理实现PriorityOrdered接口的
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
//在处理实现Ordered接口的
invokeBeanFactoryPostProcessors(orderedPostProcessors, beanFactory);
//最后处理普通的
invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

到这里,关于BeanFactoryPostProcessor调用过程就已经完结了

关于BeanDefinition的小彩蛋

解析配置类的流程我们已经分析完了,那么在这过程中用了多少种BeanDefinition呢?他们对应的类型又是什么呢?这里附上本文的一个小彩蛋。

  • AnnotatedGenericBeanDefinition:在开始传入的配置类,以及通过@Import注解引入的Bean
  • ScannedGenericBeanDefinition:通过@Component扫描包引入的Bean
  • ConfigurationClassBeanDefinition:通过@Bean注解引入的Bean
  • RootBeanDefinition:Spring内部使用,如生产Bean时将其他BeanDefinition转成RootBeanDefinition

Mybatis 如何整合 Spring的?

此节知识为概要知识,具体内容将放在Mybatis源码系列详细说明

先带大家理理思路~

我们知道,在Spring中是可以通过扫描的方式扫描出标识了@Component注解的class注册到容器中,并且该class不能为一个接口类(忘了请看上面的扫描逻辑),而我们的mapper通常又是一个接口类,这是默认不允许被注册的。那么该如何解决这个问题呢?

思考:既然默认不允许是接口类,那么我们是否可以自定义一个扫码器继承Spring的扫描器,然后重写其中判断是否为接口类的逻辑,这样,我们不就可以使用我们自定义的扫描器去扫描包就可以了吗?

问题2:假设上面的方法可行,但是我们扫描出来的BeanDefintion是个接口,接口是不能被实例化的,那在后面我们createBean中的实例化步骤又该如何解决呢?

思考:我们知道其实我们的mappermybatis中本来就是个接口,我们创建时是通过sqlSessionTemplate.getMapper()的方式创建的,这里其实是生成了一个代理类返回给我们,那我们应该如何将这个代理类给接到Spring的createBean过程中呢,如何接过去了岂不是就万事大吉?

小知识:嘿,不知道大家还记不记的我们的bean里有一种特殊的bean称为FactoryBean,我们这个FactoryBean最后从容器中获取出来时其实是先拿到这个FactoryBean,然后调用它的getObject()方法返回我们真正需要的bean

思考:知道这个之后,那么我们是不是可以使用FactoryBean,然后将扫描出来的接口(mapper)放到FactoryBean的属性中,最后从容器中获取时只要这样:

public class FactoryBean{
private Class mapper;
public Object getObject(){
sqlSessionTemplate.getMappper(mapper);
}
}

嘿,看看是不是好像搞定啦~

现在问题好像都已经解决了,那剩下的就是怎么让Spring在启动的时候调用我们的自定义扫描器呢?我们现在就来看看源码吧

@MapperScan

Mybatis整合Spring当然是从@MapperScan注解看起,因为我们通常情况只加这个注解就可以了

@MapperScan简要内容如下

// 组合注解,组合了@Import注解,再通过@Import注解导入了MapperScannerRegistrar类
@Import(MapperScannerRegistrar.class)
public @interface MapperScan{
// 包路径
String[] basePackages() default {}
}

MapperScannerRegistrar

// 实现的是ImportBeanDefinitionRegistrar接口
public class MapperScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware{ }

registerBeanDefinitions

@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
// 从元数据中拿到@MapperScan的信息
AnnotationAttributes annoAttrs = AnnotationAttributes.fromMap(importingClassMetadata.getAnnotationAttributes(MapperScan.class.getName()));
// 实例化一个自定义的扫描器
ClassPathMapperScanner scanner = new ClassPathMapperScanner(registry); // 下面都是些属性填充,由于一般我们只配一个包路径,所以下面除了包路径,其他都是null
if (resourceLoader != null) {
scanner.setResourceLoader(resourceLoader);
} Class<? extends Annotation> annotationClass = annoAttrs.getClass("annotationClass");
if (!Annotation.class.equals(annotationClass)) {
scanner.setAnnotationClass(annotationClass);
} Class<?> markerInterface = annoAttrs.getClass("markerInterface");
if (!Class.class.equals(markerInterface)) {
scanner.setMarkerInterface(markerInterface);
} Class<? extends BeanNameGenerator> generatorClass = annoAttrs.getClass("nameGenerator");
if (!BeanNameGenerator.class.equals(generatorClass)) {
scanner.setBeanNameGenerator(BeanUtils.instantiateClass(generatorClass));
} Class<? extends MapperFactoryBean> mapperFactoryBeanClass = annoAttrs.getClass("factoryBean");
if (!MapperFactoryBean.class.equals(mapperFactoryBeanClass)) {
scanner.setMapperFactoryBean(BeanUtils.instantiateClass(mapperFactoryBeanClass));
} scanner.setSqlSessionTemplateBeanName(annoAttrs.getString("sqlSessionTemplateRef"));
scanner.setSqlSessionFactoryBeanName(annoAttrs.getString("sqlSessionFactoryRef")); List<String> basePackages = new ArrayList<String>();
for (String pkg : annoAttrs.getStringArray("value")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (String pkg : annoAttrs.getStringArray("basePackages")) {
if (StringUtils.hasText(pkg)) {
basePackages.add(pkg);
}
}
for (Class<?> clazz : annoAttrs.getClassArray("basePackageClasses")) {
basePackages.add(ClassUtils.getPackageName(clazz));
}
// 注册自定义的过滤器,我们啥也没配,所以扫描出来的所以接口都通过
scanner.registerFilters();
// 开始扫描
scanner.doScan(StringUtils.toStringArray(basePackages));
}

scanner.registerFilters中的有效片段

// 添加一个直接返回true的过滤器
addIncludeFilter(new TypeFilter() {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
return true;
}
});

doScan

public Set<BeanDefinitionHolder> doScan(String... basePackages) {
// 直接走的就是Spring的扫描逻辑了,但现在过滤器只有一个默认全放行的
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages); if (beanDefinitions.isEmpty()) {
logger.warn("No MyBatis mapper was found in '" + Arrays.toString(basePackages) + "' package. Please check your configuration.");
} else {
// 处理扫描出来的BeanDefinition,这里就是我们思考中搞成`FactoryBean`的逻辑
processBeanDefinitions(beanDefinitions);
}
return beanDefinitions;
}

我们思考中重写的扫描逻辑

@Override
protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
// 放行是接口的类
return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
}

摘取processBeanDefinitions中的代码片段

private void processBeanDefinitions(Set<BeanDefinitionHolder> beanDefinitions) {
GenericBeanDefinition definition;
for (BeanDefinitionHolder holder : beanDefinitions) {
definition = (GenericBeanDefinition) holder.getBeanDefinition();
// 将原来的接口mapper放到beanDefintion的构造方法参数中,以指定的构造方法实例化
definition.getConstructorArgumentValues().addGenericArgumentValue(definition.getBeanClassName());
// 注意这里:将原来的beanClass替换成FactoryBean了!
definition.setBeanClass(this.mapperFactoryBean.getClass());
}
}

Mybatis整合Spring的过程大致就是这些了

Spring 源码系列
  1. Spring源码分析之 IOC 容器预启动流程(已完结)
  2. Spring源码分析之BeanFactory体系结构(已完结)
  3. Spring源码分析之BeanFactoryPostProcessor调用过程(已完结)
  4. Spring源码分析之Bean的创建过程
  5. Spring源码分析之什么是循环依赖及解决方案
  6. Spring源码分析之AOP从解析到调用
  7. Spring源码分析之事务管理(上),事物管理是spring作为容器的一个特点,总结一下他的基本实现与原理吧
  8. Spring源码分析之事务管理(下) ,关于他的底层事物隔离与事物传播原理,重点分析一下
Spring Mvc 源码系列
  1. SpringMvc体系结构
  2. SpringMvc源码分析之Handler解析过程
  3. SpringMvc源码分析之请求链过程
Mybatis 源码系列

暂定


追更,可关注我,近期有时间就文章全写完,分享纯粹为了乐趣,也有一种成就感吧,笔者这篇文章先就到这

关注笔者公众号:奇客时间,获取互联网公司面试真题,回复关键字形式:公司-部门-面试轮次,例如 阿里-蚂蚁金服-一面,自动回复面试真题;当前已经收录如下:

字节跳动-抖音-面试轮次, 搜狐-搜索组-面试轮次, OPPO-商城-面试轮次, 58同城-基础架构部-面试轮次,湖南台-芒果TV-面试轮次 , 腾讯-乘车码-面试轮次 , 腾讯-微信支付-面试轮次 , 腾讯-零售新业务-面试轮次 , 腾讯-直播平台-面试轮次, 快手-广告业务部-面试轮次 , 贝壳找房-商品组-面试轮次 , 百度-信息流-面试轮次 , 京东-零售-面试轮次 , 京东-物流-面试轮次 , 京东-电商-面试轮次 , 滴滴-小桔车服-面试轮次 , 滴滴-金融-面试轮次 , 阿里-高德-面试轮次 , 阿里-大文娱-面试轮次 , 阿里-健康-面试轮次 , 阿里-蚂蚁金服-面试轮次 , 美团-外卖-面试轮次 , 美团-风控-面试轮次

Spring源码分析之`BeanFactoryPostProcessor`调用过程的更多相关文章

  1. mybatis源码分析(方法调用过程)

    十一月月底,宿舍楼失火啦,搞得20多天没有网,目测直到放假也不会来了... 正题 嗯~,其实阅读源码不是为了应付面试,更重要的让你知道,大师是怎样去写代码的,同样是用Java,为啥Clinton Be ...

  2. Openstack Nova 源码分析 — RPC 远程调用过程

    目录 目录 Nova Project Services Project 的程序入口 setuppy Nova中RPC远程过程调用 nova-compute RPC API的实现 novacompute ...

  3. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

  4. Spring源码分析之AOP从解析到调用

    正文: 在上一篇,我们对IOC核心部分流程已经分析完毕,相信小伙伴们有所收获,从这一篇开始,我们将会踏上新的旅程,即Spring的另一核心:AOP! 首先,为了让大家能更有效的理解AOP,先带大家过一 ...

  5. Spring源码分析之循环依赖及解决方案

    Spring源码分析之循环依赖及解决方案 往期文章: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostPro ...

  6. Spring源码分析-BeanFactoryPostProcessor

    Spring源码分析-BeanFactoryPostProcessor 博主技术有限,本文难免有错误的地方,如果您发现了欢迎评论私信指出,谢谢 BeanFactoryPostProcessor接口是S ...

  7. 【Spring源码分析】非懒加载的单例Bean初始化过程(下篇)

    doCreateBean方法 上文[Spring源码分析]非懒加载的单例Bean初始化过程(上篇),分析了单例的Bean初始化流程,并跟踪代码进入了主流程,看到了Bean是如何被实例化出来的.先贴一下 ...

  8. 【Spring源码分析】原型Bean实例化过程、byName与byType及FactoryBean获取Bean源码实现

    原型Bean加载过程 之前的文章,分析了非懒加载的单例Bean整个加载过程,除了非懒加载的单例Bean之外,Spring中还有一种Bean就是原型(Prototype)的Bean,看一下定义方式: & ...

  9. spring源码分析系列 (5) spring BeanFactoryPostProcessor拓展类PropertyPlaceholderConfigurer、PropertySourcesPlaceholderConfigurer解析

    更多文章点击--spring源码分析系列 主要分析内容: 1.拓展类简述: 拓展类使用demo和自定义替换符号 2.继承图UML解析和源码分析 (源码基于spring 5.1.3.RELEASE分析) ...

随机推荐

  1. 微服务实战系列(二)-注册中心Springcloud Eureka客户端

    1. 场景描述 前几天介绍了下springcloud的Eureka注册中心(springcloud-注册中心快速构建),今天结合springboot-web介绍下eureka客户端服务注册. 2. 解 ...

  2. 从GitHub建站迁移到服务器(Java环境)

    一.购买域名和服务器 域名:阿里云:lookabc.cn 服务器:腾讯云,学生价格便宜 二.域名解析 注意:由于域名和服务器不在同一家,需要域名迁入和迁出 三.搭建服务器环境 1.下载xftp6和xs ...

  3. Linux Wait Queue 等待队列

    一.引言 linux 内核的等待队列和进程调度息息相关,进程在某些情况下必须等待某些事件的发生,例如:等待一个磁盘操作的终止,等待释放系统资源,或等待指定的时间间隔. 等待队列实现了在事件上的条件等待 ...

  4. Centos-系统任务队列信息-uptime

    uptime 显示系统的当前时间.系统从启动到当前运行时间.当前总共在线用户.系统1.5.15分钟负载情况

  5. STM32F103C8T6-CubeMx串口收发程序详细设计与测试(1)——CubeMx生成初始代码

    STM32F103C8T6-CubeMx串口收发程序详细设计与测试(1)--CubeMx生成初始代码 关键词:STM32F103C8T6 CubeMX UART 详细程序设计 1.开发环境 (1)ST ...

  6. servercat IOS Linux监控 SSH客户端

    servercat IOS Linux监控 SSH客户端 iOS 平台上新出的一个挺有趣的服务器监控 + SSH 客户端. 监控服务器状态,内存.CPU.网络 还能对Docker容器进行监控 价格:¥ ...

  7. Docker笔记4:在 CentOS 上安装 Docker

    Docker 是一个开源的应用容器引擎,主要有两个分支,一个是社区免费版(Docker CE),一个是企业版(Docker EE). 第1步:系统环境要求 Docker 支持的 CentOS 版本: ...

  8. kubernetes-介绍与特性

    1. kubernetes概述 1) kubernetes是什么 2) kubernetes能做什么 3) kubernetes特性 4) kubernetes集群架构与组件 5) kubernete ...

  9. gitlab介绍

    1. GitLab简介    GitLab是一个利用 Ruby on Rails 开发的开源应用程序,实现一个自托管的Git项目仓库,可通过Web界面进行访问公开的或者私人项目. GitLab拥有与G ...

  10. 本文介绍如何使用 Docker Swarm 来部署 Nebula Graph 集群,并部署客户端负载均衡和高可用

    本文作者系:视野金服工程师 | 吴海胜 首发于 Nebula Graph 论坛:https://discuss.nebula-graph.com.cn/t/topic/1388 一.前言 本文介绍如何 ...