带着问题看SpringBoot

带着问题看SpringBoot

1、Spring容器具体是什么?

跟进run方法,context = this.createApplicationContext(),得出容器是AnnotationConfigServletWebServerApplicationContext类。

复制代码
SpringApplication.run(ServeroneApplication.class, args);

   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);
        }
    }

    protected ConfigurableApplicationContext createApplicationContext() {
        Class<?> contextClass = this.applicationContextClass;
        if (contextClass == null) {
            try {
                switch (this.webApplicationType) {
                    case SERVLET:
                        contextClass = Class.forName("org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext");
                        break;
                    case REACTIVE:
                        contextClass = Class.forName("org.springframework.boot.web.reactive.context.AnnotationConfigReactiveWebServerApplicationContext");
                        break;
                    default:
                        contextClass = Class.forName("org.springframework.context.annotation.AnnotationConfigApplicationContext");
                }
            } catch (ClassNotFoundException var3) {
                throw new IllegalStateException("Unable create a default ApplicationContext, please specify an ApplicationContextClass", var3);
            }
        }

        return (ConfigurableApplicationContext)BeanUtils.instantiateClass(contextClass);
    }
2、SpringBoot中Tomcat的启动流程。

2.1、跟进TomcatWebServer类的initialize() 方法,断点到logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));然后反向debug你可以看出Tomcat的初始化过程,是在容器执行run()方法的时候执行refresh()方法的this.onRefresh();的时候初始化的。

复制代码
   private void initialize() throws WebServerException {
        logger.info("Tomcat initialized with port(s): " + this.getPortsDescription(false));
        synchronized(this.monitor) {
            try {
                this.addInstanceIdToEngineName();
                Context context = this.findContext();
                context.addLifecycleListener((event) -> {
                    if (context.equals(event.getSource()) && "start".equals(event.getType())) {
                        this.removeServiceConnectors();
                    }

                });
                this.tomcat.start();
                this.rethrowDeferredStartupExceptions();

                try {
                    ContextBindings.bindClassLoader(context, context.getNamingToken(), this.getClass().getClassLoader());
                } catch (NamingException var5) {
                }

                this.startDaemonAwaitThread();
            } catch (Exception var6) {
                this.stopSilently();
                this.destroySilently();
                throw new WebServerException("Unable to start embedded Tomcat", var6);
            }

        }
    }

    public void refresh() throws BeansException, IllegalStateException {
        synchronized(this.startupShutdownMonitor) {
            StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
            this.prepareRefresh();
            ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
            this.prepareBeanFactory(beanFactory);

            try {
                this.postProcessBeanFactory(beanFactory);
                StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
                this.invokeBeanFactoryPostProcessors(beanFactory);
                this.registerBeanPostProcessors(beanFactory);
                beanPostProcess.end();
                this.initMessageSource();
                this.initApplicationEventMulticaster();
                //Tomcat初始化
                this.onRefresh();
                this.registerListeners();
                this.finishBeanFactoryInitialization(beanFactory);
                this.finishRefresh();
            } catch (BeansException var10) {
                if (this.logger.isWarnEnabled()) {
                    this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
                }

                this.destroyBeans();
                this.cancelRefresh(var10);
                throw var10;
            } finally {
                this.resetCommonCaches();
                contextRefresh.end();
            }

        }
    }
3、SpringBoot加载配置文件。

3.1、跟进run()到SpringApplication类的run()方法的ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);

复制代码
SpringApplication.run(TestApplication.class, args);

3.2、跟进prepareEnvironment()--->listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment);--->SimpleApplicationEventMulticaster类的doInvokeListener()方法。

复制代码
    private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
        try {
            listener.onApplicationEvent(event);
        } catch (ClassCastException var6) {
            String msg = var6.getMessage();
            if (msg != null && !this.matchesClassCastMessage(msg, event.getClass())) {
                throw var6;
            }

            Log logger = LogFactory.getLog(this.getClass());
            if (logger.isTraceEnabled()) {
                logger.trace("Non-matching event type for listener: " + listener, var6);
            }
        }

    }

当listener为EnvironmentPostProcessorApplicationListener的时候,进入onApplicationEvent()方法。

复制代码
 public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationEnvironmentPreparedEvent) {
            this.onApplicationEnvironmentPreparedEvent((ApplicationEnvironmentPreparedEvent)event);
        }

        if (event instanceof ApplicationPreparedEvent) {
            this.onApplicationPreparedEvent((ApplicationPreparedEvent)event);
        }

        if (event instanceof ApplicationFailedEvent) {
            this.onApplicationFailedEvent((ApplicationFailedEvent)event);
        }

    }

跟进onApplicationEnvironmentPreparedEvent()方法。

复制代码
  private void onApplicationEnvironmentPreparedEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment environment = event.getEnvironment();
        SpringApplication application = event.getSpringApplication();
        Iterator var4 = this.getEnvironmentPostProcessors(event.getBootstrapContext()).iterator();

        while(var4.hasNext()) {
            EnvironmentPostProcessor postProcessor = (EnvironmentPostProcessor)var4.next();
            postProcessor.postProcessEnvironment(environment, application);
        }

    }

跟进到ConfigDataEnvironmentPostProcessor类的postProcessEnvironment()。

