javascript
maven springboot 除去指定的jar包_SpringBoot的运行机制
SpringBoot打包機制
先看一眼spring-boot的maven插件打包后的target目錄:
其中有一個.jar.original的文件,一個.jar文件,其中.jar.original才是原始的jar包,而.jar文件是經過spring-boot的maven插件處理過后的jar,springboot的maven插件會將原始jar重命名成.jar.original,然后按springboot自己的規范打出一個可執行的jar包。
將該jar包重命名成.zip文件后打開即可看到文件中的內容:
可以看到,springboot執行的jar并不是一個java標準的jar,其中包含了springboot自身定義的內容。我們再打開其中的META-INF/MANIFEST.MF文件,看看其中指定的內容:
Main-Class是其中的啟動類,springboot打包出來的jar,啟動類并不是工程中包含main方法的啟動類,而是springboot自己的JarLauncher類,而工程中定義的啟動類在這里變成了Start-Class,由此也可以看出springboot應用在IDE里通過main方法運行與通過java -jar命令運行的區別。
SpringBoot應用的啟動
打開springboot的Main-Class JarLauncher類,其中包含main方法:
這是springboot啟動的入口,JarLauncher類繼承自ExecutableArchiveLauncher類,進入到launch方法可以看到springboot有一個archive的概念,archive是歸檔的意思,springboot打出來的jar包就是一個archive。
ExecutableArchiveLauncher類的createArchive方法可以看到啟動時的archive創建,通過當前類找到jar包的路徑,并創建JarFileArchive:
通過getNestedArchives方法可以看到Archive是一個遞歸的概念,JarFileArchive中可以有其它嵌套的Archive:
在launch方法中,有getClassPathArchives方法的調用,此方法中調用了前面的getNestedArchives方法,傳入的Filter是lambda表達式,通過isNestedArchive方法對JarFileArchive中的Entry做過濾:
可以得知,springboot打出的archive jar包中,ROOT-INF/classes/目錄被認為是一個嵌套的Archive,ROOT-INF/lib/下的每一個jar包也被認為是一個Archive
因為springboot的archive不是一個標準的jar包,java提供的ClassLoader無法加載到archive中的依賴以及class,springboot提供了新的classloader的實現用來做Archive中類的加載:
可以看到springboot使用的是LaunchedURLClassLoader這個ClassLoader做的類的加載。創建好類加載器后,需要調用Start-Class,即應用中的main方法:
MainMethodRunner.run方法非常簡單,邏輯是通過反射調用應用的main:
這一步之后,進入到了應用代碼中。
SpringBoot應用初始化
在使用spring boot時,我們在main方法中調用SpringApplication.run進行初始化:
在SpringApplication.run方法中做了Spring的初始化:
可以清晰的看到spring的初始化。創建ApplicationContext對象使用的是createApplicationContext方法,此方法實現如下:
對于非WEB應用,使用的ApplicationContext的實例是DEFAULT_CONTEXT_CLASS,此常用定義為AnnotationConfigApplicationContext類,在依賴注入中提到的這個類,此類用于實現注解配置的ApplicationContext。
回到啟動類,啟動類上加了一個@SpringBootApplication注解,此注解的定義:
前面Annotation的解析機制中提到,spring能通過解析@ComponentScan注解注冊bean,但是springboot中,@ComponentScan標識在SpringBootApplication注解上,AnnotationConfigApplicationContext是定義在spring-context包中的,而@SpringBootApplication是定義在spring-boot-autoconfig中的注解,spring-context包并不依賴于spring-boot-autoconfig包,AnnotationConfigApplicationContext能通過@SpringBootApplication注解完成初始化是因為spring的注解處理工具類能識別出@SpringBootApplication的元注解@ComponentScan以及@AliasFor注解標識 的屬性,實現邏輯在spring-core包中的AnnotationConfigUtils類中。
最后看看SpringApplication類的構造器:
在getSpringFactoriesInstances方法中,使用了SpringFactoriesLoader:
打開spring-boot相關的包,能看到spring.factories文件:
SpringFactoriesLoader是spring-core中提供的類,用于處理spring.factories文件,SpringFactoriesLoader.loadFactoryNames方法會讀取類路徑下的所有META-INF/spring.factories文件:
AutoConfiguration
回到@SpringBootApplication注解的定義:
其注解上被標記了@EnableAutoConfiguration注解,此注解用于實現autoconfiguration。打開此注解可以看到它實際上是使用了注解解析機制中的@Import注解:
如何使用ImportSelector就回到了@Import的處理邏輯中(見前面的文章)。可以看到,實現autoconfiguration的入口正是這個EnableAutoConfigurationImportSelector類,此類的selectImports方法返回的是需要作為配置類的類,這里的具體作用就是拿到類路徑下的所有的自動配置的類,其代碼實現:
AutoConfigurationMetadataLoader.loadMetadata方法的實現比較簡單
即從META-INF/spring-autoconfigure-metadata.properties文件中加載數據,此文件在classpath下可以有多個(每個jar包中都可以有一個),隨便打開一個配置文件,看看其中的內容:
里面都是一些配置類。@Import將這些配置類導入給spring的注解處理器ConfigurationClassParser就完成了bean的配置。
另外,在@SpringBootApplication注解上,還標記了一個@ComponentScan注解,其中的excludeFilters中有一個是AutoConfigurationExcludeFilter:
此類會判斷如果class標了@Configuration并且此類包含spring.factories文件中,則在處理@Configuration注解時排除此類:
上面的代碼中,getAutoConfigurations方法是從SpringFactoriesLoader中取的EnableAutoConfiguration關聯的類。
總結
以上是生活随笔為你收集整理的maven springboot 除去指定的jar包_SpringBoot的运行机制的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 特斯拉提不了车 退订不了订金!车主无奈
- 下一篇: 国内玩家最期待的来了!《微软飞行模拟》官