คำนำ
เมื่อเราใช้คำอธิบายประกอบ @DiscoveryClient เราจะมีคำถามต่อไปนี้: ทำไมมันถึงดำเนินการลงทะเบียนบริการ? ไม่ควรใช้เป็นบริการ Discovery? มาสำรวจซอร์สโค้ดในเชิงลึก
1. อินเทอร์เฟซวงจรชีวิตของ SpringFramework
เพื่อให้เข้าใจถึงปัญหานี้เราต้องเข้าใจอินเทอร์เฟซที่สำคัญนี้:
/ * * ลิขสิทธิ์ 2002-2015 ผู้แต่งหรือผู้เขียนดั้งเดิม * * ได้รับอนุญาตภายใต้ใบอนุญาต Apache เวอร์ชัน 2.0 ("ใบอนุญาต"); * คุณไม่สามารถใช้ไฟล์นี้ยกเว้นตามใบอนุญาต * คุณอาจได้รับสำเนาใบอนุญาตที่ * * http://www.apache.org/licenses/license-2.0 * * เว้นแต่ว่ากฎหมายที่บังคับใช้หรือตกลงที่จะเป็นลายลักษณ์อักษรซอฟต์แวร์ * แจกจ่ายภายใต้ใบอนุญาตจะถูกแจกจ่ายใน "ตาม" โดยไม่มีการรับประกันหรือเงื่อนไขใด ๆ * ดูใบอนุญาตสำหรับภาษาเฉพาะที่ควบคุมการอนุญาตและ * ข้อ จำกัด ภายใต้ใบอนุญาต */แพ็คเกจ org.springframework.context;/*** วิธีการกำหนดอินเทอร์เฟซทั่วไปสำหรับการควบคุมวงจรชีวิตเริ่ม/หยุด * กรณีการใช้งานทั่วไปสำหรับสิ่งนี้คือการควบคุมการประมวลผลแบบอะซิงโครนัส * <b> หมายเหตุ: อินเทอร์เฟซนี้ไม่ได้หมายความถึงความหมายการเริ่มต้นอัตโนมัติเฉพาะ * พิจารณาการใช้งาน {@link smartlifecycle} เพื่อจุดประสงค์นั้น </b> * * <p> สามารถนำไปใช้งานได้โดยทั้งสองส่วนประกอบ (โดยทั่วไปจะเป็นถั่วฤดูใบไม้ผลิที่กำหนดไว้ในบริบท * ฤดูใบไม้ผลิ) และคอนเทนเนอร์ (โดยทั่วไปคือสปริง {@link ApplicationContext คอนเทนเนอร์จะเผยแพร่สัญญาณเริ่มต้น/หยุดไปยังส่วนประกอบทั้งหมดที่ * ใช้ภายในแต่ละคอนเทนเนอร์เช่นสำหรับสถานการณ์หยุด/รีสตาร์ทเมื่อรันไทม์ * * <p> สามารถใช้สำหรับการเรียกใช้โดยตรงหรือสำหรับการดำเนินการจัดการผ่าน JMX * ในกรณีหลัง {@link org.springframework.jmx.export.mbeanexporter} * โดยทั่วไปแล้วจะถูกกำหนดด้วย * {@link org.springframework.jmx.export.assembler อินเทอร์เฟซ * * <p> โปรดทราบว่าอินเทอร์เฟซวงจรชีวิตได้รับการสนับสนุนเฉพาะใน <b> Singleton ระดับบนสุด * ถั่ว </b> ในส่วนประกอบอื่น ๆ อินเทอร์เฟซวงจรชีวิตจะยังคงไม่ถูกตรวจพบ * และไม่สนใจ นอกจากนี้โปรดทราบว่าอินเตอร์เฟส {@link smartlifecycle} extended * ให้การรวมเข้ากับเฟสเริ่มต้นและปิดการปิดของบริบทของแอปพลิเคชัน * * @author Juergen Hoeller * @Since 2.0 * @See SmartLifecycle * @See ConfiguRableApplicationContext * @SEE org.springFramework.jms.listener.abstractMessagelistenercontainer * @See org.springframework /*** เริ่มองค์ประกอบนี้ * <p> ไม่ควรโยนข้อยกเว้นหากส่วนประกอบกำลังทำงานอยู่แล้ว * <p> ในกรณีของคอนเทนเนอร์สิ่งนี้จะเผยแพร่สัญญาณเริ่มต้นไปยังส่วนประกอบ * ทั้งหมดที่ใช้ * @See SmartLifecycle#isautostartup () */ void start (); /** * หยุดส่วนประกอบนี้โดยทั่วไปจะอยู่ในรูปแบบซิงโครนัสเช่นส่วนประกอบจะหยุดอย่างเต็มที่เมื่อกลับมาของวิธีนี้ พิจารณาการใช้งาน {@link smartlifecycle} * และตัวแปร {@code stop (runnable)} เมื่อต้องใช้พฤติกรรมหยุดแบบอะซิงโครนัส * <p> โปรดทราบว่าการแจ้งเตือนการหยุดนี้ไม่รับประกันว่าจะมาก่อนการทำลายล้าง: เปิด * การปิดปกติ {@code lifecycle} ถั่วจะได้รับการแจ้งเตือนหยุดก่อน * การโทรกลับการทำลายล้างทั่วไปจะถูกเผยแพร่; อย่างไรก็ตามในการรีเฟรชร้อนในช่วงชีวิตของบริบท * หรือในความพยายามรีเฟรชที่ถูกยกเลิกจะมีการเรียกใช้วิธีการทำลายเท่านั้น * <p> ไม่ควรโยนข้อยกเว้นหากส่วนประกอบยังไม่เริ่ม * <p> ในกรณีของคอนเทนเนอร์สิ่งนี้จะเผยแพร่สัญญาณหยุดไปยังส่วนประกอบทั้งหมด * ที่ใช้ * @See SmartLifecycle#Stop (Runnable) * @See org.springframework.beans.factory.disposableBean#destroy () */ void stop (); /*** ตรวจสอบว่าส่วนประกอบนี้กำลังทำงานอยู่หรือไม่ * <p> ในกรณีของคอนเทนเนอร์สิ่งนี้จะส่งคืน {@code True} เฉพาะในกรณีที่ <i> ทั้งหมด </i> * ส่วนประกอบที่ใช้กำลังทำงานอยู่ * @return ว่าส่วนประกอบกำลังทำงานอยู่ในขณะนี้ */ บูลีน isrunning ();}อินเทอร์เฟซนี้กำหนดวิธีการควบคุมวงจรชีวิตเริ่ม/หยุด เมื่อคอนเทนเนอร์สปริง IOC เริ่มต้นหรือหยุดสัญญาณเริ่มต้นหรือหยุดจะถูกส่งไปยังแต่ละองค์ประกอบดังนั้นเราสามารถทำสิ่งที่เราต้องการในวิธีการที่เกี่ยวข้อง เราสามารถค้นหาได้ผ่านไดอะแกรมคลาสที่เราใช้คลาส classpathxmlapplicationContext โดยทั่วไปใช้อินเทอร์เฟซนี้
มาสาธิตกรณีสั้น ๆ และสร้าง mylifecycle คลาส:
แพ็คเกจ org.hzgj.spring.study.context; นำเข้า org.springframework.context.smartlifecycle; Mylifecycle คลาสสาธารณะใช้ SmartLifecycle {@Override public start start () {system.out.println ("mylifecycle start .... "); } @Override โมฆะสาธารณะหยุด () {system.out.println ("mylifecycle stop ..... "); } @Override บูลีนสาธารณะ isrunning () {return false; } @Override บูลีนสาธารณะ isautostartup () {return true; } @Override โมฆะสาธารณะหยุด (เรียกใช้กลับมาได้) {} @Override สาธารณะ int getPhase () {system.out.println ("เฟส"); กลับ 10; -ที่นี่เราสืบทอด SmartLifecycle อินเทอร์เฟซสืบทอดวงจรชีวิต วิธีการ isrunning ใช้เพื่อตรวจสอบว่าส่วนประกอบปัจจุบันอยู่ในสถานะการทำงานหรือไม่ โปรดทราบว่ามันสามารถรันได้ก็ต่อเมื่อค่าส่งคืน isrunning เป็นเท็จ
เรากำหนดค่า mylifecycle เป็นไฟล์การกำหนดค่าสปริงและเรียกใช้ผ่าน classpathxmlapplicationContext เพื่อรับผลลัพธ์ต่อไปนี้:
นอกจากนี้วิธีการ getPhase ที่นี่คือการกำหนดค่าขั้นตอน (สามารถเข้าใจได้ว่าเป็นลำดับความสำคัญยิ่งค่าที่เล็กลงเท่าไหร่วงจรชีวิตที่สอดคล้องกันก็จะถูกดำเนินการก่อน) มากขึ้น)
2. การวิจัยซอร์สโค้ด DiscoveryClient
@enablediscoveyclient
/ * * ลิขสิทธิ์ 2013-2015 ผู้แต่งหรือผู้แต่งดั้งเดิม * * ได้รับอนุญาตภายใต้ใบอนุญาต Apache เวอร์ชัน 2.0 ("ใบอนุญาต"); * คุณไม่สามารถใช้ไฟล์นี้ยกเว้นตามใบอนุญาต * คุณอาจได้รับสำเนาใบอนุญาตที่ * * http://www.apache.org/licenses/license-2.0 * * เว้นแต่ว่ากฎหมายที่บังคับใช้หรือตกลงที่จะเป็นลายลักษณ์อักษรซอฟต์แวร์ * แจกจ่ายภายใต้ใบอนุญาตจะถูกแจกจ่ายใน "ตาม" โดยไม่มีการรับประกันหรือเงื่อนไขใด ๆ * ดูใบอนุญาตสำหรับการอนุญาตการกำกับดูแลภาษาเฉพาะและ * ข้อ จำกัด ภายใต้ใบอนุญาต */แพ็คเกจ org.springframework.cloud.client.discovery นำเข้า java.lang.annotation.documented; นำเข้า java.lang.annotation.elementtype; นำเข้า java.lang.annotation.inherited; java.lang.annotation.target; นำเข้า org.springframework.context.annotation.import;/*** คำอธิบายประกอบเพื่อเปิดใช้งานการใช้งาน DiscoveryClient * @author Spencer Gibb * /@Target (ElementType.type) @retention (RetentionPolicy.runtime)@documented@สืบทอด@import (enableiscoveryClientImportSelector.class) สาธารณะ @interface */ บูลีน autoregister () ค่าเริ่มต้นจริง;} โปรดทราบว่า @Import(EnableDiscoveryClientImportSelector.class) เราสามารถอ้างถึงคลาสนี้:
/ * * ลิขสิทธิ์ 2013-2015 ผู้แต่งหรือผู้แต่งดั้งเดิม * * ได้รับอนุญาตภายใต้ใบอนุญาต Apache เวอร์ชัน 2.0 ("ใบอนุญาต"); * คุณไม่สามารถใช้ไฟล์นี้ยกเว้นตามใบอนุญาต * คุณอาจได้รับสำเนาใบอนุญาตที่ * * http://www.apache.org/licenses/license-2.0 * * เว้นแต่ว่ากฎหมายที่บังคับใช้หรือตกลงที่จะเป็นลายลักษณ์อักษรซอฟต์แวร์ * แจกจ่ายภายใต้ใบอนุญาตจะถูกแจกจ่ายใน "ตาม" โดยไม่มีการรับประกันหรือเงื่อนไขใด ๆ * ดูใบอนุญาตสำหรับภาษาเฉพาะที่ควบคุมการอนุญาตและ * ข้อ จำกัด ภายใต้ใบอนุญาต */แพ็คเกจ org.springframework.cloud.client.discovery; นำเข้า org.springframework.boot.bind.relaxedpropertyresolver นำเข้า org.springframework.cloud.commons.util.springfringFringFringFringFringFactoryImportlector; org.springframework.core.annotation.annotationattributes; นำเข้า org.springframework.core.annotation.order; นำเข้า org.springframework.core.env.configurable org.springframework.core.env.mappropertysource นำเข้า org.springframework.core.type.annotationmetadata; นำเข้า java.util.arraylist; นำเข้า java.util.arrays; gibb */ @order (ordered.lowest_precedence - 100) คลาสสาธารณะ enableiscoveryClientImportSelector ขยาย SpringFactoryImportSelector <EnablediscoveryClient> {@Override สตริงสาธารณะ [] SelectImports (AnnotationMetadata Metadata) AnnotationAttributes แอตทริบิวต์ = AnnotationAttributes.fommap (metadata.getannotationattributes (getannotationClass (). getName (), จริง)); บูลีน autoregister = attributes.getBoolean ("autoregister"); if (autoreGister) {รายการ <String> importSlist = arrayList ใหม่ <> (array.aslist (นำเข้า)); importslist.add ("org.springframework.cloud.client.serviceregistry.autoserviceregistrationConfiguration"); นำเข้า = importSlist.toArray (สตริงใหม่ [0]); } else {environment env = getenvironment (); if (configureDableEnvironment.class.isinstance (env)) {configurableEnvironment configenv = (กำหนดค่าความสามารถในสภาพแวดล้อม) env; LinkedHashMap <String, Object> MAP = ใหม่ LinkedHashMap <> (); map.put ("spring.cloud.service-registry.auto-registration.enabled", false); MappropertySource PropertySource = ใหม่ mapropertySource ("SpringCloudDiscoveryClient", แผนที่); configenv.getPropertySources (). AddLast (PropertySource); }} ส่งคืนนำเข้า; } @Override บูลีนที่ได้รับการป้องกัน isenabled () {ส่งคืนใหม่ RelaxedPropertyResolver (getenvironment ()). getProperty ("Spring.cloud.discovery.enabled", boolean.class, boolean.true); } @Override Boolean Protected HasDefaultFactory () {return true; - วิธีการเขียนคลาสนี้ใหม่มาจากอินเทอร์เฟซ ImportSelector เราสามารถติดตามคลาสตามรหัสภายใต้ if(autoRegister) : org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration มาดูแผนภาพโครงสร้างกันเถอะ:
เราสามารถรู้ได้ว่าคลาสนี้ใช้อินเทอร์เฟซวงจรชีวิตดังนั้นลองมาดูวิธีการเริ่มต้นซึ่งอยู่ในคลาสหลัก AbstractDiscoverylifecycle:
/ * * ลิขสิทธิ์ 2013-2015 ผู้แต่งหรือผู้แต่งดั้งเดิม * * ได้รับอนุญาตภายใต้ใบอนุญาต Apache เวอร์ชัน 2.0 ("ใบอนุญาต"); * คุณไม่สามารถใช้ไฟล์นี้ยกเว้นตามใบอนุญาต * คุณอาจได้รับสำเนาใบอนุญาตที่ * * http://www.apache.org/licenses/license-2.0 * * เว้นแต่ว่ากฎหมายที่บังคับใช้หรือตกลงที่จะเป็นลายลักษณ์อักษรซอฟต์แวร์ * แจกจ่ายภายใต้ใบอนุญาตจะถูกแจกจ่ายใน "ตาม" โดยไม่มีการรับประกันหรือเงื่อนไขใด ๆ * ดูใบอนุญาตสำหรับภาษาเฉพาะที่ควบคุมการอนุญาตและ * ข้อ จำกัด ภายใต้ใบอนุญาต */แพ็คเกจ org.springframework.cloud.client.discovery นำเข้า java.util.concurrent.atomic.atomicboolean; นำเข้า java.util.concurrent.atomic.atomicinteger; นำเข้า Javax.annotation.predestroy; org.apache.commons.logging.logfactory; นำเข้า org.springframework.beans.beansexception; นำเข้า org.springframework.boot.context.embedded.embeddedservletContainerInitialiveDevent; org.springframework.cloud.client.serviceregistry.serviceregistry; นำเข้า org.springframework.context.applicationContext; นำเข้า org.springframework.context.applicationContextAware org.springframework.core.env.environment;/*** วิธีวงจรชีวิตที่อาจเป็นประโยชน์และเป็นเรื่องธรรมดาสำหรับการใช้งาน DiscoveryClient ต่างๆ * * @deprecated ใช้ {@link org.springframework.cloud.client.serviceregistry.abstractautoserviceregistration} แทน คลาสนี้จะถูกลบออกในรถไฟรุ่นถัดไป * * @author Spencer Gibb */ @DecrecatedPublic Abstract Class AbstractDiscoverylifecycle ใช้ Discoverylifecycle, ApplicationContextaware, ApplicationListener บูลีนส่วนตัว autostartup = true; Atomicboolean ส่วนตัว Running = New Atomicboolean (เท็จ); คำสั่งส่วนตัว int = 0; บริบท ApplicationContext ส่วนตัว สภาพแวดล้อมภาคเอกชน พอร์ต Atomicinteger ส่วนตัว = Atomicinteger ใหม่ (0); Protected ApplicationContext getContext () {กลับบริบท; } @Override โมฆะสาธารณะ setApplicationContext (ApplicationContext ApplicationContext) พ่น beansexception {this.context = ApplicationContext; this.environment = this.context.getenvironment (); } @deprecated สภาพแวดล้อมที่ได้รับการป้องกัน getenvironment () {return environment; } @deprecated ป้องกัน Atomicinteger getport () {return port; } @Override บูลีนสาธารณะ isautostartup () {return this.autostartup; } @Override โมฆะสาธารณะหยุด (เรียกกลับกลับได้) {ลอง {stop (); } catch (Exception e) {logger.error ("ปัญหาเกิดขึ้นพยายามหยุดการค้นพบวงจรชีวิต", e); } callback.run (); } @Override โมฆะสาธารณะเริ่มต้น () {ถ้า (! isenabled ()) {ถ้า (logger.isdebugenabled ()) {logger.debug ("Discovery Lifecycle ปิดใช้งานไม่เริ่มต้น"); } กลับ; } // ตั้งค่าพอร์ตเท่านั้นหาก nonsecureport เป็น 0 และ this.port! = 0 ถ้า (this.port.get ()! = 0 && getConfiguredPort () == 0) {setConfiguredPort (this.port.get ()); } // เริ่มต้นเฉพาะเมื่อ nonsecureport มากกว่า 0 และยังไม่ทำงานอยู่ // เนื่องจาก containerportinitializer ด้านล่างถ้า (! this.running.get () && getConfiguredport ()> 0) {register (); if (ควร registerManagement ()) {registeragement (); } this.context.publisheVent (ใหม่ InstanceregisteredEvent <> (นี่คือ getConfiguration ())); สิ่งนี้ running.compareandset (เท็จ, จริง); }} @deprecated abstract int int getConfiguredPort (); @deprecated void void setConfiguredPort (พอร์ต int); / ** * @return หากควรลงทะเบียนบริการการจัดการด้วย {@link serviceregistry} */ บูลีนที่ได้รับการป้องกันควรจะลงทะเบียนการจัดการ () {return getmanagementport ()! = null && managementerportils.isdifferent } / ** * @return วัตถุที่ใช้ในการกำหนดค่าการลงทะเบียน * / @deprecated วัตถุนามธรรมที่ได้รับการป้องกัน getConfiguration (); / ** * ลงทะเบียนบริการท้องถิ่นด้วย DiscoveryClient */ Void Void register () ที่ได้รับการป้องกัน (); / ** * ลงทะเบียนบริการการจัดการท้องถิ่นด้วย DiscoveryClient */ Void registerManagement () {}/ ** * ยกเลิกการลงทะเบียนบริการท้องถิ่นด้วย DiscoveryClient */ Void Deregister ที่ได้รับการป้องกัน (); / ** * ยกเลิกการลงทะเบียนบริการการจัดการท้องถิ่นด้วย DiscoveryClient */ void deregisterManagement () {}/ ** * @@return จริงถ้า {@link discoverylifecycle} เปิดใช้งาน * / ** * @return ServiceId ของบริการการจัดการ */ @deprecated String ที่ได้รับการป้องกัน getmanagementserviceId () {// todo: การจัดการที่กำหนดค่าได้รับการต่อท้าย this.context.getId () + ": การจัดการ"; } / ** * @return ชื่อบริการของบริการการจัดการ * / @deprecated String getManagementserviceName () {// todo: การจัดการที่กำหนดค่าได้รับการต่อท้าย getAppName () + ": การจัดการ"; } / ** * @return พอร์ตเซิร์ฟเวอร์การจัดการ * / @deprecated Integer Integer GetManagementPort () {ส่งคืน ManagementServerPortUts.getport (this.context); } / ** * @return ชื่อแอปปัจจุบัน Spring.application.Name คุณสมบัติ * / @deprecated String ที่ได้รับการป้องกัน getAppName () {return this.environment.getProperty ("Spring.application.name", "แอปพลิเคชัน"); } @Override โมฆะสาธารณะหยุด () {ถ้า (this.running.CompareAndset (จริง, เท็จ) && isenabled ()) {deregister (); if (ควร registerManagement ()) {deregisterManagement (); }}} @predestroy โมฆะสาธารณะทำลาย () {stop (); } @Override บูลีนสาธารณะ isrunning () {return this.running.get (); } ป้องกัน Atomicboolean getRunning () {return running; } @Override สาธารณะ int getOrder () {return this.order; } @Override สาธารณะ int getPhase () {return 0; } @Override @Deprecated Public Void onapplicationEvent (EmbeddedServletContainerInitializedEvent) {// todo: นำ SSL เข้าบัญชี // อย่าลงทะเบียนพอร์ตการจัดการเป็นพอร์ตถ้า (! "การจัดการ" Event.getembeddedServletContainer (). getPort ()); this.start (); -โปรดทราบว่ามีส่วนหนึ่งของรหัสนี้ในวิธีการเริ่มต้น:
if (! this.running.get () && getConfiguredPort ()> 0) {register (); if (ควร registerManagement ()) {registeragement (); } this.context.publisheVent (ใหม่ InstanceregisteredEvent <> (นี่คือ getConfiguration ())); สิ่งนี้ running.compareandset (เท็จ, จริง); - โปรดทราบ register() เป็นวิธีนามธรรมในชั้นเรียนนี้ ลองดูที่รหัสในคลาส Abstractautoserviceregistration และฉันจะโพสต์เฉพาะส่วนสำคัญที่นี่:
// ..... ได้รับการป้องกัน Abstractautoserviceregistration (serviceregistry <r> serviceregistry, คุณสมบัติ AutoserviceregistrationProperties) {this.serviceregistry = serviceregistry; this.properties = คุณสมบัติ; } //e./** * ลงทะเบียนบริการท้องถิ่นด้วย {@link serviceregistry} */@Override Void Void register () {this.serviceregistry.register (getRegistration ()); -เราสามารถพบว่าประเภท serviceregistry ถูกส่งผ่านในตัวสร้างซึ่งเป็นอินเตอร์เฟส SpringCloud ให้เราสำหรับการลงทะเบียนบริการ ที่นี่ Eurekaserviceregistry ใช้อินเทอร์เฟซนี้:
/ * * ลิขสิทธิ์ 2013-2016 ผู้แต่งหรือผู้แต่งดั้งเดิม * * ได้รับอนุญาตภายใต้ใบอนุญาต Apache เวอร์ชัน 2.0 ("ใบอนุญาต"); * คุณไม่สามารถใช้ไฟล์นี้ยกเว้นตามใบอนุญาต * คุณอาจได้รับสำเนาใบอนุญาตที่ * * http://www.apache.org/licenses/license-2.0 * * เว้นแต่ว่ากฎหมายที่บังคับใช้หรือตกลงที่จะเป็นลายลักษณ์อักษรซอฟต์แวร์ * แจกจ่ายภายใต้ใบอนุญาตจะถูกแจกจ่ายใน "ตาม" โดยไม่มีการรับประกันหรือเงื่อนไขใด ๆ * ดูใบอนุญาตสำหรับภาษาเฉพาะที่ควบคุมการอนุญาตและ * ข้อ จำกัด ภายใต้ใบอนุญาต * */แพ็คเกจ org.springframework.cloud.netflix.eureka.serviceregistry; นำเข้า java.util.hashmap; นำเข้า org.apache.commons.logging.log; นำเข้า org.apache.commons.logging.logfactory; org.springframework.cloud.client.serviceregistry.serviceregistry; นำเข้า com.netflix.appinfo.instanceinfo;/** * @author Spencer Gibb */ชั้นเรียนสาธารณะ logfactory.getLog (Eurekaserviceregistry.class); @Override Void Void Register (Eurekaregistration reg) {อาจจะเป็นลิขสิทธิ์ (reg); if (log.isinfoenabled ()) {log.info ("การลงทะเบียนแอปพลิเคชัน" + reg.getInstanceconfig (). getAppName () + "กับ Eureka ที่มีสถานะ" + reg.getInstanceconfig () getInitialStatus (); } reg.getApplicationInfomanager () .setInstancestatus (reg.getInstanceconfig (). getInitialStatus ()); if (reg.gethealthcheckhandler ()! = null) {reg.geteurekaclient (). registerHealthCheck (reg.gethealthcheckhandler ()); }} โมฆะส่วนตัวอาจจะเป็นลิขสิทธิ์ (reg Eurekaregistration) {// การเริ่มต้นการเริ่มต้นของพร็อกซีที่เป็นไปได้ reg.getapplicationInfomanager (). getInfo (); reg.geteurekaclient (). getapplications (); } @Override เป็นโมฆะสาธารณะ deregister (Eurekaregistration reg) {ถ้า (reg.getapplicationInfomanager (). getInfo ()! = null) {ถ้า (log.isinfoenabled ()) {log.info ("แอปพลิเคชันที่ไม่ลงทะเบียน" } reg.getApplicationInfomanager (). setinstancestatus (instanceInfo.instancestatus.down); // การปิดตัวลงของไคลเอนต์ยูเรก้าควรเกิดขึ้นกับยูเรกอเรตต์การลงทะเบียน () // การลงทะเบียนอัตโนมัติจะสร้างถั่วซึ่งจะแจกจ่ายอย่างถูกต้อง // การลงทะเบียนด้วยตนเองจะต้องโทรปิด ()} @Override void setstatus // TODO: วิธีจัดการกับการลบอย่างถูกต้อง? if ("cancel_override" .equalsignorecase (สถานะ)) {registration.geteurekaclient (). canceloverridestatus (ข้อมูล); กลับ; } // TODO: วิธีจัดการกับประเภทสถานะในระบบการค้นพบ? InstanceInfo.instancestatus newstatus = instanceInfo.instancestatus.toenum (สถานะ); ลงทะเบียน. geteurekaclient (). setstatus (newstatus, ข้อมูล); } @Override วัตถุสาธารณะ getStatus (การลงทะเบียน Eurekaregistration) {HashMap <String, Object> สถานะ = ใหม่ HashMap <> (); InstanceInfo info = ลงทะเบียน getApplicationInfomanager (). getInfo (); status.put ("สถานะ", info.getStatus (). toString ()); status.put ("overriddenStatus", info.getOverRiddenStatus (). TOSTRING ()); สถานะการส่งคืน; } public void close () {}}ดังนั้นเราสามารถสรุปประเด็นต่อไปนี้:
1. การใช้ @DiscoveryClient เพื่อลงทะเบียนบริการใช้กลไก Lifecycle และวิธี register() ของ Serviceregistry จะถูกดำเนินการเมื่อเริ่มต้นคอนเทนเนอร์
2. การใช้ @DiscoveryClient นั้นมีความยืดหยุ่นมากกว่า @enableeurekaclient และ @enableeurekaserver เพราะมันบล็อกการใช้งานการลงทะเบียนบริการและเราสามารถปรับแต่งศูนย์การลงทะเบียนได้
3. สิ่งนี้จะค้นหาการใช้งานอินเทอร์เฟซ DiscoveryClient สำหรับการค้นหาบริการโดยอัตโนมัติ
3. ศูนย์ลงทะเบียน Redis DiscoveryClient
ด้านล่างเราใช้ข้อกำหนดตาม Redis เป็นศูนย์ลงทะเบียนเพื่อทำความเข้าใจ DiscoveryClient โดยวิธีการที่จะเข้าใจอินเทอร์เฟซที่สำคัญของ SpringCloud: Serviceregistry, ServiceInstance ก่อนหน้านี้เราจะเพิ่มการสนับสนุนสำหรับ Redis:
กลุ่มคอมไพล์: 'org.springframework.boot', ชื่อ: 'Spring-Boot-Starter-Data-Redis'
1. ใช้ส่วนต่อประสานการลงทะเบียน
แพ็คเกจ com.hzgj.lyrk.member; นำเข้า org.springframework.beans.factory.annotation.value; นำเข้า org.springframework.cloud.client.serviceregistry.gramet.pringframework.stereotype.component; java.net.networkInterface; นำเข้า java.net.uri; นำเข้า java.util.enumeration; นำเข้า java.util.map; @componentpublic คลาส redisregistration ดำเนินการลงทะเบียน {@value ("$ {server.port}" @Value ("$ {Spring.application.Name}") แอปพลิเคชันสตริงส่วนตัว; โฮสต์สตริงส่วนตัว โมฆะสาธารณะ sethost (โฮสต์สตริง) {this.host = โฮสต์; } โมฆะสาธารณะ setport (พอร์ตจำนวนเต็ม) {this.port = พอร์ต; } โมฆะสาธารณะ setApplicationName (สตริงแอปพลิเคชันชื่อ) {this.applicationName = ApplicationName; } @Override สตริงสาธารณะ getServiceId () {return applicationname + ":" + gethost () + ":" + getPort (); } @Override สตริงสาธารณะ getHost () {ลอง {ถ้า (host == null) return getLocalhostlanaddress (). gethostaddress (); อื่น ๆ กลับโฮสต์; } catch (exception e) {e.printstacktrace (); } return null; } @Override สาธารณะ int getPort () {พอร์ตส่งคืน; } @Override บูลีนสาธารณะ issecure () {return false; } @Override URI Public Geturi () {return null; } @Override แผนที่สาธารณะ <สตริงสตริง> getMetAdata () {return null; } สตริงสาธารณะ getServicename () {return this.applicationName; } public inetaddress getLocalhostlanaddress () โยนข้อยกเว้น {ลอง {inetaddress candidateDateDress = null; // traverse อินเตอร์เฟสเครือข่ายทั้งหมดสำหรับ (การแจงนับ ifaces = networkInterface.getNetWorkInterfaces (); ifaces.hasmoreElements ();) {networkInterface iface = (networkInterface) ifaces.nextElement (); // สำรวจ IP ภายใต้อินเทอร์เฟซทั้งหมดสำหรับ (การแจงนับ inetAddrs = iface.getInetAddresses (); inetaddrs.hasmoreElements ();) {inetaddress inetaddr = (inetaddress) inetaddrs.nextelement (); if (! inetaddr.isloopbackaddress ()) {// ยกเว้นที่อยู่ประเภท loopback ถ้า (inetaddr.issitelocaladdress ()) {// ถ้าเป็นที่อยู่เว็บไซต์ท้องถิ่นมันจะส่งคืน inetaddr; } อื่นถ้า (candidateAddress == null) {// ที่อยู่ของประเภทไซต์ท้องถิ่นไม่พบบันทึกแรกที่ที่อยู่ผู้สมัคร CandidateAddress = InetAddr; }}}}} if (candidateAddress! = null) {return candidateAddress; } // หากไม่พบที่อยู่ที่ไม่ใช่ loopback คุณสามารถใช้โซลูชันที่เลือกมากที่สุดเท่านั้น InetAddress JdksUppliedDdress = InetAddress.getLocalHost (); ส่งคืน JdksUppliedaddress; } catch (exception e) {e.printstacktrace (); } return null; -อินเทอร์เฟซนี้สืบทอดการบริการดังนั้นฟังก์ชั่นหลักของอินเทอร์เฟซนี้คือการกำหนดข้อกำหนดของอินสแตนซ์บริการเช่นสิ่งที่เป็นบริการของมันคืออะไรหมายเลขพอร์ต ฯลฯ คืออะไร ฯลฯ
2. ใช้อินเทอร์เฟซของ serviceregistry
แพ็คเกจ com.hzgj.lyrk.member; นำเข้า org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.cloud.client.serviceregistry.serviceregistry; Serviceregistry <RedisRegistration> {@autowired Private Stringredistemplate Redistemplate; @Override โมฆะสาธารณะลงทะเบียน (การลงทะเบียนการลงทะเบียน redisregistration) {String ServiceId = ลงทะเบียน. getServiceId (); redistemplate.opsforlist (). leftpush (serviceId, registration.gethost () + ":" + registration.getport ()); } @Override โมฆะสาธารณะ deregister (การลงทะเบียน redisregistration) {redistemplate.opsforlist (). ลบ (ลงทะเบียน. getServiceId (), 1, ลงทะเบียน. gethost () + ":" + ลงทะเบียน. getport ()); } @Override โมฆะสาธารณะปิด () {//redistemplate.d System.out.println ("ปิด ... "); } @Override โมฆะสาธารณะ setstatus (การลงทะเบียน redisregistration, สถานะสตริง) {} @Override สาธารณะ <t> t getStatus (การลงทะเบียน redisregistration) {return null; -ฟังก์ชั่นหลักของอินเทอร์เฟซนี้คือการกำหนดวิธีการลงทะเบียนยกเลิกบริการตั้งค่าและรับสถานะบริการ ฯลฯ
3. มรดก Abstractautoserviceregistration คลาสบทคัดย่อ
แพ็คเกจ com.hzgj.lyrk.member; นำเข้า org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.cloud.client.serviceregistry.abstractautoserviceregistration; org.springframework.cloud.client.serviceregistry.abstractautoserviceregistration; นำเข้า org.springframework.cloud.client.serviceregistry.serviceregistry; Redisregistration; ได้รับการป้องกัน redisautoserviceregistration (serviceregistry <dredisregistration> serviceregistry, คุณสมบัติ AutoserviceregistrationProperties) {super (serviceregistry, คุณสมบัติ); // serviceregistry.register (getRegistration ()); } @Override ป้องกัน int getConfiguredPort () {return redisregistration.getport (); } @Override void void setConfiguredPort (พอร์ต int) {} @Override วัตถุที่ได้รับการป้องกัน getConfiguration () {return null; } @Override boolean ที่ได้รับการป้องกัน isenabled () {return true; } @Override ได้รับการปกป้อง redisregistration getRegistration () {return redisregistration; } @Override ป้องกันการลงทะเบียน getmanagementRegistration () {return null; -4. กำหนดระดับการใช้งานของ DiscoveryClient RedisdiscoveryClient
แพ็คเกจ com.hzgj.lyrk.member; นำเข้า org.apache.commons.lang.stringutils; นำเข้า org.springframework.beans.factory.annotation.autowired; นำเข้า org.springframework.cloud.client.serviceinstance; org.springframework.data.redis.core.stringredistemplate; นำเข้า java.util.arraylist; นำเข้า java.util.list; นำเข้า java.util.function.function; นำเข้า java.util.stream.collectors; @Override Public String คำอธิบาย () {return "การค้นพบบริการใน Redis Registration Center"; } @Override Public ServiceInstance getLocalserviceInstance () {return null; } @Override รายการสาธารณะ <ServiceInstance> getInstances (String ServiceId) {return redistemplate.opsforlist (). ช่วง (ServiceId, 0, -1) ParalleLsStream (). MAP ((ฟังก์ชั่น <String, ServiceInstance>) s -> {redisRegistration redisregistration = ใหม่ redisregistration (); redisregistration.setApplicationName (serviceId); สตริงโฮสต์ = stringutils.split (s, ") [0] Redisregistration.Sethost (ชื่อโฮสต์); } @Override รายการสาธารณะ <String> getServices () {list <string> list = new ArrayList <> (); list.addall (redistemplate.keys ("*")); รายการคืน; -ชั้นเรียนนี้มีวัตถุประสงค์หลักในการค้นพบบริการของศูนย์ทะเบียน Redis
5. กำหนดคลาสแอสเซมบลีอัตโนมัติเพื่อสร้างถั่วที่สอดคล้องกัน
แพ็คเกจ com.hzgj.lyrk.member; นำเข้า org.springframework.boot.autoconfigure.condition.conditionalonproperty; นำเข้า org.springframework.boot.context.properties.enableconfigurationproperties; org.springframework.cloud.client.serviceregistry.autoserviceregistrationProperties; นำเข้า org.springframework.context.annotation.bean; นำเข้า org.springframework.context.annotation.configuration; org.springframework.context.annotation.primary;@configuration@enableConfigurationProperties (redisconfig.class) @conditionalonProperty (value = "Spring.redis.registry.enabled", MatchifMissing = True) redisserviceregistry (redisconfig redisconfig) {system.out.println (redisconfig.gethost ()); ส่งคืน REDISSERVICEREGISTRY ใหม่ (); } @Bean redisautoserviceregistration redisautoserviceregistration (redisserviceregistry redisserviceregistry) {ส่งคืนใหม่ redisautoserviceregistry ใหม่ } @Bean @Primary RedisDiscoveryClient RedisDiscoveryClient () {ส่งคืน RedisDiscoveryClient ใหม่ (); -6. กำหนดคลาสเริ่มต้น
แพ็คเกจ com.hzgj.lyrk.member; นำเข้า org.springframework.boot.springapplication; นำเข้า org.springframework.boot.autoconfigure.springbootapplication; นำเข้า org.springframework.cloud.client.discovery.discovery.discovery org.springframework.cloud.client.discovery.enablediscoveryclient นำเข้า org.springframework.cloud.client.discovery.composite org.springframework.context.configurableapplicationContext;@enablediscoveryclient@springbootapplication (exclude = {simplediscoveryClientautoconFiguration.class, compositedIscoveryClientAutoconFiguration.class}) springapplication.run (memberapplication.class, args); DiscoveryClient DiscoveryClient = ApplicationContext.getBean (DiscoveryClient.class); DiscoveryClient.getServices (). foreach (การกระทำ -> {system.out.println (การกระทำ);}); -ที่นี่การประกอบเริ่มต้นของ DiscoveryClient ได้รับการยกเว้นในคำอธิบายประกอบ SpringBootapplication
เมื่อเราเริ่มสำเร็จเราจะพบว่าคอนโซลมีการส่งออกชื่อบริการและที่อยู่ที่เกี่ยวข้อง:
เราสร้างไฟล์ JAR อีกครั้งผ่านการบรรจุหีบห่อและเรียกใช้:
java -jar member-server-0.0.1-snapshot.jar-server.port = 8800
เราจะเห็นได้ว่าค่าที่ลงทะเบียนบริการที่ได้รับการแคชใน Redis:
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com