真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

Spring-Boot啟動之前做了哪些事?

Spring Boot Jar文件探究

初始化一個Spring 應(yīng)用,添加如下依賴

創(chuàng)新互聯(lián)公司專注于企業(yè)全網(wǎng)營銷推廣、網(wǎng)站重做改版、東風(fēng)網(wǎng)站定制設(shè)計、自適應(yīng)品牌網(wǎng)站建設(shè)、H5頁面制作、成都商城網(wǎng)站開發(fā)、集團公司官網(wǎng)建設(shè)、外貿(mào)營銷網(wǎng)站建設(shè)、高端網(wǎng)站制作、響應(yīng)式網(wǎng)頁設(shè)計等建站業(yè)務(wù),價格優(yōu)惠性價比高,為東風(fēng)等各大城市提供網(wǎng)站開發(fā)制作服務(wù)。



    4.0.0
    
        org.springframework.boot
        spring-boot-starter-parent
        2.1.6.RELEASE
         
    
    com.fxipp.spring
    first-app-by-gui
    0.0.1-SNAPSHOT
    first-app-by-gui
    Demo project for Spring Boot

    
        1.8
    

    
        
            org.springframework.boot
            spring-boot-starter-web
        

        
            org.springframework.boot
            spring-boot-starter-test
            test
        
    

    
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
        
    

執(zhí)行mvn package命令打包,查看jar包的目錄結(jié)構(gòu)

.
├── BOOT-INF
│?? ├── classes
│?? │?? ├── application.properties
│?? │?? └── com
│?? │??     └── fxipp
│?? │??         └── spring
│?? │??             └── FirstAppByGuiApplication.class
│?? └── lib
│??     ├── classmate-1.4.0.jar
│??     ├── hibernate-validator-6.0.17.Final.jar
│??     ├── jackson-annotations-2.9.0.jar
│??     ├── jackson-core-2.9.9.jar
│??     ......
├── META-INF
│?? ├── MANIFEST.MF
│?? └── maven
│??     └── com.fxipp.spring
│??         └── first-app-by-gui
│??             ├── pom.properties
│??             └── pom.xml
└── org
    └── springframework
        └── boot
            └── loader
                ├── ExecutableArchiveLauncher.class
                ├── JarLauncher.class
                ├── LaunchedURLClassLoader$UseFastConnectionExceptionsEnumeration.class
                ├── LaunchedURLClassLoader.class
                ├── ......
                ├── archive
                │?? ├── Archive$Entry.class
                │?? ├── Archive$EntryFilter.class
                │?? ├── Archive.class
                │?? ├── ......
                ├── data
                │?? ├── RandomAccessData.class
                │?? ├── RandomAccessDataFile$1.class
                │?? ├──......
                ├── jar
                │?? ├── AsciiBytes.class
                │?? ├── Bytes.class
                │?? ├── ......
                └── util
                    └── SystemPropertyUtils.class
18 directories, 91 files

文件結(jié)構(gòu)比較復(fù)雜,解釋一下

  • BOOT-INF/classes: 存放應(yīng)用編譯后的class文件;
  • BOOT-INF/lib:class path目錄, 存放應(yīng)用依賴的jar包;
  • META-INF: 存放應(yīng)用的元信息,如MANIFEST.MF文件;
  • org:存放Spring Boot自身的class文件;

Jar文件的執(zhí)行器: Spring Boot Loader

我們先從MANIFEST.MF文件查看

Manifest-Version: 1.0
Implementation-Title: first-app-by-gui
Implementation-Version: 0.0.1-SNAPSHOT
Start-Class: com.fxipp.spring.FirstAppByGuiApplication
Spring-Boot-Classes: BOOT-INF/classes/
Spring-Boot-Lib: BOOT-INF/lib/
Build-Jdk-Spec: 1.8
Spring-Boot-Version: 2.1.6.RELEASE
Created-By: Maven Archiver 3.4.0
Main-Class: org.springframework.boot.loader.JarLauncher

里面記錄了應(yīng)用的元信息,Spring的版本,應(yīng)用的版本,Maven的版本,Main-Class等信息。不難發(fā)現(xiàn),MainClass指向的是org.springframework.boot.loader.JarLauncher(以下簡稱JarLauncher),而不是我們自己編寫的com.fxipp.spring.FirstAppByGuiApplication。

JarLauncher從名字看出是一個jar的執(zhí)行器,他的class文件位于org.springframework.boot.loader目錄下,可見它是Spring自身的class文件。

JarLauncher的GAV org.springframework.boot:spring-boot-loader:2.1.6.RELEASE

通常情況下,他會在spring-boot-starter-parent引入到應(yīng)用中,既然main-class指向到是JarLauncher,那我們也可以直接執(zhí)行java org.springframework.boot.loader.JarLauncher,也可以啟動Spring項目的。

java org.springframework.boot.loader.JarLauncher

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.6.RELEASE)

2019-06-19 20:30:52.202  INFO 3094 --- [           main] c.fxipp.spring.FirstAppByGuiApplication  : Starting FirstAppByGuiApplication on fangxideMacBook-Pro.local with PID 3094 (/Users/fangxi/Java/workspace/default/spring-boot/first-app-by-gui/target/temp/BOOT-INF/classes started by fangxi in /Users/fangxi/Java/workspace/default/spring-boot/first-app-by-gui/target/temp)

既然可以執(zhí)行,那就說明了,JarLauncher這個類才是Spring項目真正的入口。如果我們執(zhí)行自己寫的com.fxipp.spring.FirstAppByGuiApplication會怎么樣?

