一文通透spring的初始化

news2024/11/25 0:46:38

简述

今天重点分析ApplicationContext初始化时做的事情,我们都只到spring是个IOC和AOP容器,那再我们new一个ApplicationContext,spring内部都做了什么?怎么实现的IOC和AOP?
比如说下面这段代码

@Configuration
@ComponentScan("com.xxx.xxx")
@EnableAspectJAutoProxy
public class MainApplication {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(MainApplication.class);
        IUser user = context.getBean(IUser.class);
        user.sayHi();
    }

}

通过new一个AnnotationConfigApplicationContext我们就得到了这个bean容器,还可以添加切面,那再new的时候都做了什么呐?

BeanFactory

这篇文章的基础是懂得BeanFactory,如果不懂可以做做功课或者翻翻之前的文章~

简单总结一下BeanFactory。
BeanFactory能干什么,以最主要的DefaultListableBeanFactory为例

  • 注册bean定义
  • 通过bean定义生产bean并可以随时获取
  • 可以添加bean后置处理器(BeanPostProcessor)来调整bean的创建过程
  • 可以一次性创建所有非懒加载单例bean(preInstantiateSingletons)
  • 等等

ApplicationContext

有了BeanFactory为啥还要有ApplicationContext呐,其实BeanFactory只是一个给图纸(bean定义)生产产品(bean)的工厂,离我们太遥远了,或者说用起来他麻烦了,甚至依赖注入和AOP都不是BeanFactory实现的

如果单纯使用BeanFactory,需要给他添加依赖注入的后置处理器,需要给他加AOP的后置处理器,才能实现这些功能,而使用ApplicationContext这些活它帮干了,它还可以自动扫描包或者读取配置自动生成bean定义注册到BeanFactory当中,还有一些事件的支持和国际化的支持。

所以为什么有ApplicationContext,ApplicationContext就是把一些我们平时开发用到的功能封装好了,我们开发时直接用就可以实现IOC,AOP,事件等功能

它俩的关系就好比工厂和门店,那有了工厂为啥还有有门店呐?单一职责吗,工厂的技术宅就能看懂图纸,你跟他说中国话他听不懂,所以就有了门店,你简单和门店的人说一下你的需求,门店的人帮你画图纸交给工厂生产,整个过程你不需要和工厂接触

后置处理器

后置处理器分为BeanFactoryPostProcessor和BeanPostProcessor

  • BeanPostProcessor
    bean后置处理器,beanFactory可以添加BeanPostProcessor,再生成bean的不同时期执行这些后置处理器,简单来说,通过设置后置处理器,可以再bean的创建过程中植入一些自定义逻辑
  • BeanFactoryPostProcessor
    BeanFactory后置处理器,ApplicationContext可以添加BeanFactoryPostProcessor,再初始化ApplicationContext时会调用这些BeanFactory后置处理器

总结BeanPostProcessor和BeanFactoryPostProcessor都是钩子,前者是存储于beanFactory,再生产bean时候调用,后者存储于ApplicationContext,再初始化ApplicationContext时调用,二者都有很多子类型,以便再不同阶段调用,使代码有很大的扩展性

ApplicationContext

接下来分析ApplicationContext的源码,由于现在都很少用xml这种了,所以我们找了个AnnotationConfigApplicationContext,注解配置的ApplicationContext,也就是现在当然springboot内部用的ApplicationContext,那就开始跟宗AnnotationConfigApplicationContext的构造方法

public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
    this();
    register(componentClasses);
    refresh();
}

一共就三局,一个一个跟

this()

调用无参构造方法,首先要调用父类构造方法,父类是GenericApplicationContext,看看他的构造方法

public GenericApplicationContext() {
    this.beanFactory = new DefaultListableBeanFactory();
}

这个简单,内部初始化了一个DefaultListableBeanFactory,这个好理解,门店的背后肯定是有工厂的,再来看当前类的无参构造方法

