>  기사  >  Java  >  SpringBoot 애플리케이션의 시작 항목을 캡슐화하는 방법

SpringBoot 애플리케이션의 시작 항목을 캡슐화하는 방법

WBOY
WBOY앞으로
2023-05-13 10:28:211459검색

SpringBoot 애플리케이션의 시작 항목을 캡슐화하는 방법

Springboot는 Java 프로그래머에게 필수적인 기술이라고 할 수 있습니다. Springboot는 결국 maven을 통해 jar 패키지로 패키징된 후 java -jar 명령을 직접 사용하여 실행할 수 있다는 것은 누구나 알고 있습니다. 웹 프로젝트(또는 기타). 이는 원래 Tomcat 기반 웹 프로젝트의 복잡한 작업을 방지합니다. Springboot는 Jetty(또는 Tomcat) 서버가 내장되어 있기 때문에 웹 서비스 배포를 매우 간단하게 만들 수 있으며, 웹 서비스를 성공적으로 실행하기 위해 컨테이너 시작 프로세스 중에 서버를 시작합니다. java -jar命令运行一个Web工程(或其它)。这样就避免了原先基于tomcat的web工程的复杂操作。Springboot能够使Web服务的部署简单到如此程度是因为其内置了Jetty(或Tomcat)服务器,并且在容器启动过程中start该服务器,成功运行Web服务。

相信各位Springbooter一定不会陌生下面的代码,无论是初学Springboot的新同学,或是开始研究Springboot源码的新司机,这段代码几乎是我们的落脚点。我们如此熟悉它,以至于认为它就是Springboot这个魔法乐园的起点。但真的是这样吗?

 @SpringBootApplication
 public class Springboot01helloworldApplication {
     public static void main(String[] args) {
         SpringApplication.run(Springboot01helloworldApplication.class, args);
     }
 }

我们都知道,一个Java工程打包过后,这个jar包的入口描述被写在了/META-INF/MANIFEST.MF文件下,下面让我们来看看这个文件内容:

 Manifest-Version: 1.0
 Archiver-Version: Plexus Archiver
 Built-By: MrXu
 Start-Class: com.vivo.internet.nex.repeater.console.RepeaterConsoleApplication
 Spring-Boot-Classes: BOOT-INF/classes/
 Spring-Boot-Lib: BOOT-INF/lib/
 Spring-Boot-Version: 1.5.19.RELEASE
 Created-By: Apache Maven 3.8.1
 Build-Jdk: 1.8.0_281
 Main-Class: org.springframework.boot.loader.JarLauncher

文件入口的描述为Main-Class对应的value,即org.springframework.boot.loader.JarLauncher。那么,接下来我们需要看下这个类究竟做了什么?

 // JarLauncher.java
 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() {
     }
     // ...省略无关代码
     public static void main(String[] args) throws Exception {
         (new JarLauncher()).launch(args);
     }
 }

明显的main函数吸引了我们的注意,没错了,这就是入口,看看JarLauncher的空构造并没有任何代码,我们先往它的父类找找:

 // ExecutableArchiveLauncher.java
 public abstract class ExecutableArchiveLauncher extends Launcher {
     public ExecutableArchiveLauncher() {
         try {
             this.archive = this.createArchive();
         } catch (Exception var2) {
             throw new IllegalStateException(var2);
         }
     }
     // ...省略
 }
 
 // Launcher.java
 public abstract class Launcher {
     public Launcher() {}
     // ...省略无关代码
 }

从代码中可以看出,真正干了事情的父类是ExecutableArchiveLauncher,它在初始化时构造了archive实例,该实例封装了/META-INF/MANIFEST.MF文件的信息。后面我们也会用到它。

