springboot应用启动原理分析.docx
springbootquickstart在springboot里彳艮吸引人的T特性是可以干脆把应用打包成为一Tjar/war,然后这个jar/war是可以干脆启动的,不须要另外配置一个WebServer.假如之前没有运用过springboot可以通过下面的demo来感受下.下面以这个工程为例,演示如何启动Springboot项目:gitclone:hengyuabcspring-boot-demo.gitmvnSpring-boot-demojava-jartargetdemo-<>.1-SNAPSHOT.jar123假如运用的IDE是springsts或者idea,可以通过向导来创建springboot项目。也可以参考官方教程:对SPringboot的两个疑问刚起先接触springboot时,通常会有这些疑问 springboot如何启动的? springbootembedtomcat是如何工作的?睁态文件Jsp,网页模板这些是如何加载到?下面来分析springboot是如何做到的打包为单个jar时,springboot的启动方式maven打包之后,会生成两个jar文件:dem-e.I-SNAPSHOTJardemo-0.,1-SNAPSHOTjar.original其中demo0.0.1SNAPSHOT,jar.original是默认的mavenjar-plugin生成的包.demo-0.0.1SNAPSHOTjar是springbootmaven插件生成的jar包,里面包含了应用的依靠,以及springboot相关的类.下面称之为fatjar.先来直看springboot打好的包的书目结构(不重要的省略掉):I-META-INFII-MANIFEST.MFIapplication.propertiesIcomexampleSpringBootDemoApplication-Class|aopalliance-l.jarIsprlng-beans-4<2,3。RElEASEJarI.org1 springframework1- boot,loaderExecutableArchive1.auncher.classJar1.aucher.classIDavaAgentDetector,class1.aunchedUR1.Class1.oader.classI1.auncherxlassIMainMethodRunner.class9101112131415161718192021依次来看下这些内容。MANIFEST.MFHanifest-Version:1Start-Class:com.example.SpringBootDemoApplicationImplementation-Vendor-Id:com.exampleSpring-Boot-Version;1。3.(RE1.EASECreated-By:Build-Jdk:1.86Implementatiorv-Vendor:PivotalSoftware.Inc.Main-Class:orgSpringframework.boot.loader.Jar1.auncher12345678可以看至!J有Main-Class是org.springframework.boot.loader.Jar1.auncherr这个是jar启动的Main函数.还有一个StartClass是com.e×ampleSPringBootDemOAPPIiCation,这个是我彳口应用自己的Main函数.SpringBootApplicationpublicclassSpringBootDemoApplicationpublicstaticvoidmain(StringIIargs)SpringApplication.run(SpringBootDeffloApplication.class,args);) 3 4 5 6 7com/example书目这下面放的是应用的.class文件.Iib书目这里存放的是应用的Maven依靠的jar包文件.比如springbeans,SPring-mvc等jar.org/springframework/boot/loader书目这下面存放的是Springbootloader的.class文件.Archive的概念 archive即归档文件,这个概念在IinUX下册5常见 通常就是ftar/zip格式的压缩包 jar是ZiP格式在springboot里,抽象出了Archive的蟋.一个archive可以是一个jar(Jar),也可以是一个文件书目(ExpIodedArchive).可以理解为Springboot抽象出来的统一访问资源的层.上面的demo0。Ol-SNAPSHOTjar是一个ArChiVe,砺demo-0。O.l-SNAPSHOT.jar里的/Iib书目下面的每一个Jar包,也是一个ArChiVe.publicabstractclassArchivepublicabstractUR1.getUrl();publicStringgetMainClass():publicabstractCollection(Entry>getEntries():publicabstract1.ist<Archive>getNestedArchives(EntryFiIterfilter); 1 2 3 4 5可以看到Archive有f自己的UR1.,比如:jar:-SNAPSHOTJar!/ 1还有一个QetNestedArchives函数,这个实际返回的是demo0.01-SNAPSHOT,jar/lib下面的jar的Archive列表.它们的UR1.是:jar:et0.1-snapshot.jarI/IibZaopalliance-I>0.jarjar:).1-SNAPSHOT,jar!libspri11g-beans-4.2.3.RE1.EASE,jarJar1.auncher从MANIFEST.MF可以看到Main函数是Jar1.auncherr下面来分析它的工作流程.Jar1.aUnCher类的继承结构是:classJar1.auncherextendsExecutableArchive1.auncherclassExecutableArchive1.auncherextends1.auncher以demo0.0。1SNAPSHOTjar创建一个ArChiVe:Jar1.aUrKher先找到自己所在的jar,即demoO.0.I-SNAPSHOTjar的路径,然后创建了一个Archive.下面的代码展示了如何从一个类找到它的加载的位置的技巧:protectedfinalArchiveCreateArChiVe()throwsException(ProtectionDomainprotectIonDcxnain=getClass(),getProtectioDomain();CodeSourcecodeSource=protectionDomai11.getCodeSource():URIlocation=(codeSource=null?null;codesource.get1.ocatlon()toRIO>;StringpathH(location=null?null:location.getSchemeSpecificPart();if(path-null)throwneMIIlegalStateException(wUnabletodeterminecodesourcearchive”):=new);if(!root,exists()thrownewIllegalStateException("Unabletodeterminecodesourcearchivefrom"+root);return(root.isDirectory()?newExplodedArchive(root):newJar(root):) 1 2 3 4 5 6 7 8 9101415获得ib下面的jar,并创建一个1.aunchedUR1.CIass1.oaderJar1.auncher创建好Archive之后,通过getNestedArchives函数来获得到demo-0.0.1SNAPSHOT.jar/lib下面的全部jar文件,并创建为1.ist.留意上面提到,Archive都是有自己的UR1.的。获得到这些Archive的UR1.之后,也就获得了一个UR1.口数组,用这个来构造一个自定义的CIass1.oader:1.aunchedUR1.CIass1.oadere创建好CIaSS1.Oader之后,再从MANIFEST.MF里读取到Start-Class,即com.e×ample.SpringBootDemoApplication,然后创建一个新的线程来启动应用的Main函数./*1.aunchtheapplicationgiventhearchiveafullyconfiguredclassloader.*/protectedvoidlaunch(Stringargs,StringmainClass,Class1.oaderClass1.oader)throwsExceptionRunnablerunner=createMainMethodRunner(mainClass.args,Class1.oader);Threadrunnerhread=newThread(runner);runnerThread.SetcontextClass1.oader(Class1.oader):runerThreadoSetName(ThreadcurrentThread().getNameO);runerThread,.start();)/*Createthe©codeMainMethodRunnerJusedtolaunchtheapplication.*/protectedRunnablecreateMainMethodRunner(StringmaiClass.Stringargs.Class1.oaderClass1.oader)throwsException(Class<?)runner<lass=Class1.oader.IoadClass(RUNNEReC1.ASS):Constructor<?)constructorrunnerdass.getConstructor(String,class,String.class);return(Runnable)constructornewlnstancemaiClass.args):)12 5 6 7 8