public AnnotationConfigApplicationContext() {
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

初始化了一个reader,一个scanner,先看看reader
跟踪reader的构造方法会出现这么一条代码

AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);

这句话很重要,这里的this.registry就是ApplicationContext,在这里扮演一个bean定义注册器的角色,进入这个方法查看~
具体的代码就不贴了,很长可以自己看看,总结就是像这个bean定义注册器注册了很多个后置处理器类型的bean定义,包括BeanFactoryPostProcessor类型和BeanPostProcessor类型,主要有:

  • 配置类解析后置处理器 ConfigurationClassPostProcessor(BeanFactoryPostProcessor)
  • @Autowired 注解的处理器 AutowiredAnnotation(BeanPostProcessor)
  • @Required属性的注解处理器 RequiredAnnotation(BeanPostProcessor)
  • @EventListener解析器 EventListenerMethodProcessor
  • 事件监听器工厂 DefaultEventListenerFactory

注意:上面讨论过两种后置处理器存放的位置,而这时添加的后置处理器并没有存放到相应位置,而是以bean的形式存放在bean容器中

至于为什么在这时机添加后置处理器,应该是这些后置处理器都属于读文件、读类的功能,即reader

register(componentClasses)

这里的componentClasses就是初始化时传入的唯一参数MainApplication.class,register都干了什么呐

public void register(Class<?>... componentClasses) {
    Assert.notEmpty(componentClasses, "At least one component class must be specified");
    this.reader.register(componentClasses);
}

调用刚才初始化的reader的register方法,这里就要介绍reader的主要作用,就是传入一个类,把类转换为bean定义并注册到初始化时传入的bean定义注册器

所以register方法就是把主配置类(MainApplication)解析为bean定义并完成注册

refresh()

这句就是初始化的核心方法了,内部有很多子方法的调用

// Prepare this context for refreshing.
prepareRefresh();

// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
    // Allows post-processing of the bean factory in context subclasses.
    postProcessBeanFactory(beanFactory);

    // Invoke factory processors registered as beans in the context.
    invokeBeanFactoryPostProcessors(beanFactory);

    // Register bean processors that intercept bean creation.
    registerBeanPostProcessors(beanFactory);

    // Initialize message source for this context.
    initMessageSource();

    // Initialize event multicaster for this context.
    initApplicationEventMulticaster();

    // Initialize other special beans in specific context subclasses.
    onRefresh();

    // Check for listener beans and register them.
    registerListeners();

    // Instantiate all remaining (non-lazy-init) singletons.
    finishBeanFactoryInitialization(beanFactory);

    // Last step: publish corresponding event.
    finishRefresh();
}

这么多方法,一个一个来吧

1.prepareRefresh

这个先不管,就是做一些准备工作吗,比如记录一下程序开始的时间什么的

2.beanFactory = obtainFreshBeanFactory()

因为refresh方法是再父类中执行的,而beanFactory是在子类初始化的,所以这句话就是父类管子类要beanFactory,也就是刚才GenericApplicationContext无参构造中初始化的DefaultListableBeanFactory

3.prepareBeanFactory

拿到了beanFactory,再给beanFactory做一次准备工作,比如初始化属性什么的

4.postProcessBeanFactory(beanFactory)

Allows post-processing of the bean factory in context subclasses
这句话相当于给子类一个机会做一些操作,比如添加一些后置处理器进来(因为下一步就要执行后置处理器了,再次之前给一个机会再添加一些后置处理),也是为了代码灵活,查看子类并没有再这一步做什么操作

5.invokeBeanFactoryPostProcessors(beanFactory);

重点来了,字面意思执行BeanFactory后置处理器,看一下代码

protected void invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(beanFactory, getBeanFactoryPostProcessors());

这里相当于把工作交给一个类PostProcessorRegistrationDelegate处理,我们先管他叫后置处理委托器,spring使用这种委托模式来让代码规整,也比较符合单一职责

PostProcessorRegistrationDelegate把后置处理器相关的业务代码从ApplicationContext中抽离出来

