SpringBoot项目的启动的自动注入源码解析

实现是启动
然后一直往下,可以看到SpringApplication的主要逻辑:
public ConfigurableApplicationContext run(String... args) {
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    ConfigurableApplicationContext context = null;
    Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList();
    this.configureHeadlessProperty();
    SpringApplicationRunListeners listeners = this.getRunListeners(args);
    listeners.starting();

    Collection exceptionReporters;
    try {
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments);
        this.configureIgnoreBeanInfo(environment);
        Banner printedBanner = this.printBanner(environment);
        context = this.createApplicationContext();
        exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context);
        this.prepareContext(context, environment, listeners, applicationArguments, printedBanner);
        this.refreshContext(context);
        this.afterRefresh(context, applicationArguments);
        stopWatch.stop();
        if (this.logStartupInfo) {
            (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
        }

        listeners.started(context);
        this.callRunners(context, applicationArguments);
    } catch (Throwable var10) {
        this.handleRunFailure(context, var10, exceptionReporters, listeners);
        throw new IllegalStateException(var10);
    }

    try {
        listeners.running(context);
        return context;
    } catch (Throwable var9) {
        this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null);
        throw new IllegalStateException(var9);
    }
}

这里主要关注一些主干方法:

   1、 context = this.createApplicationContext();

        debug进去可以看到这里获取到的类是AnnotationConfigServletWebServerApplicationContext:

         看其初始化方法

public AnnotationConfigServletWebServerApplicationContext() {
    this.annotatedClasses = new LinkedHashSet();
    this.reader = new AnnotatedBeanDefinitionReader(this);
    this.scanner = new ClassPathBeanDefinitionScanner(this);
}

这两个一个是读取器,一个是扫描器,先来看AnnotatedBeanDefinitionReader 的初始化:

public AnnotatedBeanDefinitionReader(BeanDefinitionRegistry registry, Environment environment) {
    this.beanNameGenerator = new AnnotationBeanNameGenerator();
    this.scopeMetadataResolver = new AnnotationScopeMetadataResolver();
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    Assert.notNull(environment, "Environment must not be null");
    this.registry = registry;
    this.conditionEvaluator = new ConditionEvaluator(registry, environment, (ResourceLoader)null);
    AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
}
除了一些基本赋值,主要是AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry)注册了5个BeanFactoryPostProcessor的Spring容器中;

 

其中这里面主要是ConfigurationClassPostProcessor类,实现了BeanDefinitionRegistryPostProcessor接口,此接口继承了BeanFactoryPostProcessor:

   2、先往下看:this.refreshContext(context);

public void refresh() throws BeansException, IllegalStateException {
    Object var1 = this.startupShutdownMonitor;
    synchronized(this.startupShutdownMonitor) {
        this.prepareRefresh();
        ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
        this.prepareBeanFactory(beanFactory);

        try {
            this.postProcessBeanFactory(beanFactory);
            this.invokeBeanFactoryPostProcessors(beanFactory);
            this.registerBeanPostProcessors(beanFactory);
            this.initMessageSource();
            this.initApplicationEventMulticaster();
            this.onRefresh();
            this.registerListeners();
            this.finishBeanFactoryInitialization(beanFactory);
            this.finishRefresh();
        } catch (BeansException var9) {
            if (this.logger.isWarnEnabled()) {
                this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
            }

            this.destroyBeans();
            this.cancelRefresh(var9);
            throw var9;
        } finally {
            this.resetCommonCaches();
        }

    }
}

关于Bean加载以及初始化的一大堆逻辑就在此了。

   关于这个方法的整体了解可以看下我的这篇文章:https://blog.csdn.net/qq_25179481/article/details/100188594

这里我们以自动加载为主要目标来找到实现方法:我们前面有提到,实现了

BeanDefinitionRegistryPostProcessor的ConfigurationClassPostProcessor,这里我们直接来看其的执行:通过this.invokeBeanFactoryPostProcessors()

    直接debug来到其的processConfigBeanDefinitions(BeanDefinitionRegistry registry)方法:

        可以看到现在已经注册了7个Bean:

其中有一个thymeleafApplication,就是我们的启动类,有加一个SpringBootApplication的组合注解(关于注解就不展开了),现在会将其筛选出来,因为要使用这个注解

这里主要就是parser.parse(candidates)方法,这里面会有复杂的循环调用,因为@Configuration、@Import等注解需要循环调用去获取对应的信息,就不具体展开来讲了。我们看主要的方法:

  一、ConfigurationClassParser类的processConfigurationClass方法:

           

我们可以看到现在这个BeanDefinition已经变成了一个对应的Configuration,其中annotations是这个注解有什么属性,就是根据这些去进行对应的解析的,正确来说是根据注解去获取这些属性的值。(以下整理可能来自来ConfigurationClassParser类的不同方法),如

   1、Set<AnnotationAttributes> componentScans = AnnotationConfigUtils.attributesForRepeatable(sourceClass.getMetadata(), ComponentScans.class, ComponentScan.class);

其中ComponentScan、ComponentScans等这些都是注解

  2、if (candidate.isAssignable(ImportSelector.class))

     3、importResource = AnnotationConfigUtils.attributesFor(sourceClass.getMetadata(), ImportResource.class);

     4、

public static boolean isFullConfigurationCandidate(AnnotationMetadata metadata) {
   return metadata.isAnnotated(Configuration.class.getName());
}

等就是根据这些注解加上循环检测及调用,就能进行拓展来将满足这些注解条件、条件的Bean加载到spring容器中。

 

此后我们来看下另一个重要的方法:this.deferredImportSelectorHandler.process();这里就是springBoot项目根据你引用的jar包就能自动帮你配置,不用你像以前springMVC那样手动的去写一些配置了。

    在这个方法中进行debug:

       

可以看到

SpringFactoriesLoader.loadFactoryNames()方法,而这个spring.factories就是在每个jar包下面,所以你引用了什么jar包,就会帮你自动注入那些需要的类,然后可以看到加载了哪些Bean:

      

我们选两个典型来看下这些有什么用,WebMvcAutoConfiguration类:

  看下其中的代码:

     

我们看到如果有类DispatcherServlet、WebMvcConfiguration,就进行加载。

      

DispatcherServletAutoConfiguration类

通过这些我们就知道了,DispathcherServlet中那些处理器、处理器适配器是通过什么注入进去的了,以及那些需要的Bean是怎样自动注入的。

自此。关于SpringBoot项目的启动就大体有所了解了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值