Spring源码分析之BeanFactoryPostProcessor调用过程(二)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: Spring源码分析之BeanFactoryPostProcessor调用过程

处理@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的过程大致就是这些了

本文内容就是以上这些了,希望小伙伴们有所收获,有问题的小伙伴欢迎在下方留言哦

目录
相关文章
|
1月前
|
监控 Java 应用服务中间件
Spring Boot整合Tomcat底层源码分析
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置和起步依赖等特性,大大简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是其与Tomcat的整合。
61 1
|
3天前
|
设计模式 XML Java
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
38 1
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
35 1
|
2月前
|
缓存 JavaScript Java
Spring之FactoryBean的处理底层源码分析
本文介绍了Spring框架中FactoryBean的重要作用及其使用方法。通过一个简单的示例展示了如何通过FactoryBean返回一个User对象,并解释了在调用`getBean()`方法时,传入名称前添加`&`符号会改变返回对象类型的原因。进一步深入源码分析,详细说明了`getBean()`方法内部对FactoryBean的处理逻辑,解释了为何添加`&`符号会导致不同的行为。最后,通过具体代码片段展示了这一过程的关键步骤。
Spring之FactoryBean的处理底层源码分析
|
1月前
|
前端开发 Java Spring
Spring MVC源码分析之DispatcherServlet#getHandlerAdapter方法
`DispatcherServlet`的 `getHandlerAdapter`方法是Spring MVC处理请求的核心部分之一。它通过遍历预定义的 `HandlerAdapter`列表,找到适用于当前处理器的适配器,并调用适配器执行具体的处理逻辑。理解这个方法有助于深入了解Spring MVC的工作机制和扩展点。
30 0
|
6月前
|
存储 安全 Java
Spring Security 6.x OAuth2登录认证源码分析
上一篇介绍了Spring Security框架中身份认证的架构设计,本篇就OAuth2客户端登录认证的实现源码做一些分析。
277 2
Spring Security 6.x OAuth2登录认证源码分析
|
6月前
|
存储 Java Spring
Spring IOC 源码分析之深入理解 IOC
Spring IOC 源码分析之深入理解 IOC
205 2
|
7月前
|
Dubbo Java 应用服务中间件
Dubbo 第四节: Spring与Dubbo整合原理与源码分析
DubboConfigConfigurationRegistrar的主要作⽤就是对propties⽂件进⾏解析并根据不同的配置项项⽣成对应类型的Bean对象。
164 0
|
7月前
|
安全 Java 数据安全/隐私保护
【Spring Security】Spring Security 认证过程源码分析
【Spring Security】Spring Security 认证过程源码分析
84 0