那么继续跟到PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors这个方法,这个比较重要,得贴下代码

public static void invokeBeanFactoryPostProcessors(
            ConfigurableListableBeanFactory beanFactory, List<BeanFactoryPostProcessor> beanFactoryPostProcessors) {

        // Invoke BeanDefinitionRegistryPostProcessors first, if any.
        // 已执行的后置处理器(bean容器中),为防止重复执行
        Set<String> processedBeans = new HashSet<>();

        // 如果bean工厂是bean定义注册器,比如DefaultListableBeanFactory本身也是可以注册bean定义的注册器
        if (beanFactory instanceof BeanDefinitionRegistry) {
            // bean定义注册器
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            // 基础型后置处理器集合
            List<BeanFactoryPostProcessor> regularPostProcessors = new ArrayList<>();
            // bean定义注册型后置处理器集合
            List<BeanDefinitionRegistryPostProcessor> registryProcessors = new ArrayList<>();

            // 循环后置[参数]后置处理器
            for (BeanFactoryPostProcessor postProcessor : beanFactoryPostProcessors) {
                // 如果是bean定义注册型后置处理器,直接执行postProcessBeanDefinitionRegistry,并存入registryProcessors
                if (postProcessor instanceof BeanDefinitionRegistryPostProcessor) {
                    BeanDefinitionRegistryPostProcessor registryProcessor =
                            (BeanDefinitionRegistryPostProcessor) postProcessor;
                    registryProcessor.postProcessBeanDefinitionRegistry(registry);
                    registryProcessors.add(registryProcessor);
                }
                // 如果是基础型后置处理器,直接执行,并存入regularPostProcessors
                else {
                    regularPostProcessors.add(postProcessor);
                }
            }

            // 开始执行[bean容器中]后置处理器
            
            // 当前bean定义注册型后置处理器集合,为了按循序执行
            List<BeanDefinitionRegistryPostProcessor> currentRegistryProcessors = new ArrayList<>();

            // 首先,从bean容器中获取带@PriorityOrdered标识的bean定义注册型后置处理器
            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
            registryProcessors.addAll(currentRegistryProcessors);
            // 执行当前bean定义注册型后置处理器集合的postProcessBeanDefinitionRegistry方法
            invokeBeanDefinitionRegistryPostProcessors(currentRegistryProcessors, registry);
            // 清空当前bean定义注册型后置处理器集合
            currentRegistryProcessors.clear();

            // 其次, 从bean容器中获取带@Ordered标识的bean定义注册型后置处理器,逻辑和上一步基本一样
            postProcessorNames = beanFactory.getBeanNamesForType(BeanDefinitionRegistryPostProcessor.class, true, false);
            for (String ppName : postProcessorNames) {
                // 多了一个!processedBeans.contains判断,避免后置处理器被多次执行
                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);
            currentRegistryProcessors.clear();

            // 最后, 执行其他的bean定义注册型后置处理器,知道容器中的所有都被执行过
            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方法,bean定义注册型后置处理器也是基础型后置处理器的一种,所以也要执行
            // 这里的regularPostProcessors来源于[参数]后置处理器
            invokeBeanFactoryPostProcessors(registryProcessors, beanFactory);
            invokeBeanFactoryPostProcessors(regularPostProcessors, beanFactory);
        }

        else {
            // 如果传入的beanFactory不是bean定义注册器,只是简单的执行了[参数]后置处理器的postProcessBeanFactory方法
            invokeBeanFactoryPostProcessors(beanFactoryPostProcessors, beanFactory);
        }

        // 开始执行[bean容器中]普通后置处理器,和执行[bean容器中]bean定义注册型后置处理器基本逻辑差不多,都是按循序执行
        String[] postProcessorNames =
                beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);

        // 按@PriorityOrdered, @Ordered, 和无注解,区分优先级
        List<BeanFactoryPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
        List<String> orderedPostProcessorNames = new ArrayList<>();
        List<String> nonOrderedPostProcessorNames = new ArrayList<>();
        for (String ppName : postProcessorNames) {
            if (processedBeans.contains(ppName)) {
                // skip - already processed in first phase above
            }
            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);
            }
        }

        // 首先,执行带@PriorityOrdered的.
        sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
        invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);

        // 其次, 执行带@Ordered的.
        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));
        }
        // 执行了[bean容器中]基础型后置处理器的postProcessBeanFactory方法
        invokeBeanFactoryPostProcessors(nonOrderedPostProcessors, beanFactory);

        // Clear cached merged bean definitions since the post-processors might have
        // modified the original metadata, e.g. replacing placeholders in values...
        beanFactory.clearMetadataCache();
    }

