최근에 회사의 Open API 플랫폼을 최적화 할 시간이 있습니다. JAR 패키지를 입력 할 때, 나는 Spring Boot를 사용하는 데 매우 능숙하다는 것을 갑자기 깨달았지만 Spring Boot에서 생성 된 Jar의 시작 원리를 결코 알지 못했습니다. 그런 다음 이번에는 항아리를 풀고 그것을 보았다. 내가 상상했던 것과 실제로 달랐습니다. 다음은 압축 된 항아리에 대한 완전한 분석입니다.
Spring Boot의 응용 프로그램은 게시되지 않았습니다. 더 간단한 데모의 구조는 비슷합니다. 또한 내가 사용한 Spring Boot 버전은 1.4.1입니다. 인터넷에는 Spring Boot Jar의 시작을 분석하기위한 또 다른 기사가 있습니다. 이는 1.4 미만이어야하며 시작 방법은 현재 버전과 매우 다릅니다.
MVN Clean 설치 후 대상 디렉토리를 살펴보면 다음과 같이 두 개의 JAR 패키지가 있습니다.
xxxx.jarxxx.jar.original
이는 스프링 부트 플러그인 메커니즘으로 인해 일반적인 JAR을 실행 가능한 JAR 패키지로 바꾸고 XXX.Jar.Original은 Maven에서 생성 한 JAR 패키지입니다. 이들은 다음과 같이 공식 Spring 웹 사이트의 기사를 참조하여 찾을 수 있습니다.
http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#executable-jar
다음은 Spring Boot 응용 프로그램에 의해 생성 된 JAR의 디렉토리 구조의 일부이며, 대부분은 생략되며 중요한 부분 만 표시됩니다.
.├── BOOT-INF│ ├── classes│ ├── application-dev.properties│ │ ├── application-prod.properties│ │ ├── application.properties│ │ │ │ └── com│ │ │ │ └── weibangong│ │ │ └── open│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └── open│ │ │ │ │ │ │ │ └── SwaggerConfig.class│ │ │ │ │ │ │ └── SwaggerConfig.class│ │ │ │ │ │ │ └── SwaggerConfig.class│ SwaggerConfig.class │ │ │ │ │ │ │ ├ ├ 담사 SwaggerConfig. Oauth2│ │ │ │ │ ├ ├ ├ ├ ├ ├ ├ ├ ├ ├ ├ ├ │ │ │ │ │├ │ │ │ │ │ ├ ├ 접어 액세스 TokenController.class │ │ ├ ├ ├ ├ ├ ├ 사장 동안 │ │ └ └ └ ├ 착용 ├ 테. └── guru.css│ │ ├── images│ │ ├── FBcover1200x628.png│ │ └── NewBannerBOOTS_2.png│ └── lib│ ├── accessors-smart-1.1.jar├── META-INF│ ├── MANIFEST.MF│ └── maven│ └── com.weibangong.open│open│ └ └얼은 Open-Server-Openapi│ ├ ├ ├ 바인 · ─ Pom.Properties │ └ └ └ 커프 └ ─ POM.XMLATINTAMLINTING │ 신 동안 ORG └ 커트 └ └ └퀴 └ ─캠 └ 착용 └ 착 EXECUTIVEVELAUNCHER $ 1.CARCIVEREACTHER $ 1. CANTRASS ├ 익전 타 런서. DelakeDurlclassloader $ 1. Class ├ ── 런치 러어 클래스 로더. 클래스 ├ ├ ├ ├ ├ ├ ├얼. # Xlass.class ├ ├ ├ ├ ├ 경우 archive $ entry.class.class.class.class.class.class.class.class.class.class │ ├ ├들은 아카이브 .class.class.class $ 1. Class Anclass anclass. thevernathive. ExplodedArchive $ FileEntryiterator $ EntictComparator.class ├ ├ ├ 커스티브 $ FileEntryiterator.class
응용 프로그램에 쓴 수업 외에도이 항아리에는 별도의 조직 패키지가 있습니다. Spring Boot 응용 프로그램은 Spring Boot 플러그인을 사용 하여이 패키지를 입력해야합니다.이 패키지는 MVN 수명주기의 패키지 단계를 향상시키는 것입니다. 스타트 업 프로세스에서 중요한 역할을하는 것은이 패키지입니다. 또한 응용 프로그램에 필요한 다양한 종속성이 JAR에 입력되고 추가 스프링 부팅 패키지가 입력됩니다. 올인원을 할 수있는이 항아리는 Fat.jar라고도합니다. 여기서 우리는 항상 Fat.jar를 사용하여 항아리의 이름을 교체합니다.
현재 Meta-Inf의 Manifest.mf 파일을 계속 살펴볼 것입니다.
매니페스트-버전 : 1.0 구조 타이틀 : Open :: Server :: OpenApiimplementation-Version : 1.0-SnapShotarchiver-Version : Plexus ArchiverBuilt-BY : XIAXUANIMPLEMENTATION-VENDOR-ID : COM.WEIBANG-PRING-BOOT-VERSION : 1.4.1. PIVOTIMPLEMPORMEMETION-rETAMEMPLEMPTEREMEMETION- Inc.main 클래스 : org.springframework.boot.loader.propertieslauncherstart-class : com.weibangong.open.openapi.springbootwebapplicationspring-boot classes : boot-inf/classes/spring-boot-lib : boot-inf/lib/create-by : apache maven 3.3.9build-jdk : 1.8.0_20implementation-url : http://maven.apache.org/open-server-openapi
여기에 지정된 메인 클래스는 시작 프로그램 대신 별도로 입력 한 패키지의 클래스 파일이며, Manifest.MF 파일에는 응용 프로그램의 시작 프로그램을 지정하는 별도의 시작 클래스가 있습니다.
먼저 클래스 org.springframework.boot.loader.propertieslauncher를 찾습니다. 여기서 주요 메소드는 다음과 같습니다.
public static void main (String [] args)은 예외 {propertiesLauncher 런치어 = 새로운 PropertiesLauncher (); args = runcher.getargs (args); Launcher.launch (Args);}시작 방법을 확인하십시오. 이 방법은 부모 클래스 런처에서 찾을 수 있으며 부모 클래스 런칭 방법은 다음과 같습니다.
Protected Void Launch (String [] Args, String MainClass, ClassLoader ClassLoader) Exception {Thread.CurrentThread (). SetContextClassLoader (ClassLoader); this.createmainmethodrunner (Mainclass, Args, ClassLoader) .run (); } 보호 된 MainMethodrunner CreateMainMethodrunner (String Mainclass, String [] Args, ClassLoader ClassLoader) {Return New MainMethodrunner (Mainclass, Args); }런치 방법은 마침내 CreateMainMethodrunner 메소드를 호출하여 MainMethodrunner 객체를 인스턴스화하고 실행 메소드를 실행합니다. 다음과 같이 MainMethodrunner 소스 코드로 이동합니다.
패키지 org.springframework.boot.loader; import java.lang.reflect.method; public class mainmethodrunner {private final String mainclassname; 개인 최종 문자열 [] args; public mainmethodrunner (String mainclass, String [] args) {this.mainclassname = mainclass; this.args = args == null? null : (string []) args.clone (); } public void run ()은 예외를 던져 {class mainclass = thread.currentThread (). getContextClassLoader (). loadClass (this.MainClassName); 메소드 mainmethod = mainclass.getDeclaredMethod ( "main", new Class [] {String []. class}); mainmethod.invoke ((객체) null, new Object [] {this.args}); }}실행 방법을 확인하면 Spring Boot Jar를 실행하는 것이 매우 쉽고 분석은 기본적으로 끝납니다.
5. 주요 프로그램의 시작 과정
JAR의 시작 과정에 대해 이야기 한 후 Spring Boot 응용 프로그램에서 기본 프로그램의 시작 및로드 프로세스에 대해 이야기 해 봅시다. 먼저 Spring Boot 응용 프로그램의 주요 방법을 살펴 보겠습니다.
패키지 cn.com.devh; import org.springframework.boot.springApplication; import org.springframework.boot.autoconfigure.springbootapplication; import org.springframework.cloud.client.client.client.enablediscoveryclient; org.springframework.cloud.netflix.eureka.enableeurekaclient; import org.springframework.cloud.netflix.neableflix.enablefeignclients;/*** 17/8/25에 생성 된. */@springbootApplication@enableFeignClients@enableEureKaclientPublic Class A1ServiceApplication {public static void main (String [] args) {springApplication.run (a1serviceApplication.class, args); }}다음과 같이 SpringApplication의 실행 방법으로 이동하십시오.
/** * 기본 설정을 사용하여 * 지정된 소스에서 {@link springApplication}을 실행하는 데 사용할 수있는 정적 헬퍼. * @param 소스로드 * @Param Args 응용 프로그램 인수 (일반적으로 Java Main Method에서 전달됨) * @return running {@link applicationcontext} */ public static configurablePplicationContext run (Object Source, String ... args) {return run (new Object [] {source}, args); } /** * 기본 설정 및 사용자 제공 인수를 사용하여 * 지정된 소스에서 {@Link SpringApplication}을 실행하는 데 사용할 수있는 정적 헬퍼. * @param은로드 할 소스를 소스 * @param args 응용 프로그램 인수 (일반적으로 Java Main Method에서 전달) * @return running {@link applicationcontext} */ public static configurablePplicationContext run (Object [] 소스 [] args) {return new springApplication (args). }여기서 SpringApplication의 인스턴스화가 핵심입니다. 우리는 SpringApplication 생성자로갑니다.
/*** 새 {@link springApplication} 인스턴스를 만듭니다. 응용 프로그램 컨텍스트는 지정된 소스에서 * Bean을로드합니다 (자세한 내용은 {@link springApplication 클래스 레벨} * 문서 참조. {초기화 (소스); ApplicationTinitializer.class);여기에서 초기화 메소드에서 WebenVironment ()는 다음과 같이 웹 애플리케이션 또는 일반 항아리로 시작되었는지 여부를 결정합니다.
Private Boolean PrassweBenvironment () {for (String ClassName : web_environment_classes) {if (! classutils.ispresent (className, null)) {return false; }} true를 반환합니다. }web_environment_classes는 다음과 같습니다.
개인 정적 최종 문자열 [] web_environment_classes = { "javax.servlet.servlet", "org.springframework.web.context.configurablewebapplicationContext"};그들 중 어느 것도 존재하지 않는 한, 현재 응용 프로그램은 일반적인 항아리 형태로 시작됩니다.
그런 다음 setinitializers 메소드는 모든 ApplicationContextInitializers를 초기화합니다.
/** * 스프링 * {@link applicationcontext}에 적용될 {@link applicationcontextinitializer}를 설정합니다. * @param 이니셜 라이저 */ public void setInitializers를 설정하는 이니셜 라이저 (collection <? accuply <? 확장 applicationContexTinitializer <? >> 이니셜 라이저) {this.initializers = new arrayList <ApplicationContextInitializer <?> (); this.initializers.addall (이니셜 라이저); } setListEners ((Collection) GetSpringFactorioryInstances (ApplicationListener.class)) **이 단계는 모든 청취자를 초기화합니다.
이전 SpringApplication (소스) .RUN (Args)으로 돌아 갑시다. 실행 메소드를 입력하면 코드는 다음과 같습니다.
/** * 새 * {@Link ApplicationContext}를 생성하고 새로 고침하여 스프링 애플리케이션을 실행합니다. * @Param Args 응용 프로그램 인수 (일반적으로 Java Main Method에서 전달됨) * @return running {@link applicationcontext} */ public configurableApplicationContext run (string ... args) {STOPWATCH STOPWATCH = NEW STOPWATCH (); stopwatch.start (); configurableApplicationContext context = null; configureHeadsHeadsProperty (); SpringApplicationRunListeners 리스너 = getRunListEners (Args); 청취자 .started (); {ApplicationArguments ApplicationArguments = new DefaultApplicationArguments (Args); Context = CreateEndrefreshContext (리스너, 응용 프로그램); AfterRefresh (컨텍스트, 응용 프로그램); 청취자. 피니쉬 (컨텍스트, NULL); stopwatch.stop (); if (this.logstartupinfo) {new startUpInfologger (this.MainApplicationClass) .LogStarted (getApplicationLog (), stopwatch); } 반환 컨텍스트; } catch (Throwable ex) {handlerunfailure (컨텍스트, 리스너, 예); 새로운 불법 상태를 던지십시오 (예); }}이 단계는 컨텍스트 생성을 수행합니다.
private configurableApplicationContext createEndrefreshContext (springApplicationRunListeners 리스너, 응용 프로그램 응용 프로그램) {configurableApplicationContext 컨텍스트; // 환경 작성 및 구성 구성 구성 가능 환경 = GetorCreateEnvironment (); ConfigureEnvironment (환경, ApplicationArguments.getSourceargs ()); 청취자. Environmentprepared (환경); if (iswebenvironment (환경) &&! this.webenvironment) {환경 = ConvertToStandardEnvironment (환경); } if (this.bannerMode! = Banner.Mode.Off) {printbanner (환경); } // ApplicationContext Context를 작성,로드, 새로 고침 및 실행합니다. Context.SetEnvironment (환경); postprocessApplicationContext (컨텍스트); Applicinitializers (컨텍스트); 청취자 .contextprepared (컨텍스트); if (this.logstartupinfo) {logstartupinfo (context.getParent () == null); logstartupprofileinfo (컨텍스트); } // 부팅 특정 Singleton Beans Context.getBeanFactory (). RegisterSingleton ( "SpringApplicationArguments", ApplicationArguments); // 소스를로드 <object> sources = getSources (); assert.notempty (출처, "출처는 비어 있지 않아야한다"); 로드 (컨텍스트, 소스 .ToArray (새 개체 [sources.size ())); 청취자 .contextloaded (컨텍스트); // 컨텍스트 새로 고침 (컨텍스트)을 새로 고칩니다. if (this.registershutdownhook) {try {context.registershutdownHook (); } catch (AccessControleXception EX) {// 일부 환경에서는 허용되지 않습니다. }} 반환 컨텍스트; } // 환경 작성 및 구성 구성 가능 구성 환경 = GetorCreateEnvironment (); ConfigureEnvironment (환경, ApplicationArguments.getSourceargs ());이 단계는 환경의 구성 및로드를 수행합니다.
if (this.bannermode! = banner.mode.off) {printbanner (환경); }이 단계는 스프링 부트 로고를 인쇄합니다. 변경 해야하는 경우 Banner.txt 및 Banner.txt를 자원 파일에 추가하여 필요한 패턴으로 변경하십시오.
// ApplicationContext Context를 작성,로드, 새로 고침 및 실행합니다. CreateApplicationContext (); return (configurableApplicationContext) Beanutils.instantiate (ContextClass)
제작 컨텍스트에는 실제로 컨테이너가 생성되고 EmbeddedServletContainerFactory의 생성, Jetty 또는 Tomcat을 선택하는지 여부를 포함하여 응답 클래스를 인스턴스화하는 것이 실제로 포함되어 있으므로 다음에 이야기하겠습니다.
if (this.registershutdownhook) {try {context.registershutdownHook (); } catch (AccessControleXception EX) {// 일부 환경에서는 허용되지 않습니다. }}이 단계는 현재 컨텍스트를 등록하고 킬 명령이 수신되면 컨테이너를 파괴하는 것입니다.
기본적으로 시작 분석은 끝났지 만 여전히 시간이 많이 걸리는 세부 사항이 여전히 있습니다. 이것은 후속 블로그 게시물에서 논의 될 것이며 오늘은 모두입니다.
요약하면, Spring Boot Jar의 시작 프로세스는 기본적으로 다음 단계입니다.
1. Maven을 정상적으로 포장하면 Spring Boot 플러그인이 Maven 수명주기를 확장하고 Spring Boot 관련 패키지를 JAR에 전달합니다. 이 JAR에는 응용 프로그램에서 생성 된 항아리 외에 Spring Boot Startup 프로그램과 관련된 클래스 파일이 포함되어 있습니다.
2. 나는 전에 약간 낮은 버전의 Spring Boot Jar의 시작 과정을 보았습니다. 당시 현재 스레드는 메인 프로그램을 실행하기위한 새로운 스레드를 가지고 있으며, 이제 메인 프로그램을 시작하기 위해 직접 반사를 사용하도록 변경되었습니다.
요약
위는 편집자가 소개 한 Spring Boot Jar의 원리 분석입니다. 나는 그것이 당신에게 도움이되기를 바랍니다. 궁금한 점이 있으면 메시지를 남겨 주시면 편집자가 제 시간에 답장을 드리겠습니다. Wulin.com 웹 사이트를 지원해 주셔서 대단히 감사합니다!