?  classes java com.fxipp.spring.FirstAppByGuiApplication
Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/boot/SpringApplication
    at com.fxipp.spring.FirstAppByGuiApplication.main(FirstAppByGuiApplication.java:10)
Caused by: java.lang.ClassNotFoundException: org.springframework.boot.SpringApplication
    at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    ... 1 more

啟動報錯,原因是找不到org.springframework.boot.SpringApplication這個類,說白了就是沒有指定Class Path,Spring Boot應(yīng)用的Class Path目錄是BOOT-INF/lib。

也就是說,JarLauncher可以執(zhí)行成功,是因為Spring Boot知道了Class Path的路徑,說明JarLauncher在啟動調(diào)用com.fxipp.spring.FirstAppByGuiApplication之前,指定了Class Path的位置。

JarLauncher的代碼如下

public class JarLauncher extends ExecutableArchiveLauncher {

   static final String BOOT_INF_CLASSES = "BOOT-INF/classes/";

   static final String BOOT_INF_LIB = "BOOT-INF/lib/";

   public JarLauncher() {
   }

   protected JarLauncher(Archive archive) {
      super(archive);
   }

   @Override
   protected boolean isNestedArchive(Archive.Entry entry) {
      if (entry.isDirectory()) {
         return entry.getName().equals(BOOT_INF_CLASSES);
      }
      return entry.getName().startsWith(BOOT_INF_LIB);
   }

   public static void main(String[] args) throws Exception {
      new JarLauncher().launch(args);
   }

}
  • Archive.Entry:這個類對對象,代編jar包中的資源文件。

isNestedArchive方法判斷entry對象是不是位于jar包內(nèi),如果在jar內(nèi)部,返回true。如果不在jar包里面,也就是我們解壓了jar包,返回false。

重點看launch(String[])方法

    protected void launch(String[] args) throws Exception {
    // 1
        JarFile.registerUrlProtocolHandler();
    // 2
        ClassLoader classLoader = createClassLoader(getClassPathArchives());
    // 3
        launch(args, getMainClass(), classLoader);
    }

這個方法一共3步

  1. 擴展JAR協(xié)議
    1. JDK默認支持file、http、jar等協(xié)議,所以JDK內(nèi)部有默認的實現(xiàn),位于sun.net.www.protocol包下。
    2. JarFile.registerUrlProtocolHandler();這個方法將org.springframework.boot.loader包下對應(yīng)的JAR協(xié)議實現(xiàn),覆蓋原有的JAR實現(xiàn)。
    3. 因為原有的JAR實現(xiàn),ClassPath是我們自己配置環(huán)境變量的時候制定的,不是BOOT-INF/lib。
  2. 創(chuàng)建一個classloader,用于加載JarLauncher類,因為jar包可能會被解壓,解壓前和解壓后的的ClassLoader是不同的。
  3. 調(diào)用launch方法,將參數(shù)傳遞。
    1. args是我們自己指定的參數(shù)。
    2. getMainClass()是獲取MANIFEST.MF文件里面Statr-Class屬性,也就是獲取我們自定義主類的Class 文件地址。
    3. 傳遞推出的類加載器

launch方法

protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception {
   Thread.currentThread().setContextClassLoader(classLoader);
   createMainMethodRunner(mainClass, args, classLoader).run();
}

protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) {
   return new MainMethodRunner(mainClass, args);
}
public class MainMethodRunner {

   private final String mainClassName;

   private final String[] args;

   public MainMethodRunner(String mainClass, String[] args) {
      this.mainClassName = mainClass;
      this.args = (args != null) ? args.clone() : null;
   }

   public void run() throws Exception {
      Class mainClass = Thread.currentThread().getContextClassLoader().loadClass(this.mainClassName);
      Method mainMethod = mainClass.getDeclaredMethod("main", String[].class);
      mainMethod.invoke(null, new Object[] { this.args });
   }

}

launch方法分析:

  1. 將ClassLoader放入當(dāng)前線程里面的ClassLoader里面
  2. 創(chuàng)建MainMethodRunner對象,調(diào)用里面的run()方法。
    1. run()方法先獲取到之前設(shè)定的ClassLoader。
    2. 利用ClassLoader加載Start-Class之類的類,也就是我們自己的主類。
    3. 獲取主類里面的main方法,通過反射執(zhí)行。

總結(jié)

通過分析,我們可以看出,Spring Boot Loader在調(diào)用我們自己的主類之前,主要做了三件事

  1. 擴展JDK默認的支持JAR對應(yīng)的協(xié)議,因為Spring Boot啟動不僅僅需要JDK半身的JAR文件,還需要BOOT-INF/lib這個目錄下的文件。默認實現(xiàn)無法將BOOT-INF/lib這個目錄當(dāng)作ClassPath,故需要替換實現(xiàn)。
  2. 判斷當(dāng)前的介質(zhì),是java -jar啟動,還是java org.springframework.boot.loader.JarLauncher啟動。以便獲取對應(yīng)的ClassLoader。
  3. 獲取MANIFEST.MF文件中的Start-Class屬性,也就是我們自定義的主類。通過第二步獲取的ClassLoader加載獲取到Class文件,通過反射調(diào)用main方法,啟動應(yīng)用。

網(wǎng)站名稱:Spring-Boot啟動之前做了哪些事?
網(wǎng)頁網(wǎng)址:http://weahome.cn/article/ieshjh.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部