上面的代码还是比较多,但总结起来也不复杂

首先,后置处理器主要有两种:

1).基础型后置处理器(BeanFactoryPostProcessor)
基础型后置处理器,只有一个方法postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory),可以配置bean工厂,比如bean工厂添加一些bean后置处理器

2).bean定义注册型后置处理器(BeanDefinitionRegistryPostProcessor)
bean定义注册型后置处理器,继承BeanFactoryPostProcessor,所以也属于基础型后置处理器的一种,新增一个方法postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry),增加功能:可以注册一些bean定义

其次,执行后置处理器,那么后置处理器在哪里?从代码里就可以看出
1).【参数】后置处理器
之前ApplicationContext存储了一些BeanFactory后置处理器,可以通过public的addBeanFactoryPostProcessor方法添加,比如springboot启动时就添加了一些后置处理器,这些后置处理器是用第二个参数:getBeanFactoryPostProcessors()传给后置处理委托器的

/** AbstractApplicationContext中 */
private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();

2).【bean容器中】的后置处理器
ApplicationContext引用了DefaultListableBeanFactory,这个BeanFactory中存放了很多的bean,这些bean有些是后置处理器类型的(比如子类初始化reader时通过AnnotationConfigUtils.registerAnnotationConfigProcessors方法存入的bean),那么只要通过beanFactory调用getBeanNamesForType就可以获取这些后置处理器,比如

// 通过类型获取所有后置处理器的名字
String[] postProcessorNames =
        beanFactory.getBeanNamesForType(BeanFactoryPostProcessor.class, true, false);
for (String ppName : postProcessorNames) {
        // 获取到后置处理器
        beanFactory.getBean(ppName, BeanFactoryPostProcessor.class);
    }
}

存在两个地方的后置处理器,分别通过BeanFactory和getBeanFactoryPostProcessors()传给后置处理委托器,那么下一步后置处理委托器就是执行这两种来源的后置处理器

执行过程就是上面代码,比较有意思,考虑到传入的参数DefaultListableBeanFactory本身就是BeanDefinitionRegistry所以执行逻辑如下

  • 执行[参数]后置处理器中的bean定义注册型后置处理器postProcessBeanDefinitionRegistry方法
  • 查找bean容器,执行[bean容器中]后置处理器中的bean定义注册型后置处理器postProcessBeanDefinitionRegistry方法,这个过程会按@PriorityOrdered>@Ordered>Other 顺序依次分批执行,执行完一批会重新去bean容器获取一次,直到获取不到为止,这样非常巧妙,如果某个bean定义注册型后置处理器有注册了一个该类型后置处理器,该后置处理器就会在后续的查找中被找出并执行,即可以用后置处理器添加后置处理器,有点传销的意思
  • 执行上两步bean定义注册型后置处理器的postProcessBeanFactory方法
  • 执行[参数]后置处理器中基础型后置处理器的postProcessBeanFactory方法
  • 查找bean容器,执行执行[bean容器中]后置处理器中的基础型后置处理器的postProcessBeanFactory方法,依然是按@PriorityOrdered>@Ordered>Other批次进行执行,但不会在这期间再次重新查找bean容器

