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
// 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); }
/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 중국어 웹사이트의 기타 관련 기사를 참조하세요!