首先,先看SpringBoot的主配置类:SpringBootApplicationpublicclassStartEurekaApplication{publicstaticvoidmain(String〔〕args){SpringApplication。run(StartEurekaApplication。class,args);}} 点进SpringBootApplication来看,发现SpringBootApplication是一个组合注解。Target(ElementType。TYPE)Retention(RetentionPolicy。RUNTIME)DocumentedInheritedSpringBootConfigurationEnableAutoConfigurationComponentScan(excludeFilters{Filter(typeFilterType。CUSTOM,classesTypeExcludeFilter。class),Filter(typeFilterType。CUSTOM,classesAutoConfigurationExcludeFilter。class)})publicinterfaceSpringBootApplication{} 首先我们先来看SpringBootConfiguration:Target({ElementType。TYPE})Retention(RetentionPolicy。RUNTIME)DocumentedConfigurationpublicinterfaceSpringBootConfiguration{} 可以看到这个注解除了元注解以外,就只有一个Configuration,那也就是说这个注解相当于Configuration,所以这两个注解作用是一样的,它让我们能够去注册一些额外的Bean,并且导入一些额外的配置。 那Configuration还有一个作用就是把该类变成一个配置类,不需要额外的XML进行配置。所以SpringBootConfiguration就相当于Configuration。进入Configuration,发现Configuration核心是Component,说明Spring的配置类也是Spring的一个组件。Target({ElementType。TYPE})Retention(RetentionPolicy。RUNTIME)DocumentedComponentpublicinterfaceConfiguration{AliasFor(annotationComponent。class)Stringvalue()default;} 继续来看下一个EnableAutoConfiguration,这个注解是开启自动配置的功能。Target({ElementType。TYPE})Retention(RetentionPolicy。RUNTIME)DocumentedInheritedAutoConfigurationPackageImport({AutoConfigurationImportSelector。class})publicinterfaceEnableAutoConfiguration{StringENABLEDOVERRIDEPROPERTYspring。boot。enableautoconfiguration;Classlt;?〔〕exclude()default{};String〔〕excludeName()default{};} 可以看到它是由AutoConfigurationPackage,Import(EnableAutoConfigurationImportSelector。class)这两个而组成的,我们先说AutoConfigurationPackage,他是说:让包中的类以及子包中的类能够被自动扫描到spring容器中。Target({ElementType。TYPE})Retention(RetentionPolicy。RUNTIME)DocumentedInheritedImport({Registrar。class})publicinterfaceAutoConfigurationPackage{} 使用Import来给Spring容器中导入一个组件,这里导入的是Registrar。class。来看下这个Registrar:staticclassRegistrarimplementsImportBeanDefinitionRegistrar,DeterminableImports{Registrar(){}publicvoidregisterBeanDefinitions(AnnotationMetadatametadata,BeanDefinitionRegistryregistry){AutoConfigurationPackages。register(registry,(newAutoConfigurationPackages。PackageImport(metadata))。getPackageName());}publicSetObjectdetermineImports(AnnotationMetadatametadata){returnCollections。singleton(newAutoConfigurationPackages。PackageImport(metadata));}} 就是通过以上这个方法获取扫描的包路径,可以debug查看具体的值: 那metadata是什么呢,可以看到是标注在SpringBootApplication注解上的DemosbApplication,也就是我们的主配置类Application: 其实就是将主配置类(即SpringBootApplication标注的类)的所在包及子包里面所有组件扫描加载到Spring容器。因此我们要把DemoApplication放在项目的最高级中(最外层目录)。 看看注解Import(AutoConfigurationImportSelector。class),Import注解就是给Spring容器中导入一些组件,这里传入了一个组件的选择器:AutoConfigurationImportSelector。 可以从图中看出AutoConfigurationImportSelector继承了DeferredImportSelector继承了ImportSelector,ImportSelector有一个方法为:selectImports。将所有需要导入的组件以全类名的方式返回,这些组件就会被添加到容器中。publicString〔〕selectImports(AnnotationMetadataannotationMetadata){if(!this。isEnabled(annotationMetadata)){returnNOIMPORTS;}else{AutoConfigurationMetadataautoConfigurationMetadataAutoConfigurationMetadataLoader。loadMetadata(this。beanClassLoader);AutoConfigurationImportSelector。AutoConfigurationEntryautoConfigurationEntrythis。getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);returnStringUtils。toStringArray(autoConfigurationEntry。getConfigurations());}} 会给容器中导入非常多的自动配置类(xxxAutoConfiguration);就是给容器中导入这个场景需要的所有组件,并配置好这些组件。 有了自动配置类,免去了我们手动编写配置注入功能组件等的工作。那是如何获取到这些配置类的呢,看看下面这个方法:protectedAutoConfigurationImportSelector。AutoConfigurationEntrygetAutoConfigurationEntry(AutoConfigurationMetadataautoConfigurationMetadata,AnnotationMetadataannotationMetadata){if(!this。isEnabled(annotationMetadata)){returnEMPTYENTRY;}else{AnnotationAttributesattributesthis。getAttributes(annotationMetadata);ListStringconfigurationsthis。getCandidateConfigurations(annotationMetadata,attributes);configurationsthis。removeDuplicates(configurations);SetStringexclusionsthis。getExclusions(annotationMetadata,attributes);this。checkExcludedClasses(configurations,exclusions);configurations。removeAll(exclusions);configurationsthis。filter(configurations,autoConfigurationMetadata);this。fireAutoConfigurationImportEvents(configurations,exclusions);returnnewAutoConfigurationImportSelector。AutoConfigurationEntry(configurations,exclusions);}} 我们可以看到getCandidateConfigurations()这个方法,他的作用就是引入系统已经加载好的一些类,到底是那些类呢:protectedListStringgetCandidateConfigurations(AnnotationMetadatametadata,AnnotationAttributesattributes){ListStringconfigurationsSpringFactoriesLoader。loadFactoryNames(this。getSpringFactoriesLoaderFactoryClass(),this。getBeanClassLoader());Assert。notEmpty(configurations,NoautoconfigurationclassesfoundinMETAINFspring。factories。Ifyouareusingacustompackaging,makesurethatfileiscorrect。);returnconfigurations;}publicstaticListStringloadFactoryNames(Classlt;?factoryClass,NullableClassLoaderclassLoader){StringfactoryClassNamefactoryClass。getName();return(List)loadSpringFactories(classLoader)。getOrDefault(factoryClassName,Collections。emptyList());} 会从METAINFspring。factories中获取资源,然后通过Properties加载资源:privatestaticMapString,ListStringloadSpringFactories(NullableClassLoaderclassLoader){MultiValueMapString,Stringresult(MultiValueMap)cache。get(classLoader);if(result!null){returnresult;}else{try{EnumerationURLurlsclassLoader!null?classLoader。getResources(METAINFspring。factories):ClassLoader。getSystemResources(METAINFspring。factories);LinkedMultiValueMapresultnewLinkedMultiValueMap();while(urls。hasMoreElements()){URLurl(URL)urls。nextElement();UrlResourceresourcenewUrlResource(url);PropertiespropertiesPropertiesLoaderUtils。loadProperties(resource);Iteratorvar6properties。entrySet()。iterator();while(var6。hasNext()){Map。Entrylt;?,?entry(Map。Entry)var6。next();StringfactoryClassName((String)entry。getKey())。trim();String〔〕var9StringUtils。commaDelimitedListToStringArray((String)entry。getValue());intvar10var9。length;for(intvar110;var11var10;var11){StringfactoryNamevar9〔var11〕;result。add(factoryClassName,factoryName。trim());}}}cache。put(classLoader,result);returnresult;}catch(IOExceptionvar13){thrownewIllegalArgumentException(Unabletoloadfactoriesfromlocation〔METAINFspring。factories〕,var13);}}} 可以知道SpringBoot在启动的时候从类路径下的METAINFspring。factories中获取EnableAutoConfiguration指定的值,将这些值作为自动配置类导入到容器中,自动配置类就生效,帮我们进行自动配置工作。以前我们需要自己配置的东西,自动配置类都帮我们完成了。如下图可以发现Spring常见的一些类已经自动导入。 接下来看ComponentScan注解,ComponentScan(excludeFilters{Filter(typeFilterType。CUSTOM,classesTypeExcludeFilter。class),Filter(typeFilterType。CUSTOM,classesAutoConfigurationExcludeFilter。class)}),这个注解就是扫描包,然后放入spring容器。ComponentScan(excludeFilters{Filter(typeFilterType。CUSTOM,classes{TypeExcludeFilter。class}),Filter(typeFilterType。CUSTOM,classes{AutoConfigurationExcludeFilter。class})})publicinterfaceSpringBootApplication{} 总结下SpringbootApplication:就是说,他已经把很多东西准备好,具体是否使用取决于我们的程序或者说配置。 接下来继续看run方法:publicstaticvoidmain(String〔〕args){SpringApplication。run(Application。class,args);} 来看下在执行run方法到底有没有用到哪些自动配置的东西,我们点进run:publicConfigurableApplicationContextrun(String。。。args){计时器StopWatchstopWatchnewStopWatch();stopWatch。start();ConfigurableApplicationContextcontextnull;CollectionSpringBootExceptionReporterexceptionReportersnewArrayList();this。configureHeadlessProperty();监听器SpringApplicationRunListenerslistenersthis。getRunListeners(args);listeners。starting();CollectionexceptionReporters;try{ApplicationArgumentsapplicationArgumentsnewDefaultApplicationArguments(args);ConfigurableEnvironmentenvironmentthis。prepareEnvironment(listeners,applicationArguments);this。configureIgnoreBeanInfo(environment);BannerprintedBannerthis。printBanner(environment);准备上下文contextthis。createApplicationContext();exceptionReportersthis。getSpringFactoriesInstances(SpringBootExceptionReporter。class,newClass〔〕{ConfigurableApplicationContext。class},context);预刷新contextthis。prepareContext(context,environment,listeners,applicationArguments,printedBanner);刷新contextthis。refreshContext(context);刷新之后的contextthis。afterRefresh(context,applicationArguments);stopWatch。stop();if(this。logStartupInfo){(newStartupInfoLogger(this。mainApplicationClass))。logStarted(this。getApplicationLog(),stopWatch);}listeners。started(context);this。callRunners(context,applicationArguments);}catch(Throwablevar10){this。handleRunFailure(context,var10,exceptionReporters,listeners);thrownewIllegalStateException(var10);}try{listeners。running(context);returncontext;}catch(Throwablevar9){this。handleRunFailure(context,var9,exceptionReporters,(SpringApplicationRunListeners)null);thrownewIllegalStateException(var9);}} 那我们关注的就是refreshContext(context);刷新context,我们点进来看。privatevoidrefreshContext(ConfigurableApplicationContextcontext){refresh(context);if(this。registerShutdownHook){try{context。registerShutdownHook();}catch(AccessControlExceptionex){Notallowedinsomeenvironments。}}} 我们继续点进refresh(context);protectedvoidrefresh(ApplicationContextapplicationContext){Assert。isInstanceOf(AbstractApplicationContext。class,applicationContext);((AbstractApplicationContext)applicationContext)。refresh();} 他会调用((AbstractApplicationContext)applicationContext)。refresh();方法,我们点进来看:publicvoidrefresh()throwsBeansException,IllegalStateException{synchronized(this。startupShutdownMonitor){Preparethiscontextforrefreshing。prepareRefresh();Tellthesubclasstorefreshtheinternalbeanfactory。ConfigurableListableBeanFactorybeanFactoryobtainFreshBeanFactory();Preparethebeanfactoryforuseinthiscontext。prepareBeanFactory(beanFactory);try{Allowspostprocessingofthebeanfactoryincontextsubclasses。postProcessBeanFactory(beanFactory);Invokefactoryprocessorsregisteredasbeansinthecontext。invokeBeanFactoryPostProcessors(beanFactory);Registerbeanprocessorsthatinterceptbeancreation。registerBeanPostProcessors(beanFactory);Initializemessagesourceforthiscontext。initMessageSource();Initializeeventmulticasterforthiscontext。initApplicationEventMulticaster();Initializeotherspecialbeansinspecificcontextsubclasses。onRefresh();Checkforlistenerbeansandregisterthem。registerListeners();Instantiateallremaining(nonlazyinit)singletons。finishBeanFactoryInitialization(beanFactory);Laststep:publishcorrespondingevent。finishRefresh();}catch(BeansExceptionex){if(logger。isWarnEnabled()){logger。warn(Exceptionencounteredduringcontextinitializationcancellingrefreshattempt:ex);}Destroyalreadycreatedsingletonstoavoiddanglingresources。destroyBeans();Resetactiveflag。cancelRefresh(ex);Propagateexceptiontocaller。throwex;}finally{ResetcommonintrospectioncachesinSpringscore,sincewemightnoteverneedmetadataforsingletonbeansanymore。。。resetCommonCaches();}}} 由此可知,就是一个spring的bean的加载过程。继续来看一个方法叫做onRefresh():protectedvoidonRefresh()throwsBeansException{Forsubclasses:donothingbydefault。} 他在这里并没有直接实现,但是我们找他的具体实现: 比如Tomcat跟web有关,我们可以看到有个ServletWebServerApplicationContext:OverrideprotectedvoidonRefresh(){super。onRefresh();try{createWebServer();}catch(Throwableex){thrownewApplicationContextException(Unabletostartwebserver,ex);}} 可以看到有一个createWebServer();方法他是创建web容器的,而Tomcat不就是web容器,那是如何创建的呢,我们继续看:privatevoidcreateWebServer(){WebServerwebServerthis。webServer;ServletContextservletContextgetServletContext();if(webServernullservletContextnull){ServletWebServerFactoryfactorygetWebServerFactory();this。webServerfactory。getWebServer(getSelfInitializer());}elseif(servletContext!null){try{getSelfInitializer()。onStartup(servletContext);}catch(ServletExceptionex){thrownewApplicationContextException(Cannotinitializeservletcontext,ex);}}initPropertySources();} factory。getWebServer(getSelfInitializer());他是通过工厂的方式创建的。publicinterfaceServletWebServerFactory{WebServergetWebServer(ServletContextInitializer。。。initializers);} 可以看到它是一个接口,为什么会是接口。因为我们不止是Tomcat一种web容器。 我们看到还有Jetty,那我们来看TomcatServletWebServerFactory:OverridepublicWebServergetWebServer(ServletContextInitializer。。。initializers){TomcattomcatnewTomcat();FilebaseDir(this。baseDirectory!null)?this。baseDirectory:createTempDir(tomcat);tomcat。setBaseDir(baseDir。getAbsolutePath());ConnectorconnectornewConnector(this。protocol);tomcat。getService()。addConnector(connector);customizeConnector(connector);tomcat。setConnector(connector);tomcat。getHost()。setAutoDeploy(false);configureEngine(tomcat。getEngine());for(ConnectoradditionalConnector:this。additionalTomcatConnectors){tomcat。getService()。addConnector(additionalConnector);}prepareContext(tomcat。getHost(),initializers);returngetTomcatWebServer(tomcat);} 那这块代码,就是我们要寻找的内置Tomcat,在这个过程当中,我们可以看到创建Tomcat的一个流程。 如果不明白的话,我们在用另一种方式来理解下,大家要应该都知道stater举点例子。dependencygroupIdorg。springframework。bootgroupIdspringbootstarterdataredisartifactIddependencydependencygroupIdorg。springframework。bootgroupIdspringbootstarterfreemarkerartifactIddependency 首先自定义一个stater。parentgroupIdorg。springframework。bootgroupIdspringbootstarterparentartifactIdversion2。1。4。RELEASEversionrelativePathparentgroupIdcom。zgwgroupIdgwspringbootstarterartifactIdversion1。0SNAPSHOTversiondependenciesdependencygroupIdorg。springframework。bootgroupIdspringbootautoconfigureartifactIddependencydependencies 我们先来看maven配置写入版本号,如果自定义一个stater的话必须依赖springbootautoconfigure这个包,我们先看下项目目录。 publicclassGwServiceImplimplementsGwService{AutowiredGwPropertiesproperties;OverridepublicvoidHello(){Stringnameproperties。getName();System。out。println(name说:你们好啊);}} 我们做的就是通过配置文件来定制name这个是具体实现。ComponentConfigurationProperties(prefixspring。gwname)publicclassGwProperties{Stringnamezgw;publicStringgetName(){returnname;}publicvoidsetName(Stringname){this。namename;}} 这个类可以通过ConfigurationProperties读取配置文件。ConfigurationConditionalOnClass(GwService。class)扫描类EnableConfigurationProperties(GwProperties。class)让配置类生效publicclassGwAutoConfiguration{功能描述托管给springauthorzgwreturnBeanConditionalOnMissingBeanpublicGwServicegwService(){returnnewGwServiceImpl();}} 这个为配置类,为什么这么写因为,springboot的stater都是这么写的,我们可以参照他仿写stater,以达到自动配置的目的,然后我们在通过spring。factories也来进行配置。org。springframework。boot。autoconfigure。EnableAutoConfigurationcom。gw。GwAutoConfiguration 然后这样一个简单的stater就完成了,然后可以进行maven的打包,在其他项目引入就可以使用。 原文:cnblogs。comjing99p11504113。html