总结:这一步完成了对两种来源的两种类型的beanFactory后置处理器的调用,期间注册型后置处理器注册的新后置处理器也会被执行

6.registerBeanPostProcessors(beanFactory);

beanFactory后置处理器的添加和调用都结束了,下一步就要开始弄bean后置处理了,前面讲过bean后置处理器是存在beanFactory中的,所以参数还是传了个beanFactory

protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
    PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}

同样还是交给了后置处理委托器去处理,上面reader初始化的时候往bean容器里加了一些beanFactory后置处理同时也有bean后置处理器,以bean的形式存储,那总得有人把这些后置处理器给摘出来放到beanFactory的bean后置处理列表里才能再创建时被调用,因为beanFactory的后置处理器存储地点如下

private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();

但是上面reader却把后置处理器放到了bean容器中,那肯定执行不了啊,所以这一步就是把beanFactory中的bean后置处理器类型的bean定义生产出来放入beanPostProcessors中,这些bean定义除了reader添加的几个还有大部分是上一步beanFactory后置处理器执行时加入到bean容器的

总结:这一步完成把以bean形式存储在beanFactory中的后置处理器摘出来放到beanFactory中专门存放后置处理器的地方,以便后续创建bean时使用

7.initMessageSource

国际化的一些处理,以后研究

8.initApplicationEventMulticaster

事件处理,以后研究

9.onRefresh

也是一个钩子,默认什么都不做,子类可以覆盖去做点事

10.registerListeners

事件的处理,以后研究

11.finishBeanFactoryInitialization(beanFactory)

这一步就很重要了,看注释Instantiate all remaining (non-lazy-init) singletons,实例化所有非懒加载的bean,也就是调用beanFactory的preInstantiateSingletons方法,创建所有单例bean(非懒加载的bean)

12.finishRefresh

结束后的一些操作,比如发布初始化结束事件等

总结

到此,refresh方法分析完了,抛去一些事件国际化相关的辅助代码,主要结合之前的流程总结如下

  • 配置主方法注入到bean容器
  • 添加一些beanFactory后置处理器和bean后置处理器,还有一些其它的bean至bean定义注册器
  • 执行beanFactory后置处理器,分BeanDefinitionRegistryPostProcessor和BeanFactoryPostProcessor两种,通过BeanFactoryPostProcessor可以配置bean工厂,通过BeanDefinitionRegistryPostProcessor可以注册一些bean定义也配置bean工厂,其间BeanDefinitionRegistryPostProcessor可以注册新的后置处理器,也会再后续执行
  • 提取bean容器中bean后置处理器类型的bean,添加到bean工厂的bean后置处理器列表中
  • 初始化所有单例非懒加载bean

到此spring启动时所执行重点方法就分析完了,其实按总结来看,就那么几个重点步骤,但是所谓的IOC和AOP到底如何实现的呐,并没有相关代码啊?

其实,这些功能都是通过后置处理器来实现的,也就是spring定义了一套后置处理器执行的规则,并把重点的工作都交给了内置的后置处理器来实现

IOC

spring是一个IOC容器,能把我们写的@Service,@Controller,@Component的类的bean定义注册,并生成bean加入容器,但刚刚我们看了new ApplicationContext的流程代码,发现用户写的类唯一被注册成bean定义就只有MainApplication.class

那么其他的bean(@Service,@Controller,@Component修饰的)是合适注册为bean定义的?

其实这部分工作就是后置处理器ConfigurationClassPostProcessor完成的,就是上文read构造时registerAnnotationConfigProcessors方法注册的后置处理器

ConfigurationClassPostProcessor翻译过来就是配置类后置处理器,就是专门处理配置类的,它继承了BeanDefinitionRegistryPostProcessor,因此拥有注册bean定义的能力

ConfigurationClassPostProcessor

那么重点看一下它的postProcessBeanDefinitionRegistry方法

@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
    // 省略
    processConfigBeanDefinitions(registry);
 }

进入processConfigBeanDefinitions,只捡主要代码贴,可自行对照

