กำหนดค่าอัตโนมัติและรันเซิร์ฟเวอร์ gRPC แบบฝังด้วย bean ที่เปิดใช้งาน @ GRpcService ซึ่งเป็นส่วนหนึ่งของแอปพลิเคชัน spring-boot (วิดีโอสั้น)
ผู้ใช้ Gradle
ควรใช้งานปลั๊กอิน:
plugins {
id " io.github.lognet.grpc-spring-boot " version ' 5.1.5 '
}
ปลั๊กอิน io.github.lognet.grpc-spring-boot gradle ช่วยให้การตั้งค่าโปรเจ็กต์ง่ายขึ้นอย่างมาก
repositories {
mavenCentral()
// maven { url "https://oss.sonatype.org/content/repositories/snapshots" } // for snapshot builds
}
dependencies {
implementation ' io.github.lognet:grpc-spring-boot-starter:5.1.5 '
}
ตามค่าเริ่มต้น ตัวเริ่มต้นจะดึง io.grpc:grpc-netty-shaded
เป็นการพึ่งพาแบบสกรรมกริยา หากคุณถูกบังคับให้ใช้การพึ่งพา grpc-netty
ล้วนๆ:
implementation ( ' io.github.lognet:grpc-spring-boot-starter:5.1.5 ' ) {
exclude group : ' io.grpc ' , module : ' grpc-netty-shaded '
}
implementation ' io.grpc:grpc-netty:1.58.0 ' // (1)
ตรวจสอบให้แน่ใจว่าได้ดึงเวอร์ชันที่ตรงกับรุ่น
การมีอยู่ของไลบรารีทั้งสองบน classpath ยังได้รับการสนับสนุนด้วยคุณสมบัติ grpc.netty-server.on-collision-prefer-shaded-netty
หากคุณใช้ปลั๊กอิน Spring Boot Dependency Management ปลั๊กอินอาจดึงเวอร์ชันที่ไม่ใช่เวอร์ชันเดียวกันกับเวอร์ชันที่เริ่มคอมไพล์ ทำให้เกิดปัญหาความไม่เข้ากันของไบนารี
ในกรณีนี้ คุณจะต้องตั้งค่าเวอร์ชัน grpc
ที่จะใช้อย่างชัดเจนและบังคับ (ดูเมทริกซ์เวอร์ชันที่นี่ ):
configurations . all {
resolutionStrategy . eachDependency { details ->
if ( " io.grpc " . equalsIgnoreCase(details . requested . group)) {
details . useVersion " 1.58.0 "
}
}
}
สามารถดูบันทึกประจำรุ่นที่มีเมทริกซ์ความเข้ากันได้ได้ที่นี่ |
ปฏิบัติตามคำแนะนำนี้เพื่อสร้างอินเทอร์เฟซ stub และเซิร์ฟเวอร์จากไฟล์ .proto
ของคุณ
หากคุณซ้อนกับ maven - ใช้ลิงค์นี้
ใส่คำอธิบายประกอบการใช้งานอินเทอร์เฟซเซิร์ฟเวอร์ของคุณด้วย @org.lognet.springboot.grpc.GRpcService
คุณสามารถเลือกกำหนดค่าพอร์ตเซิร์ฟเวอร์ใน application.yml/properties
ของคุณ พอร์ตเริ่มต้นคือ 6565
grpc :
port : 6565
พอร์ตสุ่มสามารถกำหนดได้โดยการตั้งค่าพอร์ตเป็น 0 พอร์ตจริงที่ใช้นั้นสามารถดึงข้อมูลได้โดยใช้คำอธิบายประกอบ @LocalRunningGrpcPort ในฟิลด์ int ซึ่งจะแทรกพอร์ตที่ทำงานอยู่ (กำหนดค่าอย่างชัดเจนหรือเลือกแบบสุ่ม) |
เปิดใช้งานการสะท้อนเซิร์ฟเวอร์ (ดู https://github.com/grpc/grpc-java/blob/master/documentation/server-reflection-tutorial.md)
grpc :
enableReflection : true
เลือกที่จะตั้งค่าลำดับเฟสเริ่มต้น (ค่าเริ่มต้นเป็น Integer.MAX_VALUE
)
grpc :
start-up-phase : XXX
คุณสามารถเลือกตั้งค่าจำนวนวินาทีเพื่อรอให้การโทรที่มีอยู่แล้วเสร็จสิ้นระหว่างการปิดเซิร์ฟเวอร์อย่างค่อยเป็นค่อยไป สายใหม่จะถูกปฏิเสธในช่วงเวลานี้ ค่าลบเทียบเท่ากับระยะเวลาผ่อนผันที่ไม่มีที่สิ้นสุด ค่าเริ่มต้นคือ 0
(หมายถึงไม่ต้องรอ)
grpc :
shutdownGrace : 30
คุณสมบัติเซิร์ฟเวอร์เฉพาะ Netty สามารถระบุได้ภายใต้คำนำหน้า grpc.netty-server
ด้วยการกำหนดค่าค่า grpc.netty-server.xxxx
ค่าใดค่าหนึ่ง แสดงว่าคุณกำลังตั้งค่าการขนส่งให้เป็นแบบ Netty โดยปริยาย
grpc :
netty-server :
keep-alive-time : 30s (1)
max-inbound-message-size : 10MB (2)
primary-listen-address : 10.10.15.23:0 (3)
additional-listen-addresses :
- 192.168.0.100:6767 (4)
on-collision-prefer-shaded-netty : false (5)
คุณสมบัติประเภท Duration
สามารถกำหนดค่าด้วยรูปแบบค่าสตริงที่อธิบายไว้ที่นี่
คุณสมบัติประเภท DataSize
สามารถกำหนดค่าด้วยค่าสตริงที่อธิบายไว้ที่นี่
เปิดเผยบน IP เครือข่ายภายนอกพร้อมพอร์ตที่กำหนดเอง
รูปแบบค่าสตริงคุณสมบัติชนิด SocketAddress
:
host:port
(หากค่า port
น้อยกว่า 1 จะใช้ค่าสุ่ม)
host:
(ใช้พอร์ต grpc เริ่มต้น 6565
)
เปิดเผยบน IP เครือข่ายภายในรวมถึงพอร์ตที่กำหนดไว้ล่วงหน้า 6767
ในกรณีที่คุณมีไลบรารี netty ทั้ง shaded
และ pure
ให้เลือกประเภท NettyServerBuilder
ที่ควรสร้างขึ้น นี่คือประเภทที่จะส่งผ่านไปยัง GRpcServerBuilderConfigurer
(ดูการกำหนดค่าเซิร์ฟเวอร์ gRPC แบบกำหนดเอง) ค่าเริ่มต้นเป็น true
(เช่น io.grpc.netty.shaded.io.grpc.netty.NettyServerBuilder
; io.grpc.netty.NettyServerBuilder
ถ้า false
)
สตาร์ทเตอร์ยังรองรับ in-process server
ด้วย ซึ่งควรใช้เพื่อการทดสอบ :
grpc :
enabled : false (1)
inProcessServerName : myTestServer (2)
ปิดการใช้งานเซิร์ฟเวอร์เริ่มต้น ( NettyServer
)
เปิดใช้งานเซิร์ฟเวอร์ in-process
หากคุณเปิดใช้งานทั้ง NettyServer และเซิร์ฟเวอร์ in-process ทั้งคู่จะแชร์อินสแตนซ์เดียวกันของ HealthStatusManager และ GRpcServerBuilderConfigurer (ดูการกำหนดค่าเซิร์ฟเวอร์ gRPC แบบกำหนดเอง) |
ในโปรเจ็กต์ grpc-spring-boot-starter-demo
คุณจะพบตัวอย่างการทำงานที่สมบูรณ์พร้อมการทดสอบการรวมระบบ
คำจำกัดความของบริการจากไฟล์ .proto
มีลักษณะดังนี้:
service Greeter {
rpc SayHello ( HelloRequest ) returns ( HelloReply ) {}
}
สังเกตคลาส io.grpc.examples.GreeterGrpc.GreeterImplBase
ที่สร้างขึ้นซึ่งขยาย io.grpc.BindableService
สิ่งที่คุณต้องทำคือใส่คำอธิบายประกอบการใช้งานบริการของคุณด้วย @org.lognet.springboot.grpc.GRpcService
@ GRpcService
public static class GreeterService extends GreeterGrpc . GreeterImplBase {
@ Override
public void sayHello ( GreeterOuterClass . HelloRequest request , StreamObserver < GreeterOuterClass . HelloReply > responseObserver ) {
final GreeterOuterClass . HelloReply . Builder replyBuilder = GreeterOuterClass . HelloReply . newBuilder (). setMessage ( "Hello " + request . getName ());
responseObserver . onNext ( replyBuilder . build ());
responseObserver . onCompleted ();
}
}
สตาร์ทเตอร์รองรับการลงทะเบียน interceptors สองประเภท: Global และ Per Service
ในทั้งสองกรณี interceptor ต้องใช้อินเทอร์เฟซ io.grpc.ServerInterceptor
ต่อบริการ
@ GRpcService ( interceptors = { LogInterceptor . class })
public class GreeterService extends GreeterGrpc . GreeterImplBase {
// ommited
}
LogInterceptor
จะถูกสร้างอินสแตนซ์ผ่านโรงงานสปริง หากมี bean ประเภท LogInterceptor
หรือผ่านตัวสร้าง no-args อย่างอื่น
ทั่วโลก
@ GRpcGlobalInterceptor
public class MyInterceptor implements ServerInterceptor {
// ommited
}
สนับสนุนคำอธิบายประกอบเกี่ยวกับวิธีการตั้งค่าจากโรงงานของ Java:
@ Configuration
public class MyConfig {
@ Bean
@ GRpcGlobalInterceptor
public ServerInterceptor globalInterceptor (){
return new ServerInterceptor (){
@ Override
public < ReqT , RespT > ServerCall . Listener < ReqT > interceptCall ( ServerCall < ReqT , RespT > call , Metadata headers , ServerCallHandler < ReqT , RespT > next ) {
// your logic here
return next . startCall ( call , headers );
}
};
}
}
บริการเฉพาะนี้ยังมีโอกาสที่จะปิดการใช้งานตัวดักทั่วโลก:
@ GRpcService ( applyGlobalInterceptors = false )
public class GreeterService extends GreeterGrpc . GreeterImplBase {
// ommited
}
สามารถสั่งซื้อตัวสกัดกั้นทั่วโลกได้โดยใช้คำอธิบายประกอบ @Ordered
หรือ @Priority
ของ Spring ตามความหมายของการเรียงลำดับของ Spring ค่าลำดับที่ต่ำกว่าจะมีลำดับความสำคัญสูงกว่า และจะถูกดำเนินการก่อนในห่วงโซ่ดัก
@ GRpcGlobalInterceptor
@ Order ( 10 )
public class A implements ServerInterceptor {
// will be called before B
}
@ GRpcGlobalInterceptor
@ Order ( 20 )
public class B implements ServerInterceptor {
// will be called after A
}
สตาร์ทเตอร์ใช้ตัวดักในตัวเพื่อใช้การจัดการข้อผิดพลาด, Spring Security
, Validation
และการรวม Metrics
คำสั่งซื้อของพวกเขาสามารถควบคุมได้โดยคุณสมบัติด้านล่าง:
grpc.recovery.interceptor-order
(ข้อผิดพลาดในการจัดการคำสั่ง interceptor ค่าเริ่มต้นเป็น Ordered.HIGHEST_PRECEDENCE
)
grpc.security.auth.interceptor-order
(ค่าเริ่มต้นเป็น Ordered.HIGHEST_PRECEDENCE+1
)
grpc.validation.interceptor-order
(ค่าเริ่มต้นเป็น Ordered.HIGHEST_PRECEDENCE+10
)
grpc.metrics.interceptor-order
(ค่าเริ่มต้นเป็น Ordered.HIGHEST_PRECEDENCE+20
)
สิ่งนี้ทำให้คุณสามารถตั้งค่าลำดับที่ต้องการของตัวดักในตัวและตัวดักแบบกำหนดเองของคุณได้
อ่านต่อไป !!! ยังมีอีกมาก
วิธีการทำงานของ grpc interceptor คือดักการโทรและส่งคืน Listener การเรียกของเซิร์ฟเวอร์ ซึ่งสามารถดักจับข้อความคำขอได้เช่นกัน ก่อนที่จะส่งต่อไปยังตัวจัดการการโทรของบริการจริง:
โดยการตั้งค่าคุณสมบัติ grpc.security.auth.fail-fast
เป็น false
interceptors ดาวน์สตรีมทั้งหมดรวมถึง interceptors อัพสตรีมทั้งหมด (On_Message) จะยังคงถูกดำเนินการในกรณีที่การรับรองความถูกต้อง/การอนุญาตล้มเหลว
สมมติว่า interceptor_2
คือ securityInterceptor
:
สำหรับการตรวจสอบสิทธิ์/การอนุญาตที่ล้มเหลวด้วย grpc.security.auth.fail-fast=true
(ค่าเริ่มต้น):
สำหรับการตรวจสอบสิทธิ์/การอนุญาตที่ล้มเหลวด้วย grpc.security.auth.fail-fast=false
:
การเริ่มต้นนี้ ได้ รับการสนับสนุนโดยโปรเจ็กต์ spring-cloud-sleuth
โปรดดำเนินการสืบสวนการบูรณาการ grpc ต่อไป
ด้วยการรวมการพึ่งพา org.springframework.boot:spring-boot-starter-actuator
สตาร์ทเตอร์จะรวบรวมเมตริกเซิร์ฟเวอร์ gRPC ซึ่งแยกย่อยตาม
method
- วิธีการบริการ gRPC FQN (ชื่อที่ผ่านการรับรองครบถ้วน)
result
- รหัสสถานะการตอบสนอง
address
- ที่อยู่ภายในเซิร์ฟเวอร์ (หากคุณเปิดเผยที่อยู่การฟังเพิ่มเติมพร้อมคุณสมบัติ grpc.netty-server.additional-listen-addresses
)
หลังจากกำหนดค่าผู้ส่งออกที่คุณเลือกแล้ว คุณจะเห็น timer
ชื่อ grpc.server.calls
ด้วยการกำหนด GRpcMetricsTagsContributor
bean ในบริบทแอปพลิเคชัน คุณจะสามารถเพิ่มแท็กที่กำหนดเองให้กับตัวจับเวลา grpc.server.calls
ได้
คุณยังสามารถใช้ RequestAwareGRpcMetricsTagsContributor
bean เพื่อแท็กการโทร แบบ unary และ แบบสตรีมมิ่ง ได้
การสาธิตอยู่ที่นี่
รักษาการกระจายตัวให้ต่ำเพื่อไม่ให้ค่าคาร์ดินัลลิตีของเมตริกเพิ่มขึ้น |
RequestAwareGRpcMetricsTagsContributor
ยังคงสามารถดำเนินการได้สำหรับการตรวจสอบสิทธิ์ที่ล้มเหลว หาก Interceptor metric
มีลำดับความสำคัญสูงกว่า Interceptor security
และ grpc.security.auth.fail-fast
ตั้งค่าเป็น false
กรณีนี้ครอบคลุมโดยการทดสอบนี้
อย่าลืมอ่านบทการสั่งซื้อ Interceptors |
ตรวจสอบให้แน่ใจว่าได้รวมการอ้างอิงด้านล่าง:
implementation "org.springframework.boot:spring-boot-starter-actuator"
implementation "io.micrometer:micrometer-registry-prometheus"
implementation 'org.springframework.boot:spring-boot-starter-web'
การกำหนดค่า :
management :
metrics :
export :
prometheus :
enabled : true
endpoints :
web :
exposure :
include : " * "
ตำแหน่งข้อมูล /actuator/metrics
มาตรฐานและ /actuator/prometheus
จะแสดงผลตัววัด grpc.server.calls
(ดูการสาธิตที่นี่)
ข้อเสนอการยกเลิก GRPC |
สามารถกำหนดค่าสตาร์ทเตอร์ได้อัตโนมัติเพื่อตรวจสอบคำขอ/ตอบกลับข้อความบริการ gRPC โปรดดำเนินการตรวจสอบข้อความเพื่อดูรายละเอียดการกำหนดค่า
ตัวเริ่มต้นกำหนด bean ประเภท java.util.function.Consumer
ภายในซึ่งกำลังได้รับการพิจารณาสำหรับการลงทะเบียนฟังก์ชันเมื่อ spring-cloud-stream
อยู่บน classpath ซึ่งไม่พึงประสงค์ ( spring-cloud-stream
จะลงทะเบียนช่องอัตโนมัติหากคุณมี Consumer/Supplier/Function bean หนึ่งรายการในบริบทของแอปพลิเคชัน ดังนั้นคุณจึงมีอยู่แล้วหากคุณใช้ตัวเริ่มต้นนี้ร่วมกับ spring-cloud-stream
)
ตามนี้ ขอแนะนำให้ใช้คุณสมบัติ spring.cloud.function.definition
ในแอปพลิเคชันที่พร้อมใช้งานจริง และไม่ต้องพึ่งพาการค้นพบอัตโนมัติ
โปรดดูการสาธิต GRPC Kafka Stream ส่วนสำคัญคือบรรทัดนี้
สตาร์ทเตอร์ให้การสนับสนุนในตัวสำหรับการตรวจสอบสิทธิ์และการอนุญาตผู้ใช้ที่ใช้ประโยชน์จากการรวมเข้ากับเฟรมเวิร์ก Spring Security
โปรดดูหัวข้อ Spring Security Integration สำหรับรายละเอียดเกี่ยวกับผู้ให้บริการการรับรองความถูกต้องที่รองรับและตัวเลือกการกำหนดค่า
การรักษาความปลอดภัยการขนส่งสามารถกำหนดค่าได้โดยใช้ใบรับรองหลักร่วมกับเส้นทางคีย์ส่วนตัว:
grpc :
security :
cert-chain : classpath:cert/server-cert.pem
private-key : file:../grpc-spring-boot-starter-demo/src/test/resources/cert/server-key.pem
ค่าของคุณสมบัติทั้งสองอยู่ในรูปแบบที่ ResourceEditor รองรับ
ฝั่งไคลเอ็นต์ควรได้รับการกำหนดค่าตาม:
(( NettyChannelBuilder ) channelBuilder )
. useTransportSecurity ()
. sslContext ( GrpcSslContexts . forClient (). trustManager ( certChain ). build ());
สตาร์ทเตอร์นี้จะดึงการพึ่งพา io.netty:netty-tcnative-boringssl-static
เป็นค่าเริ่มต้นเพื่อรองรับ SSL
หากคุณต้องการการสนับสนุน SSL/TLS อื่น โปรดยกเว้นการพึ่งพานี้และปฏิบัติตามคำแนะนำด้านความปลอดภัย
หากจำเป็นต้องมีการปรับแต่งโดยละเอียดเพิ่มเติมสำหรับการตั้งค่าความปลอดภัย โปรดใช้ตัวกำหนดค่าแบบกำหนดเองที่อธิบายไว้ในการกำหนดค่าเซิร์ฟเวอร์ gRPC แบบกำหนดเอง |
หากต้องการสกัดกั้นอินสแตนซ์ io.grpc.ServerBuilder
ที่ใช้ในการสร้าง io.grpc.Server
คุณสามารถเพิ่ม bean ที่สืบทอดจาก org.lognet.springboot.grpc.GRpcServerBuilderConfigurer
ไปยังบริบทของคุณและแทนที่วิธี configure
รองรับการกำหนดค่าหลายตัวด้วย
เมื่อถึงเวลาเรียกใช้วิธี configure
ค่า บริการที่ค้นพบทั้งหมด รวมถึงตัวสกัดกั้น ได้ถูกเพิ่มไปยังตัวสร้างที่ส่งผ่าน
ในการใช้วิธี configure
คุณสามารถเพิ่มการกำหนดค่าที่กำหนดเองได้:
@ Component
public class MyGRpcServerBuilderConfigurer extends GRpcServerBuilderConfigurer {
@ Override
public void configure ( ServerBuilder <?> serverBuilder ){
serverBuilder
. executor ( YOUR EXECUTOR INSTANCE )
. useTransportSecurity ( YOUR TRANSPORT SECURITY SETTINGS );
(( NettyServerBuilder ) serverBuilder ) // cast to NettyServerBuilder (which is the default server) for further customization
. sslContext ( GrpcSslContexts // security fine tuning
. forServer (...)
. trustManager (...)
. build ())
. maxConnectionAge (...)
. maxConnectionAgeGrace (...);
}
};
}
@ Component
public class MyCustomCompressionGRpcServerBuilderConfigurer extends GRpcServerBuilderConfigurer {
@ Override
public void configure ( ServerBuilder <?> serverBuilder ){
serverBuilder
. compressorRegistry ( YOUR COMPRESSION REGISTRY )
. decompressorRegistry ( YOUR DECOMPRESSION REGISTRY ) ;
}
};
}
หากคุณเปิดใช้งานทั้ง NettyServer และเซิร์ฟเวอร์ in-process วิธี configure จะถูกเรียกใช้บนอินสแตนซ์ตัวกำหนดค่าเดียวกันหากคุณต้องการแยกความแตกต่างระหว่าง serverBuilder ที่ส่งผ่าน คุณสามารถตรวจสอบประเภทได้นี่คือข้อจำกัดในปัจจุบัน |
GRpcServerInitializedEvent
ได้รับการเผยแพร่เมื่อเริ่มต้นเซิร์ฟเวอร์ คุณสามารถใช้ได้โดยใช้ Spring API ปกติ
เริ่มต้นจากเวอร์ชัน 5.1.0
spring-boot-starter-gradle-plugin จะรวมปลั๊กอิน protoc protoc ของ SalesForce ไว้ด้วย:
import org.lognet.springboot.grpc.gradle.ReactiveFeature
plugins {
id " io.github.lognet.grpc-spring-boot "
}
grpcSpringBoot {
reactiveFeature . set( ReactiveFeature . REACTOR ) // or ReactiveFeature.RX
}
ต่อไปนี้เป็นการทดสอบและบริการตัวอย่าง grpc แบบโต้ตอบ
สตาร์ทเตอร์จะลงทะเบียน GRpcExceptionHandlerInterceptor
ซึ่งมีหน้าที่เผยแพร่ข้อยกเว้นที่ส่งมาจากบริการไปยังตัวจัดการข้อผิดพลาด
วิธีการจัดการข้อผิดพลาดสามารถลงทะเบียนได้โดยมี @GRpcServiceAdvice
ใส่คำอธิบายประกอบ bean ด้วยวิธีที่มีคำอธิบายประกอบ @GRpcExceptionHandler
สิ่งเหล่านี้ถือเป็นตัวจัดการข้อผิดพลาด global
และวิธีการที่มีพารามิเตอร์ประเภทข้อยกเว้นที่ใกล้ที่สุดตามลำดับชั้นของประเภทไปยังข้อยกเว้นที่ส่งออกจะถูกเรียกใช้
ลายเซ็นของตัวจัดการข้อผิดพลาดต้องเป็นไปตามรูปแบบด้านล่าง:
ประเภทการส่งคืน | พารามิเตอร์ 1 | พารามิเตอร์ 2 |
---|---|---|
io.grpc.สถานะ | ประเภท | GRpcExceptionScope |
@ GRpcServiceAdvice
class MyHandler1 {
@ GRpcExceptionHandler
public Status handle ( MyCustomExcpetion exc , GRpcExceptionScope scope ){
}
@ GRpcExceptionHandler
public Status handle ( IllegalArgumentException exc , GRpcExceptionScope scope ){
}
}
@ GRpcServiceAdvice
class MyHandler2 {
@ GRpcExceptionHandler
public Status anotherHandler ( NullPointerException npe , GRpcExceptionScope scope ){
}
}
คุณสามารถมี advice
bean และวิธีจัดการได้มากเท่าที่คุณต้องการ ตราบใดที่ไม่รบกวนซึ่งกันและกัน และไม่สร้างความคลุมเครือเกี่ยวกับประเภทข้อยกเว้นที่ได้รับการจัดการ
นอกจากนี้ ยังมีการค้นพบ grpc
service bean สำหรับตัวจัดการข้อผิดพลาด ซึ่งมีความสำคัญสูงกว่าวิธีการจัดการข้อผิดพลาดส่วนกลางที่พบใน @GRpcServiceAdvice
beans วิธีการจัดการข้อผิดพลาดระดับบริการถือเป็น private
และเรียกใช้เฉพาะเมื่อบริการ นี้ ส่งข้อยกเว้น:
class SomeException extends Exception {
}
class SomeRuntimeException extends RuntimeException {
}
@ GRpcService
public class HelloService extends GreeterGrpc . GreeterImplBase {
@ Override
public void sayHello ( GreeterOuterClass . HelloRequest request , StreamObserver < GreeterOuterClass . HelloReply > responseObserver ) {
...
throw new GRpcRuntimeExceptionWrapper ( new SomeException ()) ; // (1)
//or
throw new GRpcRuntimeExceptionWrapper ( new SomeException (), "myHint" ); // (2)
//or
throw new SomeRuntimeException (); //(3)
}
@ GRpcExceptionHandler
public Status privateHandler ( SomeException npe , GRpcExceptionScope scope ){
// INVOKED when thrown from HelloService service
String myHint = scope . getHintAs ( String . class ); // (4)
scope . getResponseHeaders (). put ( Metadata . Key . of ( "custom" , Metadata . ASCII_STRING_MARSHALLER ), "Value" ); // (5)
}
@ GRpcExceptionHandler
public Status privateHandler ( SomeRuntimeException npe , GRpcExceptionScope scope ){
// INVOKED when thrown from HelloService service
}
}
@ GRpcServiceAdvice
class MyHandler {
@ GRpcExceptionHandler
public Status anotherHandler ( SomeException npe , GRpcExceptionScope scope ){
// NOT INVOKED when thrown from HelloService service
}
@ GRpcExceptionHandler
public Status anotherHandler ( SomeRuntimeException npe , GRpcExceptionScope scope ){
// NOT INVOKED when thrown from HelloService service
}
}
เนื่องจากลักษณะของ API บริการ grpc
ที่ไม่อนุญาตให้ส่งข้อยกเว้นที่ตรวจสอบ จึงมีการกำหนดประเภทข้อยกเว้นรันไทม์พิเศษไว้เพื่อล้อมข้อยกเว้นที่ตรวจสอบ จากนั้นจะถูกแกะออกเมื่อมองหาวิธีจัดการ
เมื่อส่งข้อยกเว้น GRpcRuntimeExceptionWrapper
คุณยังสามารถส่งวัตถุ hint
ซึ่งสามารถเข้าถึงได้จากวัตถุ scope
ในวิธี handler
สามารถส่งข้อยกเว้นรันไทม์ตามที่เป็นอยู่และไม่จำเป็นต้องปิดล้อม
รับวัตถุคำใบ้
ส่งส่วนหัวที่กำหนดเองไปยังไคลเอนต์
ความล้มเหลวในการตรวจสอบสิทธิ์ถูกเผยแพร่ผ่าน AuthenticationException
และความล้มเหลวในการอนุญาต - ผ่าน AccessDeniedException
ความล้มเหลวในการตรวจสอบถูกเผยแพร่ผ่าน ConstraintViolationException
: สำหรับคำขอที่ล้มเหลว - โดยมี Status.INVALID_ARGUMENT
เป็นคำใบ้ และสำหรับการตอบกลับที่ล้มเหลว - โดยมี Status.FAILED_PRECONDITION
เป็นคำใบ้
การสาธิตอยู่ที่นี่
ต้องขอบคุณการสนับสนุนการกำหนดค่า Bean Validation ผ่านทางตัวอธิบายการปรับใช้ XML จึงเป็นไปได้ที่จะจัดเตรียมข้อจำกัดสำหรับคลาสที่สร้างขึ้นผ่าน XML แทนที่จะกำหนดเครื่องมือข้อความที่สร้างขึ้นด้วยคอม protoc
ที่กำหนดเอง
เพิ่ม org.springframework.boot:spring-boot-starter-validation
dependency ให้กับโปรเจ็กต์ของคุณ
สร้างไฟล์ META-INF/validation.xml
และประกาศข้อจำกัด (IntelliJ IDEA มีการสนับสนุนการเติมข้อความอัตโนมัติที่ยอดเยี่ยมสำหรับการอนุญาตไฟล์ xml ข้อ จำกัด การตรวจสอบถั่ว)
ดูตัวอย่างจากเอกสารประกอบตัวตรวจสอบความถูกต้อง Hibernate
คุณสามารถดูการกำหนดค่าสาธิตและการทดสอบที่เกี่ยวข้องได้ที่นี่
โปรดทราบว่าทั้ง request
และข้อความ response
กำลังได้รับการตรวจสอบ
หากวิธี gRPC ของคุณใช้ข้อความคำขอและข้อความตอบกลับประเภทเดียวกัน คุณสามารถใช้กลุ่มการตรวจสอบความถูกต้อง org.lognet.springboot.grpc.validation.group.RequestMessage
และ org.lognet.springboot.grpc.validation.group.ResponseMessage
เพื่อใช้ตรรกะการตรวจสอบที่แตกต่างกัน : :
...
< getter name = " someField " >
<!-- should be empty for request message -->
< constraint annotation = " javax.validation.constraints.Size " >
< groups >
< value >org.lognet.springboot.grpc.validation.group.RequestMessage</ value > (1)
</ groups >
< element name = " min " >0</ element >
< element name = " max " >0</ element >
</ constraint >
<!-- should NOT be empty for response message -->
< constraint annotation = " javax.validation.constraints.NotEmpty " >
< groups >
< value >org.lognet.springboot.grpc.validation.group.ResponseMessage</ value > (2)
</ groups >
</ constraint >
</ getter >
...
ใช้ข้อจำกัดนี้สำหรับข้อความ request
เท่านั้น
ใช้ข้อจำกัดนี้สำหรับข้อความ response
เท่านั้น
หมายเหตุถึงข้อ จำกัด ข้ามฟิลด์ที่กำหนดเองและการใช้งาน:
< bean class = " io.grpc.examples.GreeterOuterClass$Person " >
< class >
< constraint annotation = " org.lognet.springboot.grpc.demo.PersonConstraint " />
</ class >
<!-- ... -->
</ bean >
ตามที่อธิบายไว้ในบทการเรียงลำดับ Interceptors คุณสามารถกำหนดให้ validation
interceptor มีลำดับความสำคัญสูงกว่า security
interceptor และตั้งค่าคุณสมบัติ grpc.security.auth.fail-fast
เป็น false
ในสถานการณ์สมมตินี้ ถ้าการโทรทั้งไม่ได้รับการรับรองความถูกต้องและไม่ถูกต้อง ไคลเอ็นต์จะได้รับ Status.INVALID_ARGUMENT
แทนสถานะการตอบสนอง Status.PERMISSION_DENIED/Status.UNAUTHENTICATED
การสาธิตอยู่ที่นี่
แม้ว่าจะยังเป็นไปได้ที่จะให้วิธี rpc ของคุณมีคำอธิบายประกอบด้วย @Transactional
(ด้วย spring.aop.proxy-target-class=true
หากไม่ได้เปิดใช้งานตามค่าเริ่มต้น) ก็มีโอกาสที่จะมีพฤติกรรมที่คาดเดาไม่ได้ พิจารณาการใช้วิธี grpc ด้านล่าง:
@ GRpcService
class MyGrpcService extends ...{
@ Autowired
private MyJpaRepository repo ;
@ Transactional //(1)
public void rpcCall ( Req request , StreamOvserver < Res > observer ) {
Res response = // Database operations via repo
observer . onNext ( response ); //(2)
observer . onCompleted ();
} //(3)
}
วิธีการนี้มีคำอธิบายประกอบเป็น @Transactional
โดย Spring จะทำธุรกรรม ในบางครั้งหลังจากที่เมธอดส่งคืน
การตอบสนองจะถูกส่งกลับไปยังผู้โทร
วิธีการส่งคืนธุรกรรมที่กระทำ ในที่สุด
ตามทฤษฎีและอย่างที่คุณเห็น - ในทางปฏิบัติมีช่วงเวลาเล็กน้อยเมื่อไคลเอนต์ (หากเวลาแฝงของเครือข่ายน้อยที่สุดและเซิร์ฟเวอร์ grpc ของคุณสนับสนุนการสลับบริบททันทีหลังจาก <2>) สามารถลองเข้าถึงฐานข้อมูลผ่านการเรียก grpc อื่น ก่อน การทำธุรกรรมเกิดขึ้น
วิธีแก้ปัญหาเพื่อเอาชนะสถานการณ์นี้คือการแปลงตรรกะของธุรกรรมภายนอกเป็นคลาสบริการที่แยกจากกัน:
@ Service
class MyService {
@ Autowired
private MyJpaRepository repo ;
@ Transactional //(1)
public Res doTransactionalWork (){
// Database operations via repo
return result ;
} //(2)
}
@ GRpcService
class MyGrpcService extends ...{
@ Autowired
private MyService myService ;
public void rpcCall ( Req request , StreamOvserver < Res > observer ) {
Res response = myService . doTransactionalWork ();
observer . onNext ( response ); //(3)
observer . onCompleted ();
}
}
วิธีการบริการเป็นแบบธุรกรรม
ธุรกรรมมีความมุ่งมั่น ในที่สุด
ตอบกลับ หลังจาก การทำธุรกรรมเกิดขึ้น
เมื่อปฏิบัติตามแนวทางนี้ คุณจะแยกเลเยอร์การขนส่งและตรรกะทางธุรกิจที่สามารถทดสอบแยกกันได้ในขณะนี้
โครงการ | การพึ่งพาอาศัยกัน |
---|---|
ขั้นพื้นฐาน |
|
ผู้ถือ |
|
กำหนดเอง |
|
การกำหนดค่าความปลอดภัย GRPC เป็นไปตามหลักการและ API เดียวกันกับการกำหนดค่าความปลอดภัยของ Spring WEB โดยจะเปิดใช้งานตามค่าเริ่มต้นหากคุณมีการพึ่งพา org.springframework.security:spring-security-config
ใน classpath ของคุณ
คุณสามารถใช้คำอธิบายประกอบ @Secured
บนบริการ/วิธีการเพื่อปกป้องตำแหน่งข้อมูลของคุณ หรือโดยใช้ API และการแทนที่ค่าเริ่มต้น (ซึ่งอยู่ข้างหน้าคำอธิบายประกอบ @Secured
):
@ Configuration
class MySecurityCfg extends GrpcSecurityConfigurerAdapter {
@ Override
public void configure ( GrpcSecurity builder ) throws Exception {
MethodsDescriptor <?,?> adminMethods = MyServiceGrpc . getSomeMethod ();
builder
. authorizeRequests ()
. methods ( adminMethods ). hasAnyRole ( "admin" )
. anyMethodExcluding ( adminMethods ). hasAnyRole ( "user" )
. withSecuredAnnotation ();( 1 )
}
}
หรือรวม API
เข้ากับคำอธิบายประกอบ @Secured
การกำหนดค่าเริ่มต้นนี้จะรักษาความปลอดภัยวิธีการ/บริการ GRPC ที่มีคำอธิบายประกอบด้วย org.springframework.security.access.annotation.@Secured
การปล่อยให้ค่าของคำอธิบายประกอบว่างเปล่า ( @Secured({})
) หมายถึง : authenticate
เท่านั้น ไม่มีการอนุญาตใด ๆ เกิดขึ้น
หาก JwtDecoder
bean มีอยู่ในบริบทของคุณ มันจะลงทะเบียน JwtAuthenticationProvider
เพื่อจัดการการตรวจสอบความถูกต้องของการอ้างสิทธิ์การรับรองความถูกต้องด้วย
BasicAuthSchemeSelector
และ BearerTokenAuthSchemeSelector
จะได้รับการลงทะเบียนโดยอัตโนมัติเพื่อรองรับการตรวจสอบสิทธิ์ด้วยชื่อผู้ใช้/รหัสผ่าน และโทเค็นผู้ถือ
เมื่อตั้งค่า grpc.security.auth.enabled
เป็น false
คุณจะสามารถปิดการรักษาความปลอดภัย GRPC ได้
การปรับแต่งการกำหนดค่าความปลอดภัย GRPC ทำได้โดยการขยาย GrpcSecurityConfigurerAdapter
(ตัวอย่างการกำหนดค่าต่างๆ และสถานการณ์การทดสอบอยู่ที่นี่)
@ Configuration
public class GrpcSecurityConfiguration extends GrpcSecurityConfigurerAdapter {
@ Autowired
private JwtDecoder jwtDecoder ;
@ Override
public void configure ( GrpcSecurity builder ) throws Exception {
builder . authorizeRequests ()( 1 )
. methods ( GreeterGrpc . getSayHelloMethod ()). hasAnyAuthority ( "SCOPE_profile" )( 2 )
. and ()
. authenticationProvider ( JwtAuthProviderFactory . withAuthorities ( jwtDecoder ));( 3 )
}
}
รับวัตถุการกำหนดค่าการอนุญาต
MethodDefinition
ของเมธอด sayHello
ได้รับอนุญาตสำหรับผู้ใช้ที่ได้รับการรับรองความถูกต้องด้วยสิทธิ์ SCOPE_profile
ใช้ JwtAuthenticationProvider
เพื่อตรวจสอบการอ้างสิทธิ์ของผู้ใช้ (โทเค็น BEARER
) กับเซิร์ฟเวอร์ทรัพยากรที่กำหนดค่าด้วยคุณสมบัติ spring.security.oauth2.resourceserver.jwt.issuer-uri
คุณสามารถเสียบผู้ให้บริการตรวจสอบความถูกต้องตามความต้องการของคุณเองได้โดยใช้อินเทอร์เฟซ AuthenticationSchemeSelector
@ Configuration
public class GrpcSecurityConfiguration extends GrpcSecurityConfigurerAdapter {
@ Override
public void configure ( GrpcSecurity builder ) throws Exception {
builder . authorizeRequests ()
. anyMethod (). authenticated () //(1)
. and ()
. authenticationSchemeSelector ( new AuthenticationSchemeSelector () { //(2)
@ Override
public Optional < Authentication > getAuthScheme ( CharSequence authorization ) {
return new MyAuthenticationObject (); // (3)
}
})
. authenticationProvider ( new AuthenticationProvider () { // (4)
@ Override
public Authentication authenticate ( Authentication authentication ) throws AuthenticationException {
MyAuthenticationObject myAuth = ( MyAuthenticationObject ) authentication ;
//validate myAuth
return MyValidatedAuthenticationObject ( withAuthorities ); //(5)
}
@ Override
public boolean supports ( Class <?> authentication ) {
return MyAuthenticationObject . class . isInstance ( authentication );
}
});
}
}
รักษาความปลอดภัยวิธีการบริการทั้งหมด
ลงทะเบียน AuthenticationSchemeSelector
ของคุณเอง
ตามส่วนหัวการอนุญาตที่ให้มา - ส่งคืนออบเจ็กต์ Authentication
เป็นการอ้างสิทธิ์ (ยังไม่ได้รับการรับรองความถูกต้อง)
ลงทะเบียน AuthenticationProvider
ของคุณเองที่รองรับการตรวจสอบ MyAuthenticationObject
ตรวจสอบ authentication
ที่ให้มาและส่งคืนออบเจ็กต์ Authentication
รับรองความถูกต้องที่ผ่านการตรวจสอบและ รับรองความถูกต้องแล้ว
AuthenticationSchemeSelector
สามารถลงทะเบียนได้โดยกำหนด Spring bean ในบริบทแอปพลิเคชันของคุณ:
@ Bean
public AuthenticationSchemeSelector myCustomSchemeSelector (){
return authHeader ->{
// your logic here
};
}
ส่วนสนับสนุนการกำหนดค่าฝั่งไคลเอ็นต์จะอธิบายวิธีส่งแผนการอนุญาตที่กำหนดเองและการอ้างสิทธิ์จากไคลเอนต์ GRPC
เริ่มต้นจากเวอร์ชัน 4.5.9
คุณยังสามารถใช้คำอธิบายประกอบ @PreAuthorize
และ @PostAuthorize
มาตรฐานเกี่ยวกับวิธีการบริการ grpc และประเภทบริการ grpc
ประเภทการโทร | การอ้างอิงวัตถุอินพุต | การอ้างอิงวัตถุเอาท์พุต | ตัวอย่าง |
---|---|---|---|
อูนารี | ตามชื่อพารามิเตอร์ | | @ Override
@ PreAuthorize ( "#person.age<12" )
@ PostAuthorize ( "returnObject.description.length()>0" )
public void unary ( Person person , StreamObserver < Assignment > responseObserver ) {
} |
สตรีมอินพุต | | | @ Override
@ PreAuthorize ( "#p0.getAge()<12" )
@ PostAuthorize ( "returnObject.description.length()>0" )
public StreamObserver < Person > inStream ( StreamObserver < Assignment > responseObserver ) {
} |
คำขอเดียว | ตามชื่อพารามิเตอร์ | | @ Override
@ PreAuthorize ( "#person.age<12" )
@ PostAuthorize ( "returnObject.description.length()>0" )
public void outStream ( Person person , StreamObserver < Assignment > responseObserver ) {
} |
สตรีมบีดี | | | @ Override
@ PreAuthorize ( "#p0.age<12" )
@ PostAuthorize ( "returnObject.description.length()>0" )
public StreamObserver < Person > bidiStream ( StreamObserver < Assignment > responseObserver ) {
} |
หากต้องการรับออบเจ็กต์ Authentication
ในการใช้งาน วิธีที่ปลอดภัย โปรดใช้ข้อมูลโค้ดด้านล่าง
final Authentication auth = GrpcSecurity . AUTHENTICATION_CONTEXT_KEY . get ();
เริ่มต้นจาก 4.5.6
สามารถรับวัตถุ Authentication
ผ่าน Spring API มาตรฐานได้:
final Authentication auth = SecurityContextHolder . getContext (). getAuthentication ();
ด้วยการเพิ่มการพึ่งพา io.github.lognet:grpc-client-spring-boot-starter
ให้กับแอปพลิเคชัน ไคลเอนต์ java grpc ของคุณ คุณสามารถกำหนดค่าข้อมูลประจำตัวต่อช่องหรือต่อการโทรได้อย่างง่ายดาย:
class MyClient {
public void doWork (){
final AuthClientInterceptor clientInterceptor = new AuthClientInterceptor (( 1 )
AuthHeader . builder ()
. bearer ()
. binaryFormat ( true )( 3 )
. tokenSupplier ( this :: generateToken )( 4 )
);
Channel authenticatedChannel = ClientInterceptors . intercept (
ManagedChannelBuilder . forAddress ( "host" , 6565 ). build (), clientInterceptor ( 2 )
);
// use authenticatedChannel to invoke GRPC service
}
private ByteBuffer generateToken (){ ( 4 )
// generate bearer token against your resource server
}
}
สร้างตัวสกัดกั้นไคลเอนต์
สกัดกั้นช่อง
เปิด/ปิดรูปแบบไบนารี:
เมื่อ true
ส่วนหัวการรับรองความถูกต้องจะถูกส่งไปพร้อมกับคีย์ Authorization-bin
โดยใช้ไบนารีมาร์แชลเลอร์
เมื่อเป็น false
ส่วนหัวการพิสูจน์ตัวตนจะถูกส่งไปพร้อมกับคีย์ Authorization
โดยใช้ ASCII marshaller
จัดเตรียมฟังก์ชันตัวสร้างโทเค็น (โปรดดูตัวอย่าง)
class MyClient {
public void doWork (){
AuthCallCredentials callCredentials = new AuthCallCredentials ( ( 1 )
AuthHeader . builder (). basic ( "user" , "pwd" . getBytes ())
);
final SecuredGreeterGrpc . SecuredGreeterBlockingStub securedFutureStub = SecuredGreeterGrpc . newBlockingStub ( ManagedChannelBuilder . forAddress ( "host" , 6565 ));( 2 )
final String reply = securedFutureStub
. withCallCredentials ( callCredentials )( 3 )
. sayAuthHello ( Empty . getDefaultInstance ()). getMessage ();
}
}
สร้างข้อมูลรับรองการโทรด้วยรูปแบบพื้นฐาน
สร้างต้นขั้วบริการ
แนบข้อมูลรับรองการโทรเข้ากับการโทร
AuthHeader
สามารถสร้างได้ด้วยรูปแบบการอนุญาตแบบ bespoke:
AuthHeader
. builder ()
. authScheme ( "myCustomAuthScheme" )
. tokenSupplier (()-> generateMyCustomToken ())
สตาร์ทเตอร์ลงทะเบียนการใช้งานเริ่มต้นของ HealthServiceImpl
คุณสามารถให้คุณเป็นเจ้าของได้โดยการลงทะเบียน ManagedHealthStatusService bean ในบริบทของแอปพลิเคชันของคุณ
หากคุณมี org.springframework.boot:spring-boot-starter-actuator
และ org.springframework.boot:spring-boot-starter-web
ใน classpath สตาร์ทเตอร์จะแสดง:
ตัวบ่งชี้สุขภาพ grpc
ภายใต้ /actuator/health
endpoint
/actuator/grpc
ซึ่งสามารถควบคุมได้โดยจุดสิ้นสุดมาตรฐานและการกำหนดค่าความสมบูรณ์
เริ่มต้นจากเวอร์ชัน 3.3.0
สตาร์ทเตอร์จะลงทะเบียนเซิร์ฟเวอร์ grpc ที่ทำงานอยู่ในรีจิสทรีกงสุลโดยอัตโนมัติ หาก org.springframework.cloud:spring-cloud-starter-consul-discovery
อยู่ใน classpath และ spring.cloud.service-registry.auto-registration.enabled
ไม่ได้ ตั้งค่าเป็น false
ชื่อบริการที่ลงทะเบียนจะถูกนำหน้าด้วย grpc-
เช่น grpc-${spring.application.name}
เพื่อไม่ให้รบกวนชื่อบริการเว็บมาตรฐานที่ลงทะเบียน หากคุณเลือกที่จะรันทั้ง Grpc
และ Web
เซิร์ฟเวอร์แบบฝัง
ConsulDiscoveryProperties
ถูกผูกไว้จากคุณสมบัติการกำหนดค่าที่นำหน้าโดย spring.cloud.consul.discovery
จากนั้นค่าจะถูกเขียนทับด้วยคุณสมบัติที่นำหน้า grpc.consul.discovery
(หากตั้งค่าไว้) ซึ่งจะทำให้คุณมีการกำหนดค่าการค้นหากงสุลแยกต่างหากสำหรับ rest
และบริการ grpc
หากคุณเลือกที่จะเปิดเผยทั้งสองอย่างจากแอปพลิเคชันของคุณ
spring :
cloud :
consul :
discovery :
metadata :
myKey : myValue (1)
tags :
- myWebTag (2)
grpc :
consul :
discovery :
tags :
- myGrpcTag (3)
ทั้งบริการ rest
และ grpc
ได้รับการลงทะเบียนด้วยข้อมูลเมตา myKey=myValue
บริการที่เหลือได้รับการลงทะเบียนกับ myWebTag
บริการ Grpc ได้รับการลงทะเบียนกับ myGrpcTag
การตั้งค่า spring.cloud.consul.discovery.register-health-check
(หรือ grpc.consul.discovery.register-health-check
) เป็น true
จะลงทะเบียนบริการตรวจสุขภาพ GRPC กับกงสุล
มีโหมดการลงทะเบียนที่รองรับ 4 โหมด:
SINGLE_SERVER_WITH_GLOBAL_CHECK
(ค่าเริ่มต้น)
ในโหมดนี้ เซิร์ฟเวอร์ grpc ที่ทำงานอยู่จะถูกลงทะเบียนเป็นบริการเดียวโดยมีการตรวจสอบ grpc
เดียวโดยไม่มี serviceId
โปรดทราบว่าการใช้งานเริ่มต้นไม่ได้ทำอะไรเลย และเพียงแค่ส่งกลับสถานะ SERVING
คุณอาจต้องการจัดเตรียมการใช้งานการตรวจสุขภาพแบบกำหนดเองสำหรับโหมดนี้
SINGLE_SERVER_WITH_CHECK_PER_SERVICE
ในโหมดนี้ เซิร์ฟเวอร์ grpc ที่ทำงานอยู่จะถูกลงทะเบียนเป็นบริการเดียวพร้อมการตรวจสอบต่อบริการ grpc
ที่ค้นพบแต่ละรายการ
STANDALONE_SERVICES
ในโหมดนี้ แต่ละบริการ grpc ที่ค้นพบจะถูกลงทะเบียนเป็นบริการเดียวด้วยการตรวจสอบครั้งเดียว บริการที่ลงทะเบียนแต่ละรายการจะถูกแท็กด้วยชื่อบริการของตัวเอง
NOOP
- ไม่มีการลงทะเบียนบริการ grpc โหมดนี้มีประโยชน์หากคุณให้บริการทั้ง rest
และบริการ grpc
ในใบสมัครของคุณ แต่ด้วยเหตุผลบางประการ ควรลงทะเบียนเฉพาะบริการ rest
กับกงสุลเท่านั้น
grpc :
consule :
registration-mode : SINGLE_SERVER_WITH_CHECK_PER_SERVICE
เมื่อสร้างบริการที่พร้อมสำหรับการใช้งานจริง คำแนะนำคือให้มีโปรเจ็กต์แยกต่างหากสำหรับบริการ gRPC API ของคุณซึ่งมีเฉพาะคลาสที่สร้างโปรโตเท่านั้นสำหรับการใช้งานฝั่งเซิร์ฟเวอร์และไคลเอนต์
จากนั้น คุณจะเพิ่มโปรเจ็กต์นี้เป็นการพึ่งพา implementation
กับโปรเจ็กต์ gRPC client
และ gRPC server
ของคุณ
หากต้องการบูรณา Eureka
เพียงทำตามคำแนะนำที่ดีจาก Spring
ด้านล่างนี้เป็นส่วนสำคัญของการกำหนดค่าสำหรับทั้งโปรเจ็กต์เซิร์ฟเวอร์และไคลเอนต์
เพิ่ม eureka Starter เป็นการพึ่งพาของโปรเจ็กต์เซิร์ฟเวอร์ของคุณพร้อมกับคลาสที่สร้างจากไฟล์ proto
:
dependencies {
implementation( ' org.springframework.cloud:spring-cloud-starter-eureka ' )
implementation project( " :yourProject-api " )
}
กำหนดค่าเซิร์ฟเวอร์ gRPC เพื่อลงทะเบียนตัวเองกับ Eureka
spring :
application :
name : my-service-name (1)
ServiceId
ของ Eureka ตามค่าเริ่มต้นคือชื่อแอปพลิเคชัน Spring โปรดระบุก่อนที่บริการจะลงทะเบียนตัวเองกับ Eureka
grpc :
port : 6565 (1)
eureka :
instance :
nonSecurePort : ${grpc.port} (2)
client :
serviceUrl :
defaultZone : http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ (3)
ระบุหมายเลขพอร์ตที่ gRPC กำลังรับฟัง
ลงทะเบียนพอร์ตบริการ eureka ให้เหมือนกับ grpc.port
เพื่อให้ลูกค้าทราบว่าจะส่งคำขอไปที่ใด
ระบุ URL การลงทะเบียน เพื่อที่บริการจะลงทะเบียนตัวเองด้วย
เปิดเผยบริการ gRPC โดยเป็นส่วนหนึ่งของ Spring Boot Application
@ SpringBootApplication
@ EnableEurekaClient
public class EurekaGrpcServiceApp {
@ GRpcService
public static class GreeterService extends GreeterGrpc . GreeterImplBase {
@ Override
public void sayHello ( GreeterOuterClass . HelloRequest request , StreamObserver < GreeterOuterClass . HelloReply > responseObserver ) {
}
}
public static void main ( String [] args ) {
SpringApplication . run ( DemoApp . class , args );
}
}
เพิ่ม eureka Starter เป็นการพึ่งพาของโปรเจ็กต์ไคลเอนต์ของคุณพร้อมกับคลาสที่สร้างขึ้นจากไฟล์ proto
:
dependencies {
implementation( ' org.springframework.cloud:spring-cloud-starter-eureka ' )
implementation project( " :yourProject-api " )
}
กำหนดค่าไคลเอ็นต์เพื่อค้นหารีจิสทรีบริการ eureka:
eureka :
client :
register-with-eureka : false (1)
service-url :
defaultZone : http://${eureka.host:localhost}:${eureka.port:8761}/eureka/ (2)
false
หากโปรเจ็กต์นี้ไม่ได้มีวัตถุประสงค์เพื่อทำหน้าที่เป็นบริการให้กับลูกค้ารายอื่น
ระบุ URL รีจิสทรี เพื่อให้ไคลเอ็นต์ทราบว่าจะค้นหาบริการที่ต้องการได้ที่ไหน
@ EnableEurekaClient
@ SpringBootApplication
public class GreeterServiceConsumerApplication {
public static void main ( String [] args ) {
SpringApplication . run ( GreeterServiceConsumerApplication . class , args );
}
}
ใช้ EurekaClient เพื่อรับพิกัดของอินสแตนซ์บริการ gRPC จาก Eureka และใช้บริการ:
@ EnableEurekaClient
@ Component
public class GreeterServiceConsumer {
@ Autowired
private EurekaClient client ;
public void greet ( String name ) {
final InstanceInfo instanceInfo = client . getNextServerFromEureka ( "my-service-name" , false ); //(1)
final ManagedChannel channel = ManagedChannelBuilder . forAddress ( instanceInfo . getIPAddr (), instanceInfo . getPort ())
. usePlaintext ()
. build (); //(2)
final GreeterServiceGrpc . GreeterServiceFutureStub stub = GreeterServiceGrpc . newFutureStub ( channel ); //(3)
stub . greet ( name ); //(4)
}
}
รับข้อมูลเกี่ยวกับอินสแตนซ์ my-service-name
สร้าง channel
ตามนั้น
สร้างต้นขั้วโดยใช้ channel
เรียกใช้บริการ
อาปาเช่ 2.0