复制代码
 void postProcessEnvironment(ConfigurableEnvironment environment, ResourceLoader resourceLoader, Collection<String> additionalProfiles) {
        try {
            this.logger.trace("Post-processing environment to add config data");
            ResourceLoader resourceLoader = resourceLoader != null ? resourceLoader : new DefaultResourceLoader();
            this.getConfigDataEnvironment(environment, (ResourceLoader)resourceLoader, additionalProfiles).processAndApply();
        } catch (UseLegacyConfigProcessingException var5) {
            this.logger.debug(LogMessage.format("Switching to legacy config file processing [%s]", var5.getConfigurationProperty()));
            this.postProcessUsingLegacyApplicationListener(environment, resourceLoader);
        }

    }

跟进processAndApply()方法。

复制代码
  void processAndApply() {
        ConfigDataImporter importer = new ConfigDataImporter(this.logFactory, this.notFoundAction, this.resolvers, this.loaders);
        this.bootstrapContext.register(Binder.class, InstanceSupplier.from(() -> {
            return this.contributors.getBinder((ConfigDataActivationContext)null, new ConfigDataEnvironmentContributors.BinderOption[]{BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE});
        }));
        ConfigDataEnvironmentContributors contributors = this.processInitial(this.contributors, importer);
        Binder initialBinder = contributors.getBinder((ConfigDataActivationContext)null, new ConfigDataEnvironmentContributors.BinderOption[]{BinderOption.FAIL_ON_BIND_TO_INACTIVE_SOURCE});
        this.bootstrapContext.register(Binder.class, InstanceSupplier.of(initialBinder));
        ConfigDataActivationContext activationContext = this.createActivationContext(initialBinder);
        contributors = this.processWithoutProfiles(contributors, importer, activationContext);
        activationContext = this.withProfiles(contributors, activationContext);
        contributors = this.processWithProfiles(contributors, importer, activationContext);
        this.applyToEnvironment(contributors, activationContext);
    }

跟进this.processInitial(this.contributors, importer)方法->withProcessedImports()方法->importer.resolveAndLoad(activationContext, locationResolverContext, loaderContext, imports)方法->this.load(loaderContext, resolved);

复制代码
 ConfigDataEnvironmentContributors withProcessedImports(ConfigDataImporter importer, ConfigDataActivationContext activationContext) {
        ConfigDataEnvironmentContributor.ImportPhase importPhase = ImportPhase.get(activationContext);
        this.logger.trace(LogMessage.format("Processing imports for phase %s. %s", importPhase, activationContext != null ? activationContext : "no activation context"));
        ConfigDataEnvironmentContributors result = this;
        int processed = 0;

        while(true) {
            ConfigDataEnvironmentContributor contributor = this.getNextToProcess(result, activationContext, importPhase);
            if (contributor == null) {
                this.logger.trace(LogMessage.format("Processed imports for of %d contributors", processed));
                return result;
            }

            if (contributor.getKind() == Kind.UNBOUND_IMPORT) {
                Iterable<ConfigurationPropertySource> sources = Collections.singleton(contributor.getConfigurationPropertySource());
                PlaceholdersResolver placeholdersResolver = new ConfigDataEnvironmentContributorPlaceholdersResolver(result, activationContext, true);
                Binder binder = new Binder(sources, placeholdersResolver, (ConversionService)null, (Consumer)null, (BindHandler)null);
                ConfigDataEnvironmentContributor bound = contributor.withBoundProperties(binder);
                result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext, result.getRoot().withReplacement(contributor, bound));
            } else {
                ConfigDataLocationResolverContext locationResolverContext = new ContributorConfigDataLocationResolverContext(result, contributor, activationContext);
                ConfigDataLoaderContext loaderContext = new ContributorDataLoaderContext(this);
                List<ConfigDataLocation> imports = contributor.getImports();
                this.logger.trace(LogMessage.format("Processing imports %s", imports));
                Map<ConfigDataResolutionResult, ConfigData> imported = importer.resolveAndLoad(activationContext, locationResolverContext, loaderContext, imports);
                this.logger.trace(LogMessage.of(() -> {
                    return this.getImportedMessage(imported.keySet());
                }));
                ConfigDataEnvironmentContributor contributorAndChildren = contributor.withChildren(importPhase, this.asContributors(imported));
                result = new ConfigDataEnvironmentContributors(this.logger, this.bootstrapContext, result.getRoot().withReplacement(contributor, contributorAndChildren));
                ++processed;
            }
        }
    }

到这里就差不多加载到配置文件了。

相关推荐
骑士雄师8 分钟前
Java 泛型中级面试题及答案
java·开发语言·面试
Victor35610 分钟前
Redis(61)Redis的连接数上限是多少?
后端
Victor35614 分钟前
Redis(60) Redis的复制延迟如何优化?
后端
.格子衫.6 小时前
Spring Boot 原理篇
java·spring boot·后端
多云几多6 小时前
Yudao单体项目 springboot Admin安全验证开启
java·spring boot·spring·springbootadmin
摇滚侠8 小时前
Spring Boot 3零基础教程,Spring Intializer,笔记05
spring boot·笔记·spring
Jabes.yang8 小时前
Java求职面试实战:从Spring Boot到微服务架构的技术探讨
java·数据库·spring boot·微服务·面试·消息队列·互联网大厂
聪明的笨猪猪8 小时前
Java Redis “高可用 — 主从复制”面试清单(含超通俗生活案例与深度理解)
java·经验分享·笔记·面试
兮动人8 小时前
Spring Bean耗时分析工具
java·后端·spring·bean耗时分析工具
MESSIR229 小时前
Spring IOC(控制反转)中常用注解
java·spring