public void processConfigBeanDefinitions(BeanDefinitionRegistry registry) {
    // 创建一个解析器,解析@Configuration注解的类
    ConfigurationClassParser parser = new ConfigurationClassParser(
                this.metadataReaderFactory, this.problemReporter, this.environment,
                this.resourceLoader, this.componentScanBeanNameGenerator, registry);
    // 开始解析,这个candidates就是我们传入的MainApplication
    parser.parse(candidates);
    // 获取解析到的类
    Set<ConfigurationClass> configClasses = new LinkedHashSet<>(parser.getConfigurationClasses());
    // 初始化一个reader
    this.reader = new ConfigurationClassBeanDefinitionReader(
                        registry, this.sourceExtractor, this.resourceLoader, this.environment,
                        this.importBeanNameGenerator, parser.getImportRegistry());
    // 把上面解析到的类转化为bean定义并注册到bean定义注册器(registry)
    this.reader.loadBeanDefinitions(configClasses);
}

使用ConfigurationClassParser.parse进行配置类解析,而这个方法就包含了解析@ComponentScan@Import等注解

@ComponentScan就是我们制定的扫描包路径,会扫描路径下@Component注解的类(包括子注解@Configuration@Service等),注册成bean定义,同时会继续递归parse解析扫描到的ConfigurationClass(一般只带有@Configuration注解),直到把我们指定的所有bean加入bean容器

依赖注入

依赖注入是通过BeanPostProcessor实现的,即AutowiredAnnotationBeanPostProcessor,依然是上文read构造时registerAnnotationConfigProcessors方法注册的后置处理器,它修改了bean生命周期中填充属性的过程:

  • 查询带有@Autowired属性
  • 通过属性的type在bean容器中使用getBeanByType方式查找要注入的bean
  • 反射给属性赋值

AOP

ConfigurationClassParser.parse的时候还会扫描@Import注解,如果@Import的类继承了ImportBeanDefinitionRegistrar就可以自定义注册一些bean
AOP就是使用这种@Import+ImportBeanDefinitionRegistrar的方式完成AOP功能可配置的---注解@EnableAspectJAutoProxy,有则可以AOP,没有则不能AOP

@EnableAspectJAutoProxy

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AspectJAutoProxyRegistrar.class)
public @interface EnableAspectJAutoProxy {
    // 省略
}

其中引入了AspectJAutoProxyRegistrar,而AspectJAutoProxyRegistrar实现了ImportBeanDefinitionRegistrar,那么这个注解通过这种方式注册了什么bean呐?
答案就是bean后置处理器AnnotationAwareAspectJAutoProxyCreator,用来再bean创建过程中实现动态代理。

public static BeanDefinition registerAspectJAnnotationAutoProxyCreatorIfNecessary(
        BeanDefinitionRegistry registry, @Nullable Object source) {
    // 注册AnnotationAwareAspectJAutoProxyCreator
    return registerOrEscalateApcAsRequired(AnnotationAwareAspectJAutoProxyCreator.class, registry, source);
}

AnnotationAwareAspectJAutoProxyCreator继承了AbstractAutoProxyCreator继而继承BeanPostProcessor,创建代理的代码就写在AbstractAutoProxyCreator.wrapIfNecessary方法里,对其刚兴趣可以参考我之前的AOP系列文章

最后

这篇文章是根据之前的一篇文章改的,主要是因为之前写的有些不对,而且需要这里的知识时又发现很多地方已经忘了,所以这次要画一张大图,把今天总结的逻辑都包含在图中,下次再看,一目了然~

ApplicationContext

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/564783.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

计组 第二章 数据的表示与运算 2.1 数制与编码 知识点整理

2.1 数制与编码 二进制转八进制&#xff1a;3位一组&#xff0c;高位补0 二进制转十六进制&#xff1a;4位一组&#xff0c;高位补0 任意进制转十进制&#xff08;按权展开法&#xff09;&#xff1a;数码与权值相乘&#xff0c;再相加 十进制转化为任意进制数&#xff08;基…

