JDK 11ãKotlinãSpring 5ãSpring Boot 2ãGradle 5ãæ¬çªå¯Ÿå¿ã®Kotlin DSLãJUnit 5ãããã³ãµãŒãã¹æ€åºãã²ãŒããŠã§ã€APIã®äœæãã¯ã©ã€ã¢ã³ããã©ã³ã·ã³ã°ããµãŒããããã¬ãŒã«ãŒãã¿ãŒã³ã®å®è£
ã®ããã®åããŒã¹ã®Spring Cloudã¹ã¿ãã¯ã©ã€ãã©ãªããããŸãã宣èšçãªHTTPã¯ã©ã€ã¢ã³ãã忣ãã¬ãŒã¹ãªã©ãäœæããŸãã ãã®ãã¹ãŠããã€ã¯ããµãŒãã¹ã¢ãŒããã¯ãã£ãäœæããããã«å¿
èŠã ã£ãããã§ã¯ãããŸãã-楜ãã¿ã®ããã ãã«...ãšã³ããªãŒ
ãã®èšäºã§ã¯ãJavaã®äžçã§é¢é£ãããã¯ãããžãŒã䜿çšãããã€ã¯ããµãŒãã¹ã¢ãŒããã¯ãã£ã®äŸã玹ä»ããŸãããã®äž»ãªãã®ã以äžã«ç€ºããŸãïŒãããã®ããŒãžã§ã³ã¯ãçºè¡æã«ãããžã§ã¯ãã§äœ¿çšãããŠããŸãïŒã
ãã®ãããžã§ã¯ãã¯ã5ã€ã®ãã€ã¯ããµãŒãã¹ã§æ§æãããŸãã3ã€ã®ã€ã³ãã©ã¹ãã©ã¯ãã£ïŒæ§æãµãŒããŒããµãŒãã¹æ€åºãµãŒããŒãUIã²ãŒããŠã§ã€ïŒãããã³ããã³ããšã³ãïŒã¢ã€ãã UIïŒãšããã¯ãšã³ãïŒã¢ã€ãã ãµãŒãã¹ïŒã®äŸïŒ
ãããã¯ãã¹ãŠã以äžã§é 次æ€èšãããŸãã ãæŠéããããžã§ã¯ãã§ã¯ãæããã«ãããžãã¹æ©èœãå®è£
ãããã€ã¯ããµãŒãã¹ã倧å¹
ã«å¢ããŸãã ãããããã®ãããªã¢ãŒããã¯ãã£ã«è¿œå ããããšã¯ãæè¡çã«ã¯ã¢ã€ãã UIããã³ã¢ã€ãã ãµãŒãã¹ãšåãæ¹æ³ã§è¡ãããŸãã
å
責äºé
ãã®èšäºã§ã¯ãã³ã³ããåãšãªãŒã±ã¹ãã¬ãŒã·ã§ã³ã®ææ®µã«ã€ããŠã¯èæ
®ããŠããŸãããçŸæç¹ã§ã¯ããããã¯ãããžã§ã¯ãã§äœ¿çšãããŠããªãããã§ãã
æ§æãµãŒããŒ
Spring Cloud Configã䜿çšããŠãã¢ããªã±ãŒã·ã§ã³æ§æã®éäžãªããžããªãäœæããŸããã æ§æã¯ããŸããŸãªãœãŒã¹ããèªã¿åãããšãã§ããŸããããšãã°ãå¥åã®gitãªããžããªãŒã ã·ã³ãã«ããšæç¢ºãã®ããã«ããããã¯ãã®ãããžã§ã¯ãã®ã¢ããªã±ãŒã·ã§ã³ãªãœãŒã¹ã«ãããŸãã
ãã®å Žåãæ§æãµãŒããŒïŒ
application.yml
ïŒèªäœã®æ§æã¯æ¬¡ã®ããã«ãªããŸãã
spring: profiles: active: native cloud: config: server: native: search-locations: classpath:/config server: port: 8888
ããŒã8888ã䜿çšãããšãConfigãµãŒããŒã¯ã©ã€ã¢ã³ãã
bootstrap.yml
ããŒããæç€ºçã«æå®ããªãããã«ã§ããŸãã èµ·åæã«ãHTTP APIæ§æãµãŒããŒã«GETãªã¯ãšã¹ããå®è¡ããŠãæ§æãã¢ããããŒãããŸãã
ãã®ãã€ã¯ããµãŒãã¹ã®ããã°ã©ã ã³ãŒãã¯ãã¢ããªã±ãŒã·ã§ã³ã¯ã©ã¹ãšã¡ã€ã³ã¡ãœããã®å®£èšãå«ã1ã€ã®ãã¡ã€ã«ã®ã¿ã§æ§æãããŸããã¡ã€ã³ã¡ãœããã¯ãåçã®Javaã³ãŒããšã¯ç°ãªãããããã¬ãã«ã®é¢æ°ã§ãã
@SpringBootApplication @EnableConfigServer class ConfigServerApplication fun main(args: Array<String>) { runApplication<ConfigServerApplication>(*args) }
ä»ã®ãã€ã¯ããµãŒãã¹ã®ã¢ããªã±ãŒã·ã§ã³ã¯ã©ã¹ãšã¡ã€ã³ã¡ãœããã®å€èгã¯äŒŒãŠããŸãã
ãµãŒãã¹æ€åºãµãŒããŒ
ãµãŒãã¹æ€åºã¯ãã€ã³ã¹ã¿ã³ã¹ã®æ°ãšãããã¯ãŒã¯ã®å Žæã倿Žãããå¯èœæ§ãããå Žåã«ãã¢ããªã±ãŒã·ã§ã³éã®çžäºäœçšãç°¡çŽ åã§ãããã€ã¯ããµãŒãã¹ã¢ãŒããã¯ãã£ãã¿ãŒã³ã§ãã ãã®ã¢ãããŒãã®éèŠãªã³ã³ããŒãã³ãã¯ããµãŒãã¹ã¬ãžã¹ããª-ãã€ã¯ããµãŒãã¹ããã®ã€ã³ã¹ã¿ã³ã¹ãããã³ãããã¯ãŒã¯ãã±ãŒã·ã§ã³ã®ããŒã¿ããŒã¹ã§ãïŒè©³çްã¯
ãã¡ã ïŒã
ãã®ãããžã§ã¯ãã§ã¯ã
ã¯ã©ã€ã¢ã³ãåŽã®ãµãŒãã¹æ€åºã§ããNetflix Eurekaã«åºã¥ããŠãµãŒãã¹æ€åºãå®è£
ãããŸãïŒEurekaãµãŒããŒã¯ãµãŒãã¹ã¬ãžã¹ããªã®æ©èœãå®è¡ããEurekaã¯ã©ã€ã¢ã³ãã¯ãã€ã¯ããµãŒãã¹ãžã®ãªã¯ãšã¹ããå®è¡ããåã«ãåŒã³åºãããã¢ããªã±ãŒã·ã§ã³ã®ã€ã³ã¹ã¿ã³ã¹ã®ãªã¹ããæ±ããŠEurekaãµãŒããŒã«æ¥ç¶ããç¬ç«ããŠãã©ã³ã¹ãå®è¡ããŸãããŒãïŒNetflixãªãã³ã䜿çšïŒã Netflix Eurekaã¯ãä»ã®Netflix OSSã¹ã¿ãã¯ã³ã³ããŒãã³ãïŒHystrixãRibbonãªã©ïŒãšåæ§ã«ã
Spring Cloud Netflixã䜿çšããŠSpring Bootã¢ããªã±ãŒã·ã§ã³ãšçµ±åããŸãã
ãªãœãŒã¹ïŒ
bootstrap.yml
ïŒã«ãããµãŒãã¹æ€åºãµãŒããŒã®æ§æã§ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ååãšãæ§æãµãŒããŒã«æ¥ç¶ã§ããªãå Žåã«ãã€ã¯ããµãŒãã¹ã®éå§ãäžæãããããšã瀺ããã©ã¡ãŒã¿ãŒã®ã¿ã瀺ãããŸãã
spring: application: name: eureka-server cloud: config: fail-fast: true
æ®ãã®ã¢ããªã±ãŒã·ã§ã³æ§æã¯ãæ§æãµãŒããŒãªãœãŒã¹ã®
eureka-server.yml
ã«ãããŸãã
server: port: 8761 eureka: client: register-with-eureka: true fetch-registry: false
EurekaãµãŒããŒã¯ããŒã8761ã䜿çšããŸããããã«ããããã¹ãŠã®Eurekaã¯ã©ã€ã¢ã³ãã¯ããã©ã«ãå€ã䜿çšããŠæå®ã§ããªããªããŸãã
register-with-eureka
ïŒãããããããããããããã©ã«ãã§äœ¿çšãããããïŒã¯ãä»ã®ãã€ã¯ããµãŒãã¹ãšåæ§ã«ãã¢ããªã±ãŒã·ã§ã³èªäœãEurekaãµãŒããŒã«ç»é²ãããããšãæå³ããŸãã
fetch-registry
ãã©ã¡ãŒã¿ãŒã¯ãEurekaã¯ã©ã€ã¢ã³ãããµãŒãã¹ã¬ãžã¹ããªããããŒã¿ãåä¿¡ãããã©ãããæ±ºå®ããŸãã
ç»é²æžã¿ã¢ããªã±ãŒã·ã§ã³ã®ãªã¹ãããã³ãã®ä»ã®æ
å ±ã¯ã
http://localhost:8761/
å
¥æã§ããŸãã
ãµãŒãã¹æ€åºãå®è£
ããããã®ä»£æ¿ææ®µã¯ãConsulãZookeeperãªã©ã§ãã
ã¢ã€ãã ãµãŒãã¹
ãã®ã¢ããªã±ãŒã·ã§ã³ã¯ãSpring 5ã«ç»å ŽããWebFluxãã¬ãŒã ã¯ãŒã¯ã䜿çšããŠå®è£
ãããREST APIãåããããã¯ãšã³ãã®äŸã§ãïŒããã¥ã¡ã³ãã¯
ãã¡ã ïŒããŸãã¯ãããKotlin DSLã§ãïŒ
@Bean fun itemsRouter(handler: ItemHandler) = router { path("/items").nest { GET("/", handler::getAll) POST("/", handler::add) GET("/{id}", handler::getOne) PUT("/{id}", handler::update) } }
åä¿¡ããHTTPèŠæ±ã®åŠçã¯ã
ItemHandler
ã¯ã©ã¹
ItemHandler
å§ä»»ãã
ItemHandler
ã ããšãã°ããããšã³ãã£ãã£ã®ãªããžã§ã¯ãã®ãªã¹ããååŸããã¡ãœããã¯æ¬¡ã®ããã«ãªããŸãã
fun getAll(request: ServerRequest) = ServerResponse.ok() .contentType(APPLICATION_JSON_UTF8) .body(fromObject(itemRepository.findAll()))
spring-cloud-starter-netflix-eureka-client
ãååšãããããã¢ããªã±ãŒã·ã§ã³ã¯EurekaãµãŒããŒã¯ã©ã€ã¢ã³ãã«ãªããŸããã€ãŸãããµãŒãã¹ã¬ãžã¹ããªããããŒã¿ãç»é²ããã³åä¿¡ããŸãã ç»é²åŸãã¢ããªã±ãŒã·ã§ã³ã¯äžå®ã®é »åºŠã§ããŒããããããŠãŒã¬ã«ãµãŒããŒã«éä¿¡ããŸããäžå®æéããŠãŒã¬ã«ãµãŒããŒãåä¿¡ããããŒããããã®æå€§å¯èœå€ã«å¯Ÿããå²åãäžå®ã®ãããå€ãäžåããšãã¢ããªã±ãŒã·ã§ã³ã¯ãµãŒãã¹ã¬ãžã¹ããªããåé€ãããŸãã
远å ã®ã¡ã¿ããŒã¿ãEurekaãµãŒããŒã«éä¿¡ããæ¹æ³ã®1ã€ãæ€èšããŠãã ããã
@PostConstruct private fun addMetadata() = aim.registerAppMetadata(mapOf("description" to "Some description"))
http://localhost:8761/eureka/apps/items-service
ã«Postmanã§ã¢ã¯ã»ã¹ããŠããã®ããŒã¿ãEurekaãµãŒããŒã«ãã£ãŠåä¿¡ãããããšã確èªããŸãã
ã¢ã€ãã UI
ãã®ãã€ã¯ããµãŒãã¹ã¯ãUIã²ãŒããŠã§ã€ïŒæ¬¡ã®ã»ã¯ã·ã§ã³ã§èª¬æããŸãïŒãšã®å¯Ÿè©±ã®ãã¢ã«å ããŠãItemsãµãŒãã¹ã®ããã³ããšã³ãæ©èœãå®è¡ããŸããããã¯ãããã€ãã®æ¹æ³ã§REST APIãšå¯Ÿè©±ã§ããŸãã
- OpenFeignã䜿çšããŠèšè¿°ãããREST APIã®ã¯ã©ã€ã¢ã³ãïŒ
@FeignClient("items-service", fallbackFactory = ItemsServiceFeignClient.ItemsServiceFeignClientFallbackFactory::class) interface ItemsServiceFeignClient { @GetMapping("/items/{id}") fun getItem(@PathVariable("id") id: Long): String @GetMapping("/not-existing-path") fun testHystrixFallback(): String @Component class ItemsServiceFeignClientFallbackFactory : FallbackFactory<ItemsServiceFeignClient> { private val log = LoggerFactory.getLogger(this::class.java) override fun create(cause: Throwable) = object : ItemsServiceFeignClient { override fun getItem(id: Long): String { log.error("Cannot get item with id=$id") throw ItemsUiException(cause) } override fun testHystrixFallback(): String { log.error("This is expected error") return "{\"error\" : \"Some error\"}" } } } }
RestTemplate
Bean
java configã«ãã³ãäœæãããŸãã
@Bean @LoadBalanced fun restTemplate() = RestTemplate()
ãããŠããã®ããã«äœ¿çšããŸããïŒ
fun requestWithRestTemplate(id: Long): String = restTemplate.getForEntity("http://items-service/items/$id", String::class.java).body ?: "No result"
WebClient
ã¯ã©ã¹WebClient
ïŒWebFluxãã¬ãŒã ã¯ãŒã¯ã«åºæã®ã¡ãœããïŒ
java configã«ãã³ãäœæãããŸãã
@Bean fun webClient(loadBalancerClient: LoadBalancerClient) = WebClient.builder() .filter(LoadBalancerExchangeFilterFunction(loadBalancerClient)) .build()
ãããŠããã®ããã«äœ¿çšããŸããïŒ
fun requestWithWebClient(id: Long): Mono<String> = webClient.get().uri("http://items-service/items/$id").retrieve().bodyToMono(String::class.java)
http://localhost:8081/example
ã¢ã¯ã»ã¹ãããšã3ã€ã®ã¡ãœãããã¹ãŠãåãçµæãè¿ãããšã確èªã§ããŸãã
ç§ã¯ãOpenFeignã䜿çšãããªãã·ã§ã³ã奜ã¿ãŸããããã¯ãSpringãå®è£
ããŠãããåŒã³åºããããã€ã¯ããµãŒãã¹ãšã®å¯Ÿè©±ã®ããã®ã³ã³ãã©ã¯ããéçºããããšãã§ããããã§ãã ãã®ã³ã³ãã©ã¯ããå®è£
ãããªããžã§ã¯ããæ³šå
¥ãããéåžžã®ãã³ã®ããã«äœ¿çšãããŸãã
itemsServiceFeignClient.getItem(1)
äœããã®çç±ã§ãªã¯ãšã¹ãã倱æããå Žåã
FallbackFactory
ã€ã³ã¿ãŒãã§ãŒã¹ãå®è£
ããã¯ã©ã¹ã®å¯Ÿå¿ããã¡ãœãããåŒã³åºãããŸãããã®ã¡ãœããã§ã¯ããšã©ãŒãåŠçããŠããã©ã«ãã®ã¬ã¹ãã³ã¹ãè¿ãïŒãŸãã¯äŸå€ãããã«ã¹ããŒããïŒå¿
èŠããããŸãã ç¹å®ã®æ°ã®é£ç¶ããåŒã³åºãã倱æããå Žåããã¥ãŒãºã¯åç·ãéãïŒ
ãããš
ããã®ãµãŒããããã¬ãŒã«ãŒã«ã€ããŠã®è©³çްïŒãèœã¡ããã€ã¯ããµãŒãã¹ãå埩ããæéãäžããŸãã
Feignã¯ã©ã€ã¢ã³ãã䜿çšããã«ã¯ã
@EnableFeignClients
ã¢ããªã±ãŒã·ã§ã³
@EnableFeignClients
ã«æ³šéãä»ããå¿
èŠããããŸãã
@SpringBootApplication @EnableFeignClients(clients = [ItemsServiceFeignClient::class]) class ItemsUiApplication
Festã¯ã©ã€ã¢ã³ãã§Hystrixãã©ãŒã«ããã¯ãæ©èœãããã«ã¯ãã¢ããªã±ãŒã·ã§ã³æ§æã«æ¬¡ã远å ããå¿
èŠããããŸãã
feign: hystrix: enabled: true
Feignã¯ã©ã€ã¢ã³ãã§Hystrixãã©ãŒã«ããã¯ã®åäœããã¹ãããã«ã¯ã
http://localhost:8081/hystrix-fallback
ãŸãã Feignã¯ã©ã€ã¢ã³ãã¯ãItemsãµãŒãã¹ã«ååšããªããã¹ã§èŠæ±ãå®è¡ããããšãããããå¿çãè¿ãããŸãã
{"error" : "Some error"}
UIã²ãŒããŠã§ã€
APIã²ãŒããŠã§ã€ãã¿ãŒã³ã䜿çšãããšãä»ã®ãã€ã¯ããµãŒãã¹ãæäŸããAPIã®åäžã®ãšã³ããªãã€ã³ããäœæã§ããŸãïŒè©³çްã¯
ãã¡ã ïŒã ãã®ãã¿ãŒã³ãå®è£
ããã¢ããªã±ãŒã·ã§ã³ã¯ããªã¯ãšã¹ãã®ãã€ã¯ããµãŒãã¹ãžã®ã«ãŒãã£ã³ã°ïŒã«ãŒãã£ã³ã°ïŒãå®è¡ããèªèšŒãªã©ã®è¿œå æ©èœãå®è¡ã§ããŸãã
ãã®ãããžã§ã¯ãã§ã¯ãããæç¢ºã«ããããã«ãUIã²ãŒããŠã§ã€ãå®è£
ãããŠããŸããã€ãŸããç°ãªãUIã®åäžã®ãšã³ããªãã€ã³ãã§ãã æããã«ãã²ãŒããŠã§ã€APIãåæ§ã«å®è£
ãããŠããŸãã ãã€ã¯ããµãŒãã¹ã¯ãSpring Cloud Gatewayãã¬ãŒã ã¯ãŒã¯ã«åºã¥ããŠããŸãã å¥ã®æ¹æ³ã¯ãNetflix OSSã®äžéšã§ãããSpring Cloud Netflixã䜿çšããŠSpring Bootãšçµ±åãããNetflix Zuulã§ãã
UIã²ãŒããŠã§ã€ã¯ãçæãããSSLèšŒææžïŒãããžã§ã¯ãã«ããïŒã䜿çšããŠããŒã443ã§å®è¡ãããŸãã SSLããã³HTTPSã¯æ¬¡ã®ããã«æ§æãããŸãã
server: port: 443 ssl: key-store: classpath:keystore.p12 key-store-password: qwerty key-alias: test_key key-store-type: PKCS12
ãŠãŒã¶ãŒã®ãã°ã€ã³ãšãã¹ã¯ãŒãã¯ãWebFluxåºæã®
ReactiveUserDetailsService
ã€ã³ã¿ãŒãã§ã€ã¹ã®ãããããŒã¹ã®å®è£
ã«ä¿åãããŸãã
@Bean fun reactiveUserDetailsService(): ReactiveUserDetailsService { val user = User.withDefaultPasswordEncoder() .username("john_doe").password("qwerty").roles("USER") .build() val admin = User.withDefaultPasswordEncoder() .username("admin").password("admin").roles("ADMIN") .build() return MapReactiveUserDetailsService(user, admin) }
ã»ãã¥ãªãã£èšå®ã¯æ¬¡ã®ããã«æ§æãããŸãã
@Bean fun springWebFilterChain(http: ServerHttpSecurity): SecurityWebFilterChain = http .formLogin().loginPage("/login") .and() .authorizeExchange() .pathMatchers("/login").permitAll() .pathMatchers("/static/**").permitAll() .pathMatchers("/favicon.ico").permitAll() .pathMatchers("/webjars/**").permitAll() .pathMatchers("/actuator/**").permitAll() .anyExchange().authenticated() .and() .csrf().disable() .build()
æå®ãããæ§æã¯ãèªèšŒãããŠããªããŠãŒã¶ãŒãå«ããã¹ãŠã®ãŠãŒã¶ãŒãWebãªãœãŒã¹ã®äžéšïŒéçãªã©ïŒã䜿çšå¯èœã§ããããã®ä»ãã¹ãŠïŒ
.anyExchange()
ïŒã¯èªèšŒã®ã¿ã§ããããšã決å®ããŸãã èªèšŒãå¿
èŠãªURLãå
¥åããããšãããšããã°ã€ã³ããŒãžïŒ
https://localhost/login
ïŒã«ãªãã€ã¬ã¯ããã
https://localhost/login
ã
ãã®ããŒãžã§ã¯ãWebjarsã䜿çšããŠãããžã§ã¯ãã«æ¥ç¶ãããŠããBootstrapãã¬ãŒã ã¯ãŒã¯ã®ããŒã«ã䜿çšããŸããããã«ãããã¯ã©ã€ã¢ã³ãåŽã®ã©ã€ãã©ãªãéåžžã®äŸåé¢ä¿ãšããŠç®¡çã§ããŸãã Thymeleafã¯ãHTMLããŒãžã®çæã«äœ¿çšãããŸãã ãã°ã€ã³ããŒãžãžã®ã¢ã¯ã»ã¹ã¯ãWebFluxã䜿çšããŠèšå®ãããŸãã
@Bean fun routes() = router { GET("/login") { ServerResponse.ok().contentType(MediaType.TEXT_HTML).render("login") } }
Spring Cloud Gatewayã«ãŒãã£ã³ã°ã¯ãYAMLãŸãã¯java configã§èšå®ã§ããŸãã ãã€ã¯ããµãŒãã¹ãžã®ã«ãŒãã¯ããµãŒãã¹ã¬ãžã¹ããªããåä¿¡ããããŒã¿ã«åºã¥ããŠæåã§å²ãåœãŠãããããèªåçã«äœæãããŸãã ã«ãŒãã£ã³ã°ãå¿
èŠãªUIã®æ°ãååã«å€ãå ŽåããµãŒãã¹ã¬ãžã¹ããªãšã®çµ±åã䜿çšããæ¹ã䟿å©ã§ãã
spring: cloud: gateway: discovery: locator: enabled: true lower-case-service-id: true include-expression: serviceId.endsWith('-UI') url-expression: "'lb:http://'+serviceId"
include-expression
ãã©ã¡ãŒã¿ãŒã®å€ã¯ãååã
-UIã§çµãããã€ã¯ããµãŒãã¹ã«å¯ŸããŠã®ã¿ã«ãŒããäœæãããããšã瀺ãã
url-expression
ãã©ã¡ãŒã¿ãŒã®å€ã¯ãHTTPçµç±ã§å®è¡ãããŠããUIã²ãŒããŠã§ã€ãšã¯ç°ãªããHTTPãããã³ã«çµç±ã§ã¢ã¯ã»ã¹å¯èœã§ãããã¢ã¯ã»ã¹ããããšãã«ã¯ã©ã€ã¢ã³ãã®è² è·åæ£ã䜿çšããŸãïŒNetflixãªãã³ã䜿çšããŠå®è£
ïŒã
java configã«ïŒServiceã¬ãžã¹ããªãšçµ±åããã«ïŒæåã§ã«ãŒããäœæããäŸãèããŠã¿ãŸãããïŒ
@Bean fun routeLocator(builder: RouteLocatorBuilder) = builder.routes { route("eureka-gui") { path("/eureka") filters { rewritePath("/eureka", "/") } uri("lb:http://eureka-server") } route("eureka-internals") { path("/eureka/**") uri("lb:http://eureka-server") } }
æåã®ã«ãŒãã¯ãåã«ç€ºããEurekaãµãŒããŒã®ããŒã ããŒãžïŒ
http://localhost:8761
ïŒã«
http://localhost:8761
ã¯ããã®ããŒãžã®ãªãœãŒã¹ãããŒãããããã«å¿
èŠã§ãã
ã¢ããªã±ãŒã·ã§ã³ã«ãã£ãŠäœæããããã¹ãŠã®ã«ãŒãã¯ã
https://localhost/actuator/gateway/routes
å©çšã§ã
https://localhost/actuator/gateway/routes
ã
åºç€ãšãªããã€ã¯ããµãŒãã¹ã§ã¯ãUIã²ãŒããŠã§ã€ã§èªèšŒããããŠãŒã¶ãŒã®ãã°ã€ã³ããã³/ãŸãã¯åœ¹å²ã«ã¢ã¯ã»ã¹ããå¿
èŠãããå ŽåããããŸãã ãããè¡ãããã«ãèŠæ±ã«é©åãªããããŒã远å ãããã£ã«ã¿ãŒãäœæããŸããã
@Component class AddCredentialsGlobalFilter : GlobalFilter { private val loggedInUserHeader = "logged-in-user" private val loggedInUserRolesHeader = "logged-in-user-roles" override fun filter(exchange: ServerWebExchange, chain: GatewayFilterChain) = exchange.getPrincipal<Principal>() .flatMap { val request = exchange.request.mutate() .header(loggedInUserHeader, it.name) .header(loggedInUserRolesHeader, (it as Authentication).authorities?.joinToString(";") ?: "") .build() chain.filter(exchange.mutate().request(request).build()) } }
次ã¯ãUIã²ãŒããŠã§ã€
https://localhost/items-ui/greeting
ã䜿çšããŠã¢ã€ãã UIãèŠãŠã¿ãŸãããããããã®ããããŒã®åŠçãæ¢ã«ã¢ã€ãã UIã«å®è£
ãããŠãããšä»®å®ããŸãã
Spring Cloud Sleuthã¯ã忣ã·ã¹ãã ã§ã®ã¯ãšãªãã¬ãŒã¹ã®ãœãªã¥ãŒã·ã§ã³ã§ãã ãã¬ãŒã¹IDïŒãã¹ã¹ã«ãŒèå¥åïŒãšã¹ãã³IDïŒäœæ¥åäœèå¥åïŒã¯ãããã€ãã®ãã€ã¯ããµãŒãã¹ãééãããªã¯ãšã¹ãã®ããããŒã«è¿œå ãããŸãïŒçè§£ã容æã«ããããã«ãã¹ããŒã ãç°¡ç¥åããŸããã
ããã§ããã詳现ãªèª¬æããããŸãïŒ
ãã®æ©èœã¯ã
spring-cloud-starter-sleuth
远å ããã ãã§æ¥ç¶ãããŸãã
é©åãªãã°èšå®ãæå®ãããšã察å¿ãããã€ã¯ããµãŒãã¹ã®ã³ã³ãœãŒã«ã§æ¬¡ã®ãããªãã®ãèŠãããšãã§ããŸãïŒãã€ã¯ããµãŒãã¹ã®ååã®åŸã«ãã¬ãŒã¹IDãšã¹ãã³IDã衚瀺ãããŸãïŒã
DEBUG [ui-gateway,009b085bfab5d0f2,009b085bfab5d0f2,false] oscghRoutePredicateHandlerMapping : Route matched: CompositeDiscoveryClient_ITEMS-UI DEBUG [items-ui,009b085bfab5d0f2,947bff0ce8d184f4,false] oswrfunction.server.RouterFunctions : Predicate "(GET && /example)" matches against "GET /example" DEBUG [items-service,009b085bfab5d0f2,dd3fa674cd994b01,false] oswrfunction.server.RouterFunctions : Predicate "(GET && /{id})" matches against "GET /1"
忣ãã¬ãŒã¹ãã°ã©ãã£ã«ã«ã«è¡šç€ºããã«ã¯ãããšãã°ãZipkinã䜿çšã§ããŸããZipkinã¯ãä»ã®ãã€ã¯ããµãŒãã¹ããã®HTTPèŠæ±ã«é¢ããæ
å ±ãéçŽãããµãŒããŒãšããŠæ©èœããŸãïŒè©³çްã¯
ãã¡ã ïŒã
çµç«
OSã«å¿ããŠã
gradlew clean build
ãŸãã¯
./gradlew clean build
ãŸãã
Gradle wrapperã䜿çšããå¯èœæ§ãèãããšãããŒã«ã«ã«ã€ã³ã¹ããŒã«ãããGradleã¯å¿
èŠãããŸããã
ãã«ããšãã®åŸã®èµ·åã¯ãJDK 11.0.1ã§æ£åžžã«æž¡ãããŸãã ãã以åã¯ããããžã§ã¯ãã¯JDK 10ã§æ©èœããŠããããããã®ããŒãžã§ã³ã§ã¯ã¢ã»ã³ããªãšèµ·åã«åé¡ã¯ãªããšæããŸãã JDKã®ä»¥åã®ããŒãžã§ã³ã«é¢ããããŒã¿ã¯ãããŸããã ãŸãã䜿çšããGradle 5ã«ã¯å°ãªããšãJDK 8ãå¿
èŠã§ããããšã«æ³šæããŠãã ããã
æã¡äžã
ãã®èšäºã§èª¬æãããŠããé åºã§ã¢ããªã±ãŒã·ã§ã³ãèµ·åããããšããå§ãããŸãã ããã·ã¥ããŒãã®å®è¡ãæå¹ã«ããŠIntellij IDEAã䜿çšããŠããå Žåãæ¬¡ã®ããã«ãªããŸãã
ãããã«
ãã®èšäºã§ã¯ãJavaã®äžçã«ãããçŸåšã®ãã¯ãããžãŒã¹ã¿ãã¯ã®ãã€ã¯ããµãŒãã¹ã¢ãŒããã¯ãã£ããã®äž»èŠã³ã³ããŒãã³ããããã³ããã€ãã®æ©èœã®äŸãæ€èšŒããŸããã 誰ãããã®è³æã圹ã«ç«ã€ããšãé¡ã£ãŠããŸãã ãæž
èŽããããšãããããŸããïŒ
åç
§è³æ