คำนำ
บทความนี้วิเคราะห์หลักการทำงานของ Spring Boot 1.3 สปริงบูต 1.4. หลังจากนั้นโครงสร้างบรรจุภัณฑ์ก็พบว่ามีการเปลี่ยนแปลงและมีการเพิ่มไดเรกทอรี boot-Inf แต่หลักการพื้นฐานยังคงไม่เปลี่ยนแปลง
สำหรับการเปลี่ยนแปลงใน classloader ใน Spring Boot 1.4.*โปรดดูที่: http://www.vevb.com/article/141479.htm
สปริงบูตเริ่มต้นอย่างรวดเร็ว
ใน Spring Boot คุณสมบัติที่น่าสนใจมากคือแอปพลิเคชันสามารถบรรจุลงในขวด/สงครามได้โดยตรงจากนั้น Jar/War นี้สามารถเริ่มต้นได้โดยตรงโดยไม่ต้องกำหนดค่าเว็บเซิร์ฟเวอร์อื่น
หากคุณไม่เคยใช้สปริงบูตมาก่อนคุณสามารถสัมผัสได้ผ่านการสาธิตด้านล่าง
นี่คือโครงการเป็นตัวอย่างในการสาธิตวิธีการเริ่มโครงการ Spring Boot:
git clone [email protected]: hengyunabc/Spring-boot-boot-demo.gitmvn Spring-boot-demojava -jar เป้าหมาย/demo-0.0.1-snapshot.jar
หาก IDE ที่ใช้คือสปริงหรือแนวคิดคุณสามารถสร้างโครงการสปริงบูตผ่านตัวช่วยสร้าง
นอกจากนี้คุณยังสามารถอ้างอิงถึงการสอนอย่างเป็นทางการ:
http://docs.spring.io/spring-boot/docs/current-snapshot/reference/htmlsingle/#getting-started-first-application
สองคำถามเกี่ยวกับการบูตฤดูใบไม้ผลิ
เมื่อคุณเริ่มติดต่อ Spring Boot เป็นครั้งแรกคุณมักจะมีคำถามเหล่านี้
มาวิเคราะห์ว่า Spring Boot เสร็จอย่างไร
การบูต Spring เริ่มต้นอย่างไรเมื่อบรรจุเป็นขวดเดียว
หลังจาก Maven ถูกบรรจุแล้วไฟล์ Jar สองไฟล์จะถูกสร้างขึ้น:
demo-0.0.1-snapshot.jardemo-0.0.1-snapshot.jar.original
โดยที่ demo-0.0.1-snapshot.jar.original เป็นแพ็คเกจ Maven-jar-plugin เริ่มต้นเริ่มต้น
Demo-0.0.1-snapshot.jar เป็นแพ็คเกจขวดที่สร้างขึ้นโดยปลั๊กอินสปริงบูต Maven ซึ่งมีการพึ่งพาแอปพลิเคชันและคลาสที่เกี่ยวข้องกับการบูตสปริง ต่อไปนี้จะเรียกว่าขวดไขมัน
ก่อนอื่นให้ตรวจสอบโครงสร้างไดเรกทอรีของแพ็คเกจที่จัดทำโดย Spring Boot (ละเว้นหากไม่สำคัญ):
├── meta-inf│──manifest.mf├─application.properties├seC│──ตัวอย่างตัวอย่าง└─springbootdemoapplication.class├ดุlib│ดุ jar ├ดุor─ Boot └── loader ├── ExecutiveRearchIvelauncher.class ├── jarlauncher.class ├── javaagentdetector.class ├─Laimlaunch─LANGURLCLASSLOADER.CLASS├─LAY
มาดูเนื้อหาเหล่านี้กันเถอะ
manifest.mf
Manifest-Version: 1.0Start-Class: Com.example.SpringBootDemoApplicationImplementation-Vendor-Id: com.examplespring-boot-version: 1.3.0.Releasecreated-by: Apache Maven 3.3.3Build-JDK: 1.8.0_60_60 org.springframework.boot.loader.jarlauncher
คุณจะเห็นว่าคลาสหลักคือ org.springframework.boot.loader.jarlauncher ซึ่งเป็นฟังก์ชั่นหลักที่เริ่มต้นโดย Jar
นอกจากนี้ยังมีคลาสเริ่มต้นซึ่งเป็น com.example.springbootdemoapplication ซึ่งเป็นฟังก์ชั่นหลักที่เราใช้
@springbootapplicationPublic คลาส SpringbootDemoApplication {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {springapplication.run (springbootdemoapplication.class, args); - ไดเรกทอรี com/ตัวอย่าง
นี่คือไฟล์. class ของแอปพลิเคชัน
Lib Directory
นี่คือไฟล์แพ็คเกจ JAR ที่แอปพลิเคชันขึ้นอยู่กับ
ตัวอย่างเช่น Spring-beans, Spring-MVC และขวดอื่น ๆ
org/springframework/boot/loader directory
นี่คือไฟล์. class ของสปริงบูตตัวโหลด
แนวคิดเก็บถาวร
ในการบูตฤดูใบไม้ผลิแนวคิดของการเก็บถาวรนั้นเป็นนามธรรม
การเก็บถาวรสามารถเป็น jar (jarfilearchive) หรือไดเรกทอรีไฟล์ (ExplodeDarchive) สามารถเข้าใจได้ว่าเป็นเลเยอร์ของทรัพยากรการเข้าถึงแบบครบวงจรที่แยกออกจากสปริงบูต
DEMO-0.0.1-snapshot.jar ข้างต้นเป็นไฟล์เก็บถาวรและจากนั้นแต่ละแพ็คเกจขวดภายใต้ไดเรกทอรี /lib ใน demo-0.0.1-snapshot.jar ยังเป็นที่เก็บถาวร
คลังข้อมูลนามธรรมสาธารณะ {URL นามธรรมสาธารณะ Geturl (); สตริงสาธารณะ getMainClass (); คอลเล็กชันบทคัดย่อสาธารณะ <enting> getentries (); รายการบทคัดย่อสาธารณะ <CHIVE> GETNESTERARCHIVES (ตัวกรอง ententFilter);คุณจะเห็นว่าการเก็บถาวรมี URL ของตัวเองเช่น:
jar: ไฟล์: /tmp/target/demo-0.0.1-snapshot.jar!///
นอกจากนี้ยังมีฟังก์ชั่น getnestedarchives ซึ่งจริง ๆ แล้วส่งคืนรายการเก็บถาวรของขวดภายใต้ demo-0.0.1-snapshot.jar/lib URL ของพวกเขาคือ:
JAR: ไฟล์: /tmp/target/demo-0.0.1-snapshot.jar! /lib/aopalliance-1.0.jarjar: ไฟล์: /tmp/target/demo-0.0.1-snapshot.jar!
jarlauncher
จาก Manifest.mf เราจะเห็นได้ว่าฟังก์ชั่นหลักคือ Jarlauncher มาวิเคราะห์เวิร์กโฟลว์ด้านล่าง
โครงสร้างการสืบทอดของคลาส Jarlauncher คือ:
Class Jarlauncher ขยาย ExecutiveRearchivelauncherClass ExecutiveRearchivelauncher ขยายตัวเรียกใช้งาน
สร้างเก็บถาวรด้วย demo-0.0.1-snapshot.jar:
Jarlauncher พบเส้นทางของขวดที่เขาอยู่นั่นคือ Demo-0.0.1-snapshot.jar จากนั้นสร้างการเก็บถาวร
รหัสต่อไปนี้แสดงเคล็ดลับของวิธีการค้นหาตำแหน่งการโหลดจากคลาส:
ได้รับการป้องกันการเก็บถาวรขั้นสุดท้าย createRearchive () โยนข้อยกเว้น {protectionDomain protectionDomain = getClass (). getProtectionDomain (); CodeSource CodeSource = ProtectionDomain.getCodeSource (); ตำแหน่ง uri = (codeSource == null? null: codeSource.getLocation (). touri ()); String path = (location == null? null: location.getSchemEspecificPart ()); if (path == null) {โยนใหม่ legenalStateException ("ไม่สามารถกำหนดแหล่งเก็บถาวรของรหัส"); } file root = ไฟล์ใหม่ (พา ธ ); if (! root.exists ()) {โยนใหม่ lelveralStateException ("ไม่สามารถกำหนดแหล่งที่มาของรหัสที่เก็บถาวรจาก" + รูท); } return (root.isdirectory ()? New ExplodeDarchive (root): jarFilearchive ใหม่ (root));} รับขวดด้านล่าง lib/ และสร้าง unlamedurlclassloader
หลังจาก Jarlauncher สร้างการเก็บถาวรเขาใช้ฟังก์ชั่น getNestedArchives เพื่อรับไฟล์ JAR ทั้งหมดด้านล่าง DEMO-0.0.1-SNAPSHOT.JAR/LIB และสร้างเป็นรายการ
โปรดทราบว่าดังที่ได้กล่าวไว้ข้างต้น Archive มี URL ของตัวเอง
หลังจากได้รับ URL ที่เก็บถาวรเหล่านี้คุณจะได้รับอาร์เรย์ URL [] และใช้สิ่งนี้เพื่อสร้าง classloader ที่กำหนดเอง: LaunchDurlClassLoader
หลังจากสร้าง classloader ให้อ่านเริ่มคลาสจาก Manifest.mf นั่นคือ com.example.springbootdemoapplication จากนั้นสร้างเธรดใหม่เพื่อเริ่มฟังก์ชั่นหลักของแอปพลิเคชัน
/*** เรียกใช้แอปพลิเคชันที่ได้รับไฟล์เก็บถาวรและ classloader ที่กำหนดค่าไว้อย่างสมบูรณ์ */การป้องกันการเปิดตัว (สตริง [] args, สตริง mainclass, classloader classloader) โยนข้อยกเว้น {runnable runner = createMainMethodrunner (MainClass, args, classloader); เธรด runnerThread = เธรดใหม่ (runner); runnerThread.setContextClassLoader (classloader); runnerThread.setName (thread.currentthread (). getName ()); runnerThread.start ();}/*** สร้าง {@code mainmethodrunner} ที่ใช้เพื่อเปิดแอปพลิเคชัน */การป้องกัน runnable createMainMetHodrunner (สตริง mainClass, string [] args, classloader classloader) โยนข้อยกเว้น {class <?> runnerclass = classloader.loadclass (runner_class); ตัวสร้าง <?> constructor = runnerclass.getConstructor (string.class, string []. class); return (runnable) constructor.newinstance (MainClass, args);} เปิดตัว
ความแตกต่างระหว่างการเปิดตัว UrlClassLoader แบบเปิดตัวและ urlclassloader ธรรมดาคือมันให้ความสามารถในการโหลด. class จากการเก็บถาวร
การรวมฟังก์ชั่น getentries ที่จัดทำโดย Archive คุณสามารถรับทรัพยากรในการเก็บถาวร แน่นอนว่ายังมีรายละเอียดมากมายอยู่ภายในดังนั้นฉันจะอธิบายด้านล่าง
สรุปกระบวนการเริ่มต้นแอปพลิเคชัน Spring Boot Application
หลังจากเห็นสิ่งนี้คุณสามารถสรุปกระบวนการเริ่มต้นของแอปพลิเคชัน Spring Boot:
รายละเอียดในสปริงบูตตัวโหลด
ที่อยู่รหัส: https://github.com/spring-projects/spring-boot/tree/master/spring-boot-tools/spring-boot-loader
ส่วนขยายของ URL jarfile
สปริงบูตสามารถเริ่มต้นด้วยขวดไขมัน สิ่งที่สำคัญที่สุดคือใช้วิธีการโหลดของขวดในขวด
คำจำกัดความของ URL jarfile ดั้งเดิมของ JDK สามารถพบได้ที่นี่:
http://docs.oracle.com/javase/7/docs/api/java/net/jarurlconnection.html
url jarfile ดั้งเดิมมีลักษณะเช่นนี้:
jar: ไฟล์: /tmp/target/demo-0.0.1-snapshot.jar!///
URL ของทรัพยากรในแพ็คเกจ JAR:
คัดลอกรหัสดังนี้: jar: ไฟล์: /tmp/target/demo-0.0.1-snapshot.jar! /com/example/springbootdemoapplication.class
คุณจะเห็นได้ว่าสำหรับทรัพยากรใน JAR คำจำกัดความจะถูกคั่นด้วย '!/' url jarfile ดั้งเดิมรองรับหนึ่งเดียว '!/'
Spring Boot ขยายโปรโตคอลนี้เพื่อรองรับหลาย '!/' ซึ่งสามารถเป็นตัวแทนของ jar ใน jar, jar, ทรัพยากรไดเรกทอรี
ตัวอย่างเช่น URL ต่อไปนี้แสดงถึง Spring-beans-4.2.3.release.jar ในไดเรกทอรี lib ของ demo-0.0.1-snapshot.jar:
คัดลอกรหัสดังนี้: jar: ไฟล์: /tmp/target/demo-0.0.1-snapshot.jar! /lib/spring-beans-4.2.3.release.jar! /meta-inf/manifest.mf
urlstreamhandler ที่กำหนดเองขยาย jarfile และ jarurlconnection
เมื่อสร้าง URL คุณสามารถผ่านตัวจัดการและ JDK มาพร้อมกับคลาส Handler เริ่มต้น แอปพลิเคชันสามารถลงทะเบียนตัวจัดการเองเพื่อจัดการ URL ที่กำหนดเอง
URL สาธารณะ (โปรโตคอลสตริง, โฮสต์สตริง, พอร์ต int, ไฟล์สตริง, urlstreamhandler handler) พ่น malformedurlexception
อ้างถึง:
https://docs.oracle.com/javase/8/docs/api/java/net/url.html#url-java.lang.string-java.lang.string-int-java.lang.string-
Spring Boot จัดการตรรกะของขวดหลายขวดในขวดโดยการลงทะเบียนคลาส Handler ที่กำหนดเอง
ตัวจัดการนี้จะใช้ softreference เพื่อแคช jarfiles ที่เปิดทั้งหมด
เมื่อประมวลผล URL ดังต่อไปนี้ตัวคั่น '!/' จะถูกปั่นจักรยาน เริ่มต้นจากชั้นบนสุดแรกสร้าง jarfile demo-0.0.1-snapshot.jar จากนั้นสร้าง jarfile Spring-beans-4.2.3.2.3.release.jar จากนั้นสร้าง jarurlconnection ชี้ไปที่ manifest.mf
คัดลอกรหัสดังนี้: jar: ไฟล์: /tmp/target/demo-0.0.1-snapshot.jar! /lib/spring-beans-4.2.3.release.jar! /meta-inf/manifest.mf
//org.springframework.boot.loader.jar.handlerpublic คลาส handler ขยาย urlstreamhandler {ตัวคั่นสตริงสุดท้ายคงที่ส่วนตัว = "!/"; softreference ส่วนตัวคงที่ <แผนที่ <ไฟล์, jarfile >> rootfileCache; @Override ป้องกัน urlConnection openConnection (url url) พ่น ioexception {ถ้า (this.jarfile! = null) {ส่งคืน jarurlconnection ใหม่ (url, this.jarfile); } ลอง {ส่งคืน JarUrlConnection ใหม่ (url, getrootjarfilefromurl (url)); } catch (exception ex) {return openfallbackConnection (url, ex); }} public jarfile สาธารณะ getRootjarfileFromurl (url url) พ่น ioexception {string spec = url.getFile (); int separatorIndex = spec.indexof (ตัวคั่น); if (separatorIndex == -1) {โยน malformedurlexception ใหม่ ("jar url ไม่มี!/ separator"); } string name = spec.substring (0, separatorIndex); กลับ getRootjarfile (ชื่อ); - classloader อ่านทรัพยากรได้อย่างไร
ความสามารถใดที่ต้องใช้สำหรับ classloader?
API ที่เกี่ยวข้องคือ:
URL สาธารณะ FindResource (ชื่อสตริง) Public InputStream GetResourceasstream (ชื่อสตริง)
ดังที่ได้กล่าวไว้ข้างต้นเมื่อสปริงบูตสร้าง unlaedurlclassloader มันจะผ่านอาร์เรย์ URL [] อาร์เรย์เป็น URL ของขวดภายใต้ไดเรกทอรี LIB
JDK หรือ classloader รู้วิธีอ่านเนื้อหาใน URL ได้อย่างไร
อันที่จริงกระบวนการมีลักษณะเช่นนี้:
การโทรครั้งสุดท้ายคือฟังก์ชั่น getInputStream () ของ jarurlconnection
//org.springframework.boot.loader.jar.jarurlconnection @Override Public InputStream GetInputStream () พ่น IOException {Connect (); if (this.jarentryName.isEmpty ()) {โยน iOexception ใหม่ ("ไม่ระบุชื่อรายการ"); } return this.jarentrydata.getInputStream (); -จาก URL ไปจนถึงการอ่านเนื้อหาใน URL ในที่สุดกระบวนการทั้งหมดค่อนข้างซับซ้อน มาสรุปกันเถอะ:
มีรายละเอียดมากมายที่นี่มีเพียงบางจุดสำคัญเท่านั้น
ถ้าอย่างนั้น UrlclassLoader getResource จะเป็นอย่างไร?
เมื่อสร้าง urlclassloader จะมีพารามิเตอร์ url [] อาร์เรย์และจะใช้อาร์เรย์นี้เพื่อสร้าง urlclassPath:
urlclassPath UCP = ใหม่ urlclassPath (URL);
ใน URLClassPath ตัวโหลดจะถูกสร้างขึ้นสำหรับ URL ทั้งหมดและจากนั้นเมื่อได้รับการจัดหามันจะพยายามที่จะรับพวกเขาจากรถตักเหล่านี้ทีละคน
หากการได้มานั้นสำเร็จจะมีการบรรจุเป็นทรัพยากรดังต่อไปนี้
Resource GetResource (ชื่อสตริงสุดท้าย, ตรวจสอบบูลีน) {URL URL สุดท้าย; ลอง {url = url ใหม่ (ฐาน, parseutil.encodepath (ชื่อ, เท็จ)); } catch (malformedurlexception e) {โยน unlegalargumentException ใหม่ ("ชื่อ"); } ขั้นสุดท้าย URLCONNECTION UC; ลอง {ถ้า (ตรวจสอบ) {urlclassPath.check (url); } UC = url.openconnection (); inputStream ใน = UC.GetInputStream (); ถ้า (UC อินสแตนซ์ของ jarurlConnection) { / * ต้องจำไฟล์ jar เพื่อให้สามารถปิดได้ * รีบร้อน */ jarurlConnection juc = (jarUrlConnection) UC; jarfile = jarloader.checkjar (juc.getjarfile ()); }} catch (exception e) {return null; } ส่งคืนทรัพยากรใหม่ () {สตริงสาธารณะ getName () {ชื่อคืน; } URL สาธารณะ getUrl () {return url; } URL สาธารณะ getCodeSourceUrl () {ฐานกลับ; } Public InputStream getInputStream () พ่น IOException {return uc.getInputStream (); } public int getContentLength () พ่น IOException {return uc.getContentLength (); -อย่างที่คุณเห็นจากรหัส url.openconnection () เรียกจริง วิธีนี้สามารถเชื่อมต่อโซ่ที่สมบูรณ์ได้
โปรดทราบว่ารหัสของคลาส URLCLASSPATH ไม่ได้มาพร้อมกับตัวเองใน JDK ที่นี่คุณสามารถดู http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/7u40-b43/sun/misc/urlclasspath.java#506
เริ่มต้นแอปพลิเคชันสปริงบูตใน IDE/OPEN DIRECTORY
ข้างต้นจะกล่าวถึงกระบวนการของการเริ่มต้นแอปพลิเคชันการบูตสปริงในขวดไขมัน ต่อไปนี้เป็นการวิเคราะห์ว่าการบูตฤดูใบไม้ผลิเริ่มต้นอย่างไรใน IDE
ใน IDE ฟังก์ชั่นหลักที่ทำงานโดยตรงคือการใช้ฟังก์ชั่นหลักของตัวเอง:
@springbootapplicationPublic คลาส SpringbootDemoApplication {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {springapplication.run (springbootdemoapplication.class, args); -ในความเป็นจริงการเริ่มต้นแอปพลิเคชันการบูต Spring ใน IDE เป็นกรณีที่ง่ายที่สุดเนื่องจากขวดพึ่งพาจะถูกใส่ลงใน ClassPath ดังนั้น Spring Boot จึงเริ่มต้นขึ้น
อีกสถานการณ์หนึ่งคือการเริ่มต้นการบูตฤดูใบไม้ผลิในไดเรกทอรีแบบเปิด ไดเรกทอรีแบบเปิดที่เรียกว่าคือการบีบอัดขวดไขมันแล้วเริ่มแอปพลิเคชันโดยตรง
java org.springframework.boot.loader.jarlauncher
ในเวลานี้ Spring Boot จะพิจารณาว่าปัจจุบันอยู่ในไดเรกทอรีหรือไม่ ถ้าเป็นเช่นนั้นให้สร้าง ExplodeDarchive (อันก่อนหน้านี้คือ jarfilearchive) และกระบวนการเริ่มต้นที่ตามมาจะคล้ายกับขวดไขมัน
กระบวนการเริ่มต้น Tomcat เริ่มต้น
ตรวจสอบว่าอยู่ในสภาพแวดล้อมของเว็บ
เมื่อสปริงบูตเริ่มต้นก่อนกำหนดว่าจะอยู่ในสภาพแวดล้อมเว็บหรือไม่โดยเพียงแค่ค้นหาคลาสเซิร์ฟเล็ต:
สตริงสุดท้ายคงที่ [] web_environment_classes = {"javax.servlet.servlet", "org.springframework.web.context.configurablewebapplicationContex null)) {return false; }} return true;}ถ้าเป็นเช่นนั้น AnnotationConfigembedDedWebapplicationContext จะถูกสร้าง
//org.springFramework.boot.springapplication ป้องกันการกำหนดค่า createApplicationContext () {class <?> contextclass = this.applicationContextClass; if (contextclass == null) {ลอง {contextclass = class.forName (this.webenvironment? default_web_context_class: default_context_class); } catch (classnotfoundexception ex) {โยนใหม่ unlilmalstateException ("ไม่สามารถสร้าง ApplicationContext เริ่มต้น" + "โปรดระบุ ApplicationContextClass", Ex); }} return (configurableapplicationContext) beanutils.instantiate (contextclass); - รับคลาสการใช้งานของ EmbeddedServletContainerFactory
Spring Boot เริ่มต้นเว็บเซิร์ฟเวอร์ที่สอดคล้องกันโดยได้รับ EmbeddedServletContainerFactory
สองคลาสการใช้งานที่ใช้กันทั่วไปคือ tomcatembeddedservletContainerFactory และ jettyembeddedservletContainerFactory
รหัสเพื่อเริ่ม Tomcat:
// tomcatembeddedservletContainerFactory@overridepublic EmbeddedservletContainer getembeddedservletContainer (servletContextInitializer ... initializers) {tomcat tomcat = New Tomcat (); ไฟล์ basedir = (this.basedirectory! = null? this.basedir: createtempdir ("tomcat")); tomcat.setbasedir (basedir.getabsolutepath ()); ตัวเชื่อมต่อตัวเชื่อมต่อ = ตัวเชื่อมต่อใหม่ (this.protocol); tomcat.getService (). AddConnector (ตัวเชื่อมต่อ); CustomizeConnector (ตัวเชื่อมต่อ); tomcat.setConnector (ตัวเชื่อมต่อ); tomcat.gethost (). setautodeploy (เท็จ); tomcat.getEngine (). SetbackgroundProcessordelay (-1); สำหรับ (Connector MutterConnector: this.additionAltomCatConnectors) {tomcat.getService (). AddConnector (MutterConnector); } preparecontext (tomcat.gethost (), initializers); กลับ gettomcatembeddedservletcontainer (tomcat);} ไดเรกทอรีไฟล์ชั่วคราวจะถูกสร้างขึ้นสำหรับ Tomcat เช่น:
/tmp/tomcat.2233614112516545210.8080 เป็นพื้นฐานของ Tomcat ไฟล์ Tomcat ชั่วคราวเช่นไดเรกทอรีงานจะถูกวางไว้ข้างใน
Servlets Tomcat บางตัวจะเริ่มต้นเช่นค่าเริ่มต้นที่สำคัญกว่า/jsp servlet:
โมฆะส่วนตัว addDefaultServlet (บริบทบริบท) {wrapper defaultServlet = context.createWrapper (); defaultServlet.setName ("ค่าเริ่มต้น"); defaultServlet.SetServletClass ("org.apache.catalina.servlets.defaultservlet"); defaultServlet.addinitParameter ("debug", "0"); defaultServlet.addinitParameter ("รายชื่อ", "false"); DefaultServlet.setLoadOnStartup (1); // มิฉะนั้นตำแหน่งเริ่มต้นของสปริง dispatcherservlet ไม่สามารถตั้งค่า defaultServlet.setOverridable (จริง); Context.addChild (DefaultServlet); context.addservletMapping ("/", "default");} โมฆะส่วนตัว addjspservlet (บริบทบริบท) {wrapper jspservlet = context.createwrapper (); jspservlet.setName ("JSP"); jspservlet.setServletClass (getJSpservletClassName ()); jspservlet.addinitparameter ("Fork", "False"); JSPSERVLET.SETLOADONSTARTUP (3); Context.addChild (JSpservlet); Context.addservletMapping ("*. jsp", "jsp"); context.addservletmapping ("*. jspx", "jsp");} วิธีการเข้าถึงทรัพยากรด้วยแอปพลิเคชัน Web Boot Spring
ฉันจะเข้าถึงทรัพยากรเว็บได้อย่างไรเมื่อแอปพลิเคชัน Spring Boot บรรจุเป็นขวดไขมันได้อย่างไร
มันถูกนำไปใช้จริงผ่าน URL ที่จัดทำโดย Archive และจากนั้นผ่านความสามารถในการเข้าถึงทรัพยากร ClassPath ที่จัดทำโดย classloader
index.html
ตัวอย่างเช่นคุณต้องกำหนดค่า index.html ซึ่งสามารถวางโดยตรงใน SRC/Main/Resources/Directory Static ในรหัส
สำหรับหน้ายินดีต้อนรับ index.html เมื่อเริ่มต้นการบูตสปริงจะสร้าง ViewController เพื่อจัดการ:
// ResourcePropertiespublic คลาส ResourceProperties ใช้ ResourceLoaderAware {สตริงสุดท้ายคงที่ [] servlet_resource_locations = {"/"}; สตริงสุดท้ายคงที่ส่วนตัว [] classPath_Resource_locations = {"classpath:/meta-inf/resources/", "classpath:/ทรัพยากร/", "classpath:/คงที่/", "classpath:/สาธารณะ/"}; // WebMVCautoconFigurationAdapter @Override โมฆะสาธารณะ AddViewControllers (ViewControllerRegistry Registry) {หน้าทรัพยากร = this.resourceProperties.getWelcomePage (); if (page! = null) {logger.info ("เพิ่มหน้าต้อนรับ:" + หน้า); registry.addviewController ("/"). setViewName ("forward: index.html"); - เทมเพลต
ตัวอย่างเช่นไฟล์เทมเพลตหน้าสามารถวางไว้ในไดเรกทอรี SRC/Main/Resources/Template แต่นี่คือการจัดการโดยคลาสการใช้งานเทมเพลตเอง ตัวอย่างเช่นในคลาส thymeleafproperties:
สตริงสุดท้ายคงที่สาธารณะ default_prefix = "classpath:/templates/";
JSP
หน้า JSP คล้ายกับเทมเพลต มันได้รับการจัดการผ่าน JSTLView ที่สร้างขึ้นใน Spring MVC
คุณสามารถกำหนดค่า Spring.view.prefix เพื่อตั้งค่าไดเรกทอรีของหน้า JSP:
Spring.view.prefix:/web-inf/jsp/
การจัดการหน้าข้อผิดพลาดแบบครบวงจรในการบูตฤดูใบไม้ผลิ
สำหรับหน้าข้อผิดพลาดสปริงบูตยังได้รับการจัดการอย่างสม่ำเสมอโดยการสร้าง BasicerRoncontroller
@controller@requestmapping ("$ {server.error.path: $ {error.path:/ข้อผิดพลาด}}") คลาสสาธารณะ BasicerrorController ขยาย abstracterrorControllerมุมมองที่สอดคล้องกันเป็นเครื่องเตือนความจำ HTML อย่างง่าย:
@Configuration@conditionalOnProperty (prefix = "server.error.whiteLabel", name = "enabled", matchifMissing = true) @conditional (errortemplatemissingCondition.class) "<html> <body> <h1> หน้าข้อผิดพลาด Whitelabel </h1>" + "<p> แอปพลิเคชันนี้ไม่มีการแมปที่ชัดเจนสำหรับ/ข้อผิดพลาดดังนั้นคุณจะเห็นสิ่งนี้เป็นทางเลือก </p>" + "<div id = 'สร้าง'> $ {timestamp} + "<div> $ {ข้อความ} </div> </body> </html>"); @Bean (name = "ข้อผิดพลาด") @ConditionAlonMissingBean (name = "ข้อผิดพลาด") มุมมองสาธารณะ defaulterRorView () {return this.defaulterRorView; -Spring Boot เป็นวิธีปฏิบัติที่ดีซึ่งหลีกเลี่ยงข้อยกเว้นเริ่มต้นที่เกิดขึ้นเมื่อเว็บแอปพลิเคชันดั้งเดิมทำให้เกิดข้อผิดพลาดทำให้ง่ายต่อการรั่วไหลของความลับ
กระบวนการบรรจุภัณฑ์ maven ของแอปพลิเคชันสปริงบูต
ขั้นแรกให้สร้างขวดที่มีการพึ่งพาผ่าน maven-shade-plugin จากนั้นจัดทำคลาสที่เกี่ยวข้องกับสปริงบูตตัวโหลดและ manifest.mf ลงในขวดผ่านปลั๊กอินสปริง-โบท-เมเวน-ปลั๊กอิน
การใช้บันทึกสีในสปริงบูต
เมื่อเริ่มต้นแอปพลิเคชันสปริงบูตในเชลล์คุณจะพบว่าเอาต์พุตของตัวบันทึกเป็นสีซึ่งน่าสนใจมาก
การตั้งค่านี้สามารถปิดได้:
spring.output.ansi.enabled = false
หลักการคือการได้รับการกำหนดค่านี้ผ่าน ansioutputaplicationListener จากนั้นตั้งค่า logback เป็น output เพิ่ม colorconverter และแสดงผลบางฟิลด์ผ่าน org.springframework.boot.ansi.ansioutput
เคล็ดลับรหัสบางอย่าง
เมื่อใช้ classloader รองรับการโหลดแบบขนาน JDK7
คุณสามารถอ้างถึง Lockprovider ใน LaunchDurlClassLoader
คลาสสาธารณะที่เปิดตัว UrlClassLoader {Private Static LockProvider Lock_Provider = SetUplockProvider (); private lockprovider setuplockprovider () {ลอง {classloader.registerasparallelcapable (); ส่งคืน Java7LockProvider ใหม่ (); } catch (nosuchmethoderror ex) {ส่งคืน lockprovider ใหม่ (); }} @Override คลาสที่ได้รับการป้องกัน <?> loadclass (ชื่อสตริง, การแก้ไขบูลีน) พ่น classnotfoundexception {ซิงโครไนซ์ (likenedurlclassloader.lock_provider.getLock (ชื่อนี้)) {คลาส <? if (loadEdClass == null) {handler.SetUseFastConnectionExceptions (จริง); ลอง {loadEdClass = doLoadClass (ชื่อ); } ในที่สุด {handler.SetUseFastConnectionExceptions (เท็จ); }} if (Resolve) {RELEVECLASS (loadEdClass); } return loadedclass; - ตรวจสอบว่าแพ็คเกจ JAR ถูกโหลดผ่านตัวแทนหรือไม่
InputargumentsJavaagentDetector หลักการคือการตรวจสอบว่า URL ของขวดมีคำนำหน้าของ "-javaagent:"
สตริงสุดท้ายคงที่ส่วนตัว java_agent_prefix = "-javaagent:";
รับ PID ของกระบวนการ
ApplicationPid คุณสามารถรับ PID ได้
สตริงส่วนตัว getPid () {ลอง {สตริง jvmname = managementFactory.getRuntImemxBean (). getName (); ส่งคืน jvmname.split ("@") [0]; } catch (throwable ex) {return null; - คลาส Logger Packaging
แพ็คเกจการบูตสปริงชุดเครื่องบันทึกซึ่งรองรับ Java, log4j, log4j2, logback คุณสามารถอ้างถึงสิ่งนี้เมื่อคุณต้องการจัดทำเครื่องบันทึกด้วยตัวเองในอนาคต
ภายใต้แพ็คเกจ org.springframework.boot.logging
รับฟังก์ชั่นหลักเริ่มต้นดั้งเดิม
ด้วยวิธีการที่ได้รับในสแต็กตัดสินฟังก์ชั่นหลักและค้นหาฟังก์ชันหลักเริ่มต้นดั้งเดิม
คลาสส่วนตัว <?> deducemainapplicationclass () {ลอง {stacktracelement [] stacktrace = new runtimeException (). getStackTrace (); สำหรับ (stacktraceElement stacktracelement: stacktrace) {ถ้า ("main" .equals (stacktracelement.getMethodname ())) {return class.forname (stacktracelement.getClassName ()); }}} catch (classnotfoundexception ex) {// swallow และดำเนินการต่อ} return null;} ข้อเสียบางประการของ spirng boot:
เมื่อแอปพลิเคชันสปริงบูตทำงานในขวดไขมันจะพบปัญหาบางอย่าง นี่คือความคิดเห็นส่วนตัวของฉัน:
สรุป
Spring Boot ขยายโปรโตคอล JAR, บทคัดย่อแนวคิดการเก็บถาวรและการสนับสนุน jarfile, jarurlconnection และเปิดตัว Urlclassloader ดังนั้นจึงตระหนักถึงประสบการณ์การพัฒนาของทุกคนในที่เดียวโดยไม่ต้องรับรู้แอปพลิเคชันชั้นบน แม้ว่าสงครามที่สามารถดำเนินการได้ไม่ใช่แนวคิดที่เสนอโดยฤดูใบไม้ผลิ แต่การบูตในฤดูใบไม้ผลิช่วยให้สามารถดำเนินการต่อไปได้
Spring Boot เป็นโครงการที่น่าทึ่งซึ่งอาจกล่าวได้ว่าเป็นฤดูใบไม้ผลิที่สองของฤดูใบไม้ผลิ Spring-Cloud-config, Spring-Session, Metrics, Remote Shell ฯลฯ เป็นโครงการและคุณสมบัติทั้งหมดที่นักพัฒนาชื่นชอบ เกือบจะแน่นอนว่านักออกแบบมีประสบการณ์มากมายในการพัฒนาแนวหน้าและตระหนักดีถึงจุดปวดของนักพัฒนา
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น