全面接入:ChatGPT杀进10个商业应用,让AI替你打工

ChatGPT狂飙160天&#xff0c;世界已经不是两个月前的样子。 新建了一个网站 https://ai.weoknow.com/ 每天给大家更新可用的国内可用chatGPT资源 ChatGPT API已开放60多天。世界已经不是两个月前的样子了。 微软联合创始人比尔盖茨&#xff08;BillGates&#xff09;将GPT称…

一、预约挂号详情

文章目录 一、预约挂号详情1、需求分析 2、api接口2.1 添加service接口2.2 添加service接口实现2.2.1 在ScheduleServiceImpl类实现接口2.2.2 在获取科室信息 2.3 添加controller方法 3、前端3.1封装api请求3.2 页面展示 二、预约确认1、api接口1.1 添加service接口1.2 添加con…

FastRcnn理论合集

FastRcnn理论合集 Rcnn 论文原著 Rich feature hierarchies for accurate object detection and semantic segmentation R-CNN可以说是利用深度学习进行目标检测的开山之作。作者Ross Girshick多次在PASCAL VOC的目标检测竞赛中折桂&#xff0c;曾在2010年带领团队获得终身成就…

【P29】JMeter IF 控制器(If Controller)

文章目录 一、IF 控制器&#xff08;If Controller&#xff09;参数说明二、测试计划设计2.1、groovy 写法2.2、javaScript 写法2.3、jexl3 写法 一、IF 控制器&#xff08;If Controller&#xff09;参数说明 可以控制其下面的子/后代元素是否执行&#xff1b;如果为 true 则…

CSDN问答机器人

文章目录 前言一、背景二、总体流程三、构建知识库四、粗排五、精排六、Prompt总结相关博客 前言 先看结果: 已经连续很多周获得了第二名(万年老二), 上周终于拿了一回第一, 希望继续保持. &#x1f601; 这是今天的榜单, 采纳的数量相对较少, 之前基本上维持在100 重点说明…

数字韧性助力金融科技行稳致远 同创永益亮相2023双态IT武汉樱花论坛

2023年4月7日&#xff0c;由ITSS数据中心运营管理组DCMG指导&#xff0c;双态IT论坛主办的以“分布式架构和云原生时代的运维软件进化”为主题的“双态IT武汉樱花论坛”在武汉成功举办&#xff0c;共有来自银行、保险、证券等行业用户及企业代表近百人参会。 云原生时代下&am…

【Linux】-yum的使用

&#x1f496;作者&#xff1a;小树苗渴望变成参天大树 ❤️‍&#x1fa79;作者宣言&#xff1a;认真写好每一篇博客 &#x1f4a8;作者gitee:gitee &#x1f49e;作者专栏&#xff1a;C语言,数据结构初阶,Linux,C 如 果 你 喜 欢 作 者 的 文 章 &#xff0c;就 给 作 者 点…

某生存游戏玩家属性值分析

0x01 背景 这是一款丧尸生存的多人沙盒类游戏&#xff0c;角色在废墟之城内不断的搜刮&#xff0c;强化自己的装备和建造设施来抵御丧尸的无休止攻击&#xff0c;记住&#xff0c;这是一款团队合作游戏&#xff0c;你面对的丧尸随时可能夺走你的性命&#xff01; 0x02 玩家结…

【C++ Primer Plus】基础知识

C站的小伙伴们&#xff0c;大家好呀&#xff01;我最近开始阅读学习《C Primer Plus》这本书&#xff0c;在这里和大家一起分享。 下面是本书的第二章《开始学习C》 开始学习C 进入Cmain&#xff08;&#xff09;函数C注释C预处理器和iostream文件头文件名名称空间使用count进行…

【Linux专区】 Linux is not unix | Linux发展史 | Linux应用现状

