การแรเงาการพึ่งพาเป็นกระบวนการของการรวมและการเปลี่ยนชื่อการพึ่งพา (ดังนั้นการย้ายคลาสและการเขียนซ้ำที่ได้รับผลกระทบจากโค้ดและทรัพยากร) เพื่อสร้างสำเนาส่วนตัวที่คุณรวมไว้ข้างรหัสของคุณ
แนวคิดนี้มักเกี่ยวข้องกับuber-jars (aka fat jars )
มีความสับสนเกี่ยวกับคำว่าเนื่องจากปลั๊กอินเฉดสี Maven ซึ่งภายใต้ชื่อเดียวนั้นจะทำ2 สิ่ง (อ้างถึงหน้าของตัวเอง):
ปลั๊กอินนี้ให้ความสามารถในการแพคเกจสิ่งประดิษฐ์ใน uber-jar รวมถึงการอ้างอิงและแรเงา - เช่นเปลี่ยนชื่อ - แพคเกจของการอ้างอิงบางอย่าง
ดังนั้นส่วนที่แรเงานั้นเป็นทางเลือก: ปลั๊กอินอนุญาตให้รวมการพึ่งพาใน jar ของคุณ (jar ไขมัน) และการเปลี่ยนชื่อการแรเงา (แรเงา) ซึ่งเป็นทางเลือก
เพิ่มแหล่งอื่น :
เพื่อแรเงาห้องสมุดคือการใช้ไฟล์เนื้อหาของห้องสมุดกล่าวใส่ไว้ในขวดของคุณเองและเปลี่ยนแพคเกจของพวกเขา สิ่งนี้แตกต่างจากบรรจุภัณฑ์ซึ่งเป็นเพียงการส่งไฟล์ไลบรารีที่อยู่ข้างๆโถของคุณเองโดยไม่ต้องย้ายไฟล์ไปยังแพ็คเกจอื่น
ในทางเทคนิคการพูดการพึ่งพาจะถูกแรเงา แต่เป็นเรื่องปกติที่จะอ้างถึง fat-jar-with-shaded-dependencies ว่า "shaded jar" และหาก jar นั้นเป็นไคลเอนต์สำหรับระบบอื่นก็สามารถเรียกได้ว่าเป็น "shaded client"
นี่คือชื่อปัญหา Jira สำหรับ HBase ที่คุณเชื่อมโยงในคำถามของคุณ:
เผยแพร่สิ่งประดิษฐ์ของไคลเอ็นต์ที่มีการขึ้นต่อกันที่เป็นร่มเงา
ดังนั้นในโพสต์นี้ฉันพยายามเสนอแนวคิดทั้งสองโดยไม่ทำให้พวกเขาสับสน
ดี
Uber-jars มักใช้เพื่อจัดส่งแอปพลิเคชันเป็นไฟล์เดียว (ทำให้ง่ายต่อการปรับใช้และเรียกใช้) พวกเขายังสามารถใช้ในการจัดส่งห้องสมุดพร้อมกับบางส่วน (หรือทั้งหมด) ของการพึ่งพาของพวกเขาแรเงาเพื่อหลีกเลี่ยงความขัดแย้งเมื่อใช้โดยโปรแกรมอื่น ๆ (ซึ่งอาจใช้รุ่นที่แตกต่างกันของห้องสมุดเหล่านั้น)
มีหลายวิธีในการสร้าง uber-jars แต่maven-shade-plugin
ไปอีกขั้นหนึ่งด้วยคุณสมบัติการย้ายตำแหน่ง :
หาก uber JAR ถูกนำกลับมาใช้ใหม่เป็นการอ้างอิงของโปรเจ็กต์อื่นรวมถึงคลาสโดยตรงจากการพึ่งพาของสิ่งประดิษฐ์ใน uber JAR อาจทำให้เกิดความขัดแย้งในการโหลดคลาสเนื่องจากคลาสที่ซ้ำกันบนคลาสพา ธ เพื่อแก้ไขปัญหานี้เราสามารถย้ายคลาสที่รวมอยู่ในสิ่งประดิษฐ์ที่แรเงาเพื่อสร้างสำเนาส่วนตัวของ bytecode
(หมายเหตุประวัติ: ลิงก์ Jar Jarนำเสนอคุณลักษณะการย้ายตำแหน่งก่อนหน้า)
ด้วยวิธีนี้คุณสามารถทำให้การอ้างอิงไลบรารีของคุณมีรายละเอียดการใช้งานได้เว้นแต่คุณจะเปิดเผยคลาสจากไลบรารีเหล่านั้นใน API ของคุณ
สมมติว่าฉันมีโครงการ ACME Quantanizer ™ซึ่งจัดเตรียมDecayingSyncQuantanizer
คลาสและขึ้นอยู่กับ Apache Commons-rng (เพราะแน่นอนว่าต้องมีปริมาณที่เหมาะสมที่คุณต้องการ a XorShift1024Star
, duh)
ถ้าฉันใช้ plugin maven เงาเพื่อสร้าง uber-jar และฉันมองเข้าไปข้างในฉันเห็นไฟล์คลาสเหล่านี้:
com/acme/DecayingSyncQuantanizer.class
org/apache/commons/rng/RandomProviderState.class
org/apache/commons/rng/RestorableUniformRandomProvider.class
...
org/apache/commons/rng/core/source64/XorShift1024Star.class
org/apache/commons/rng/core/util/NumberFactory.class
ตอนนี้ถ้าฉันใช้คุณสมบัติการย้ายคลาส:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<relocations>
<relocation>
<pattern>org.apache.commons</pattern>
<shadedPattern>com.acme.shaded.apachecommons</shadedPattern>
</relocation>
</relocations>
</configuration>
</execution>
</executions>
</plugin>
เนื้อหาของ uber-jar มีลักษณะดังนี้:
com/acme/DecayingSyncQuantanizer.class
com/acme/shaded/apachecommons/rng/RandomProviderState.class
com/acme/shaded/apachecommons/rng/RestorableUniformRandomProvider.class
...
com/acme/shaded/apachecommons/rng/core/source64/XorShift1024Star.class
com/acme/shaded/apachecommons/rng/core/util/NumberFactory.class
มันไม่เพียงแค่เปลี่ยนชื่อไฟล์เท่านั้น แต่จะเขียน bytecode ที่อ้างอิงคลาสที่ย้ายที่ตั้งใหม่ (ดังนั้นคลาส & คอมมอนส์ rng ของฉันเองจะถูกแปลงทั้งหมด)
นอกจากนี้ปลั๊กอิน Shade จะสร้าง POM ( dependency-reduced-pom.xml
) ใหม่ซึ่งการพึ่งพาการแรเงาจะถูกลบออกจาก<dependencies>
ส่วน สิ่งนี้จะช่วยให้ใช้โถที่แรเงาเป็นที่พึ่งพิงสำหรับโครงการอื่น ดังนั้นคุณสามารถเผยแพร่ jar นั้นแทนเบสแรกหรือทั้งสองอย่าง (ใช้ qualifier สำหรับ jar สีเทา)
เพื่อให้มีประโยชน์มาก ...
เลว
... แต่มันก็มีปัญหาหลายอย่าง การรวมการพึ่งพาทั้งหมดไว้ใน "namespace" เดียวภายใน jar สามารถทำให้ยุ่งเหยิงและต้องการการแรเงาและ messing กับทรัพยากร
ตัวอย่างเช่น: วิธีจัดการกับไฟล์ทรัพยากรที่มีชื่อคลาสหรือแพ็คเกจ ไฟล์ทรัพยากรเช่นคำอธิบายของผู้ให้บริการซึ่งทุกคนอยู่ภายใต้META-INF/services
?
ปลั๊กอินสีนำเสนอตัวแปลงทรัพยากรที่สามารถช่วยได้:
การรวมคลาส / ทรัพยากรจากสิ่งประดิษฐ์หลาย ๆ อย่างไว้ใน uber JAR หนึ่งตัวจะถูกส่งต่อไปตราบใดที่ไม่มีการทับซ้อนกัน มิฉะนั้นต้องใช้ตรรกะบางอย่างเพื่อรวมทรัพยากรจาก JAR หลาย ๆ ตัวเข้าด้วยกัน นี่คือที่ที่ตัวแปลงทรัพยากรเตะเข้า
แต่ก็ยังคงยุ่งเหยิงและปัญหาแทบจะเป็นไปไม่ได้ที่จะคาดการณ์ (บ่อยครั้งที่คุณค้นพบปัญหาอย่างหนักในการผลิต) ดูว่าทำไมเรา-หยุดการสร้างไขมันไห
โดยรวมแล้วการปรับใช้ jar แบบไขมันในฐานะที่เป็นแอพ / บริการแบบสแตนด์อโลนยังคงเป็นเรื่องปกติมากคุณเพียงแค่ต้องระวัง gotchas และสำหรับบางคนที่คุณอาจต้องการการแรเงาหรือลูกเล่นอื่น ๆ
น่าเกลียด
มีปัญหาที่ยากขึ้นมากมาย (การดีบักการทดสอบความเข้ากันได้กับ OSGi และเครื่องมือสร้างคลาสที่แปลกใหม่ ... )
แต่ที่สำคัญกว่านั้นคือเมื่อคุณสร้างห้องสมุดประเด็นต่าง ๆ ที่คุณคิดว่าคุณสามารถควบคุมได้นั้นซับซ้อนมากขึ้นเรื่อย ๆ เนื่องจาก jar ของคุณจะถูกนำไปใช้ในบริบทที่แตกต่างกันมากมาย ในสภาพแวดล้อมที่มีการควบคุม)
ตัวอย่างเช่น ElasticSearch ใช้เพื่อแรเงาการอ้างอิงบางอย่างในขวดที่จัดส่ง แต่พวกเขาตัดสินใจที่จะหยุดการทำเช่นนั้น :
ก่อนเวอร์ชัน 2.0, Elasticsearch ถูกจัดให้เป็น JAR ที่มีการพึ่งพาทั่วไปบางส่วน (แต่ไม่ใช่ทั้งหมด) ที่แรเงาและบรรจุภายในสิ่งประดิษฐ์เดียวกัน สิ่งนี้ช่วยให้ผู้ใช้ Java ที่ฝัง Elasticsearch ไว้ในแอปพลิเคชันของตนเองเพื่อหลีกเลี่ยงความขัดแย้งของโมดูลเช่น Guava, Joda, Jackson และอื่น ๆ แน่นอนว่ายังมีรายการของการพึ่งพาอื่น ๆ ที่ไม่มีการแรเงาเช่น Lucene
น่าเสียดายที่การแรเงาเป็นกระบวนการที่ซับซ้อนและเกิดข้อผิดพลาดซึ่งแก้ไขปัญหาสำหรับบางคนในขณะที่สร้างปัญหาให้ผู้อื่น การแรเงาทำให้เป็นเรื่องยากสำหรับนักพัฒนาและผู้เขียนปลั๊กอินในการเขียนและตรวจแก้จุดบกพร่องรหัสอย่างถูกต้องเนื่องจากแพ็คเกจถูกเปลี่ยนชื่อในระหว่างการสร้าง ในที่สุดเราใช้ในการทดสอบ Elasticsearch ที่ไม่มีการแรเงาแล้วส่งขวดที่แรเงาและเราไม่ชอบที่จะจัดส่งสิ่งที่เราไม่ได้ทดสอบ
เราได้ตัดสินใจจัดส่ง Elasticsearch โดยไม่แรเงาตั้งแต่ 2.0 เป็นต้นไป
โปรดทราบว่าพวกเขาก็หมายถึงการพึ่งพาสีเทาไม่ใช่ขวดสีเทา