머리말
Spring Boot 자체의 시작 원칙 분석은 다음을 참조하십시오. http://www.vevb.com/article/141478.htm
Spring Boot의 클래스 로더 상속 관계는 아래에 제공된 데모를 실행하여 다른 시나리오에서 실행할 수 있습니다. 다양한 시나리오에서 Spring Boot 응용 프로그램의 클래스 로더 상속 관계를 알 수 있습니다.
https://github.com/hengyunabc/spring-boot-inside/tree/master/democlassloader-context
세 가지 상황이 있습니다.
IDE에서 실행 메인 함수는 직접 실행됩니다. 클래스 로더의 URL에는 모든 항아리와 자체 대상/클래스가 포함되어 있습니다
========= 스프링 부팅 애플리케이션 클래스 로더 URLS =============
클래스 로더 URL : Sun.Misc.launcher$ aptclassLoader@2A139A55
파일 :/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/classes/
파일 : /users/hengyunabc/.m2/repository/org/springframework/cloud/spring-cloud-starter/1.9.9.release/spring-cloud-starter-1.9.9.release.jar
파일 : /users/hengyunabc/.m2/repository/org/springframework/spring-boot-starter/1.4.7.release/spring-boot-starter-1.4.7.release.jar
...
뚱뚱한 병으로 달리십시오
MVN Clean PackageJava -Jar 대상/데모 클래스 로더-컨텍스트 -0.1-snapshot.jar
응용 프로그램의 기본 기능을 실행하는 클래스 로더는 LaunchedUrlClassLoader이며 부모는 SystemClassLoader입니다.
========== 클래스 로더 트리 ==============
org.springframework.boot.loader.launchedurlclassloader@1218025c
-un.misc.launcher$appclassloader@6bc7c054
-un.misc.launcher$extclassloader@85ede7b
그리고 LaunchedURLClassLoader的urls fat jar BOOT-INF/classes!/ Directory이며 Boot-Inf/Lib의 모든 항아리입니다.
========= 스프링 부팅 애플리케이션 클래스 로더 URLS =============
클래스 로더 URL : org.springframework.boot.loader.launchedurlclassloader@1218025c
JAR : 파일 : /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/democlassloader-context-0.0.1-snapshot.jar!/boot-inf/classs!/
jar : /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/democlassloader-context-0.0.1-snapshot.jar!
jar : /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/democlassloader-context-0.0.1-snapshot.jar!
...
SystemClassLoader 의 URL은 demo-classloader-context-0.0.1-SNAPSHOT.jar 자체입니다.
========== 시스템 클래스 로더 URLS ==============
클래스 로더 URL : Sun.misc.launcher$ aptclassloader@6bc7c054
파일 : /users/hengyunabc/code/java/spring-boot-inside/democlassloader-context/target/democlassloader-context-0.0.1-snapshot.jar
압축 압축 디렉토리로 실행하십시오
MVN Clean PackageCD TargetUnzip Demo-Classloader-Context-0.0.1-SnapShot.jar -D Democd Demojava org.springframework.boot.loader.propertieslauncher
응용 프로그램의 기본 기능을 실행하는 클래스 로더는 LaunchedURLClassLoader 이며 부모는 SystemClassLoader 입니다.
========== 클래스 로더 트리 ==============
org.springframework.boot.loader.launchedurlclassloader@4aa298b7
-un.misc.launcher$ AppClassLoader@2A139A55
-un.misc.launcher$extclassloader@1b6d3586
LaunchedURLClassLoader 의 URL은 감압 디렉토리의 BOOT-INF/classes/ 및 /BOOT-INF/lib/ 아래의 JAR 패키지입니다.
========= 스프링 부팅 애플리케이션 클래스 로더 URLS =============
클래스 로더 URL : org.springframework.boot.loader.launchedurlclassloader@4aa298b7
파일 :/users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inf/classes/
JAR : 파일 : /users/hengyunabc/code/java/spring-boot-inside/democlassloader-context/target/demo/boot-inf/lib/bcpkix-jdk15on-1.55.jar!/
JAR : 파일 : /users/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/boot-inf/lib/bcprov-jdk15on-1.55.jar!/
JAR : 파일 : /users/hengyunabc/code/java/spring-boot-inside/democlassloader-context/target/demo/boot-inf/lib/classmate-1.3.3.jar!/
SystemClassLoader 의 URL에는 현재 디렉토리 만 있습니다.
========== 시스템 클래스 로더 URLS ==============
클래스 로더 URL : Sun.Misc.launcher$ aptclassLoader@2A139A55
파일 :/사용자/hengyunabc/code/java/spring-boot-inside/demo-classloader-context/target/demo/
실제로, 실행하는 다른 두 가지 방법이 있습니다 : mvn spring-boot:run 및 mvn spring-boot:run -Dfork=true 이지만 거의 사용되지 않으며 별도로 논의되지 않습니다. 관심이 있다고 생각되면 혼자서 쓰러 질 수 있습니다.
스프링 부팅에서 클래스 로더의 상속 관계 요약
IDE에서 기본 기능이 실행되면 클래스 로더가 하나 뿐인 SystemClassLoader 만 있습니다.
Fat Jar로 달리면 SystemClassloader가있는 출시 러어 클래스 로더가 있습니다.
LaunchedUrlClassLoader의 URL은 Boot-Inf/Classes의 항아리이며 Fat Jars의 Boot-Inf/lib입니다. SystemClassLoader의 URL은 뚱뚱한 병 자체입니다.
압축이없는 디렉토리를 실행하면 Fat Jar와 유사하지만 URL은 디렉토리 형태입니다. 디렉토리 형식은 더 나은 호환성을 갖습니다.
스프링 부트 버전 1.3. 그리고 1.4.
스프링 부츠 1.3.* 버전
스프링 부트 로더 클래스는 뚱뚱한 항아리에 배치됩니다.
Spring Boot 1.4의 포장 구조 변경은이 커밋에 의해 도입되었습니다.
https://github.com/spring-projects/spring-boot/commit/87fe0b2adeef85c842c009bfeebac1c84af8a5d7
이 커밋의 원래 의도는 클래스 로더의 상속 관계를 단순화하고, 직관적 인 부모 우선 방식으로 런치 디어 클래스 로더를 구현하는 것입니다. 동시에 포장 구조는 전통적인 전쟁 패키지 응용 프로그램에 더 가깝습니다.
그러나이 변화는 많은 복잡한 문제를 일으켰습니다. 위에서 우리는 클래스 로더 상속 관계를 약간 어지러워서 분석했습니다.
현재 클래스 로더 상속 관계의 일부 영향
일부 코드는 IDE에서 잘 실행되지만 실제로 배포 될 때는 작동하지 않는다는 많은 사용자가 있습니다. 여러 번 클래스 로더의 구조로 인해 발생합니다. 몇 가지 경우가 있습니다.
demo.jar!/boot-inf/classs!/이 방법은 URL이 작동하지 않습니다
Spring Boot가 표준 JAR 프로토콜을 확장하여 JAR의 다층 JAR 및 JAR의 디렉토리를 지원할 수 있습니다. Spring Boot 응용 프로그램 시작 원리 분석을 참조하십시오.
Spring Boot 1.3에는 Jar에 Jar가 있지만 Tomcat8 자체가 Jar의 Jar를 지원하는 것과 같이 비교적 강력한 코드는 이러한 상황을 처리 할 수 있습니다.
그러나 대부분의 코드는 demo.jar!/BOOT-INF/classes!/ 와 같은 여러 URL을 지원하지 않으므로 Spring Boot1.4에서는 많은 라이브러리 코드가 유효하지 않습니다.
Demo.jar!/Meta-Inf/Resources의 리소스 문제
Servlet 3.0 사양에서 응용 프로그램은 정적 자원을 메타 INF/리소스 아래에 배치 할 수 있으며 서블릿 컨테이너는 읽기를 지원합니다. 그러나 위의 상속 결과에서 우리는 문제를 찾을 수 있습니다.
이것은 이상한 현상을 만듭니다.
또한 Spring Boot의 공식 JSSP 예제는 포장 형식의 전쟁을 지원하며 Fat Jar를 지원하지 않습니다.
getResource ( "") 및 getResources ( "")의 반환 값에 관한 문제
getResource ( "")의 의미는 클래스 로더 URL의 첫 번째 URL을 반환하는 것입니다. 여러 번 사용자는 이것이 자체 클래스 디렉토리 또는 Jar URL이라고 생각합니다.
그러나 실제로 클래스 로더가 URL 목록을로드하기 때문에 무작위이며 OS의 저수준 구현과 관련이 있으며 URL의 순서가 동일하다는 것을 보장 할 수는 없습니다. 따라서 GetResource ( "")가 반환 한 결과는 종종 다릅니다.
그러나 많은 라이브러리 나 응용 프로그램은이 코드에 의존하여 스캔 리소스를 찾아 스프링 부팅하에 작동하지 않도록합니다.
또한 Spring Boot가 세 가지 다른 형태로 실행되며 GetResources ( "")가 반환 한 결과도 다릅니다. 사용자는 데모의 코드를 스스로 변경하고 결과를 인쇄 할 수 있습니다.
요컨대,이 두 API에 의존하지 말고 직접 찾을 수있는 리소스를 배치하는 것이 가장 좋습니다. 또는 스프링 자체가 제공하는 리소스 스캔 메커니즘을 직접 사용하십시오.
ClassPath*와 유사한 와일드 분류 문제*: **-service.xml
사용자는 여러 코드 모듈이 있으며 여러 *-service.xml 스프링 구성 파일은 다른 모듈 아래에 배치됩니다.
사용자가 ClassPath*: **-service.xml과 같은 와일드 카드를 사용하여 리소스를로드하면 IDE에서 실행할 때 올바르게로드 할 수 있지만 Fat Jar에서로드 할 수는 없습니다.
Spring의 자체 문서에서 관련 분석을 볼 수 있습니다.
https://docs.spring.io/spring/docs/4.3.9.release/javadoc-api/org/springframework/core/io/support/pathmatchingresourcepatternresolver.html
경고 : "ClassPath :"개미 스타일 패턴과 결합 된 경우 실제 대상 파일이 파일 시스템에 존재하지 않는 한 패턴이 시작되기 전에 하나 이상의 루트 디렉토리 와만 안정적으로 작동합니다. 즉, "classPath :*. XML"과 같은 패턴은 JAR 파일의 루트에서 파일을 검색하는 것이 아니라 확장 된 디렉토리의 루트에서만 검색됩니다. 이는 JDK의 classloader.getResources () 메소드의 제한에서 비롯됩니다.이 메소드는 전달 된 빈 문자열에 대한 파일 시스템 위치 만 반환합니다 (검색 할 수있는 루트를 나타냅니다). 이 ResourcePatternResolver 구현은 UrlClassLoader 소개 및 "java.class.path"매니페스트 평가를 통해 JAR 루트 조회 제한을 완화하려고합니다. 그러나 이식성이없는 보장.
즉, ClassPath*를 사용하여 다른 JAR 패키지와 일치 할 때는 디렉토리 레이어가 있어야합니다. 그렇지 않으면 일치하지 않습니다. 클래스 로더.getResources () 함수에 의해 발생합니다.
IDE에서 실행할 때 응용 프로그램이 의존하는 다른 모듈은 일반적으로 클래스 디렉토리이므로 일반적으로 문제가 없습니다.
그러나 Fat Jar와 함께 달리면 다른 모듈은 항아리로 포장되어 Boot-Inf/lib 아래에 배치되므로 현재 야생 분포가 실패합니다.
요약
위는이 기사의 모든 내용입니다. 모든 사람의 학습에 도움이되기를 바랍니다. 모든 사람이 wulin.com을 더 지원하기를 바랍니다.