&#x1f49e;&#x1f49e;欢迎来到 Claffic 的博客&#x1f49e;&#x1f49e; &#x1f449; 专栏&#xff1a;《Linux专区》&#x1f448; 前言&#xff1a; 上次提前带大家搭建了Linux的环境&#xff0c;其实之前应该还有一步的&#xff0c;就是向大家介绍Linux发展史&…

HNU-电路与电子学-小班3

第三次讨论 1 、直接用晶体管而不是逻辑门实现异或门&#xff0c;并解释这个电路是如何工作的。 &#xff08;6个 MOS 管构成&#xff09; 2 、通信双方约定采用 7 位海明码进行数据传输。请为发送方设计海明码校验位 生成电路&#xff0c;采用功能块和逻辑门为接收方设计海…

SCMA基本原理介绍

SCMA: Sparse Code Multiple Access SCMA基本原理 我们考虑一个同步&#xff08;synchronous&#xff09;的SCMA系统&#xff0c; 含1个基站&#xff08;Base Station, BS&#xff09;&#xff1b; J J J个用户&#xff08;so called layers&#xff09;&#xff1b;K个OFDM…

算法练习-2:送外卖

n 个小区排成一列&#xff0c;编号为从 0 到 n-1 。一开始&#xff0c;美团外卖员在第0号小区&#xff0c;目标为位于第 n-1 个小区的配送站。 给定两个整数数列 a[0]~a[n-1] 和 b[0]~b[n-1] &#xff0c;在每个小区 i 里你有两种选择&#xff1a; 1) 选择a&#xff1a;向前 a[…

shiro环境搭建

源码部署 这种方法相对复杂&#xff0c;如果不需要分析源码直接用docker就行 前置条件&#xff1a;Maven Ideal Tomcat 下载方式1&#xff1a;https://codeload.github.com/apache/shiro/zip/shiro-root-1.2.4&#xff0c;然后将文件夹导入ideal下载方式2&#xff1a;将shiro…

装饰者模式-java实现

的简介 装饰模式又称为“包装(Wrapper)模式”&#xff0c;以对客户端透明的方式扩展对象的功能&#xff0c;是继承关系的一个替代方案。动态地给对象添加一些额外地职责&#xff0c;就增加功能而言&#xff0c;装饰模式比生成子类更加灵活。 一般来说&#xff0c;一些特殊场景…

C++ new和delete详解

文章目录 1、 C C C内存分布2、 C C C内存管理方式3、 n e w new new 和 d e l e t e delete delete 底层实现4、定位 n e w new new表达式&#xff08;了解&#xff09;5、 m a l l o c 、 f r e e 和 n e w 、 d e l e t e malloc、free和new、delete malloc、free和new、de…

初识Linux:第六篇

初识Linux&#xff1a;第六篇 初识Linux&#xff1a;第六篇1.Linux 软件包管理器 yum2.Linux下的软件生态3.Linux中编辑器vim的使用3.1命令模式3.11控制光标移动3.12复制&#xff0c;粘贴&#xff0c;剪切&#xff0c;删除3.13替换&#xff0c;大小写转换3.14撤销与反撤销3.15查…

深度学习笔记之循环神经网络(六)长短期记忆神经网络(LSTM)

深度学习笔记之循环神经网络——长短期记忆神经网络[LSTM] 引言回顾&#xff1a; RNN \text{RNN} RNN的反向传播过程 RNN \text{RNN} RNN反向传播的梯度消失问题 长短期记忆神经网络遗忘门结构输入门结构遗忘门与输入门的特征融合操作输出门结构 个人感悟 引言 上一节介绍了循…

【C++】哈希——unordered系列容器哈希概念哈希冲突

文章目录 1. unordered系列的关联式容器1.1 引言1.2 unordered_map的使用说明1.3 unordered_set的使用说明1.4 unordered_set和unordered_map的应用1.5 性能比较 2. 哈希概念3. 哈希函数4. 哈希冲突5. 哈希冲突的解决——开散列和闭散列5.1 闭散列5.2 开散列 1. unordered系列的…