随后便是launch方法,我们只关系核心执行流程:

 // Launcher.java
 protected void launch(String[] args) throws Exception {
     JarFile.registerUrlProtocolHandler();
     ClassLoader classLoader = this.createClassLoader(this.getClassPathArchives());
     this.launch(args, this.getMainClass(), classLoader);
 }
 // ExecutableArchiveLauncher.java
 protected String getMainClass() throws Exception {
     Manifest manifest = this.archive.getManifest();
     String mainClass = null;
     if (manifest != null) {
         mainClass = manifest.getMainAttributes().getValue("Start-Class");
     }
 
     if (mainClass == null) {
         throw new IllegalStateException("No 'Start-Class' manifest entry specified in " + this);
     } else {
         return mainClass;
     }
 }

这里首先调用子类ExecutableArchiveLauncher的getMainClass方法,主要逻辑就是从/META-INF/MANIFEST.MF文件中获取Start-Class信息,对应上文就是com.vivo.internet.nex.repeater.console.RepeaterConsoleApplication

모든 Springboot 사용자는 다음 코드에 익숙할 것이라고 믿습니다. Springboot를 배우는 신입생이든 Springboot 소스 코드를 공부하기 시작하는 새로운 드라이버이든 이 코드는 거의 우리의 출발점입니다. 우리는 그것이 스프링부트라는 마법의 천국의 시작점이라고 생각할 정도로 친숙하다. 하지만 정말 그렇습니까?

 // Launcher.java
 protected void launch(String[] args, String mainClass, ClassLoader classLoader) throws Exception {
     Thread.currentThread().setContextClassLoader(classLoader);
     // 这里首先调用createMainMethodRunner创建一个MainMethodRunner实例,将mainClass和args参数传入。随后调用
     this.createMainMethodRunner(mainClass, args, classLoader).run();
 }
 protected MainMethodRunner createMainMethodRunner(String mainClass, String[] args, ClassLoader classLoader) {
     return new MainMethodRunner(mainClass, args);
 }
 
 // MainMethodRunner.java
 public MainMethodRunner(String mainClass, String[] args) {
     this.mainClassName = mainClass;
     this.args = args != null ? (String[])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((Object)null, this.args);
 }

우리 모두는 Java 프로젝트가 패키징된 후 /META-INF/MANIFEST.MF 파일 아래에 jar 패키지의 항목 설명이 작성된다는 것을 알고 있습니다. :🎜rrreee🎜파일 항목 설명은 Main-Class에 해당하는 값인 org.springframework.boot.loader.JarLauncher입니다. 그럼 다음으로 이 클래스가 정확히 무엇을 하는지 살펴보겠습니다. 🎜rrreee🎜주목할 만한 주요 기능이 눈길을 끕니다. 네, JarLauncher의 빈 구조를 보세요. 먼저 상위 클래스를 찾아보겠습니다. 🎜rrreee🎜코드를 보면 알 수 있습니다. 실제로 작업을 수행하는 상위 클래스는 ExecutableArchiveLauncher입니다. 이는 초기화 중에 /META-INF/MANIFEST.MF 파일의 정보를 캡슐화하는 아카이브 인스턴스를 구성합니다. . 나중에도 사용하겠습니다. 🎜🎜다음으로 실행 메소드가 있습니다. 🎜rrreee🎜여기에서는 먼저 하위 클래스 ExecutableArchiveLauncher의 getMainClass 메소드를 호출합니다. 주요 로직은 /META-INF/MANIFEST에서 가져오는 것입니다. .MF 파일 Start-Class 정보는 위의 com.vivo.internet.nex.repeater.console.RepeaterConsoleApplication 문자열에 해당하며, 이는 우리가 작성한 시작 클래스와 연결되어 있습니다. 🎜🎜그런 다음 실행 메서드의 특정 실행이 발생합니다. launch()는 먼저 MainMethodRunner를 생성하고 위에서 얻은 Start-Class 및 투명 매개 변수를 전달한 다음 MainMethodRunner의 실행 메서드를 호출합니다. run 메소드의 실행도 매우 간단합니다. 즉, Start-Class에 해당하는 시작 클래스를 로드한 다음 시작 클래스의 기본 메소드를 반사적으로 호출하는 것입니다. 그 다음에는 컨테이너 초기화 프로세스가 진행됩니다. 🎜아아아아

위 내용은 SpringBoot 애플리케이션의 시작 항목을 캡슐화하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제