Spring Cloud Feign
Add spring cloud starter feign dependency
<!-- add to Spring Cloud Feign rely on --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency>
Claim Feign client
package com.segumentfault.spring.cloud.lesson10.api; import com.segumentfault.spring.cloud.lesson10.domain.User; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import java.util.List; /** * User services * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 1.0.0 */ @FeignClient(name = "${user.service.name}") // Use placeholders to avoid future hard coding public interface UserService { /** * Save user * * @param user * @return */ @PostMapping("/user/save") boolean saveUser(User user); /** * Query all user lists * * @return non-null */ @GetMapping("/user/find/all") List<User> findAll(); }
Note that when using @ FeignClient name attribute, try to use placeholders to avoid hard coding. Otherwise, the client version will have to be upgraded in the future.
Activate FeignClient
@EnableFeigntClients package com.segumentfault.spring.cloud.lesson10.user.service.client; import com.netflix.loadbalancer.IRule; import com.segumentfault.spring.cloud.lesson10.api.UserService; import com.segumentfault.spring.cloud.lesson10.user.service.client.rule.MyRule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; /** * Boot class * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 0.0.1 */ @SpringBootApplication @RibbonClient("user-service-provider") // Specify target app name @EnableCircuitBreaker // Service short circuit @EnableFeignClients(clients = UserService.class) // Declare that the UserService interface is called as Feign Client public class UserServiceClientApplication { public static void main(String[] args) { SpringApplication.run(UserServiceClientApplication.class, args); } /** * Expose {@ link MyRule} as {@ link Bean} * * @return {@link MyRule} */ @Bean public IRule myRule() { return new MyRule(); } /** * Claim load balancing capability {@ link RestTemplate} * * @return */ @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
Spring Cloud integration
Consolidated load balancing: Netflix Ribbon
Client: activate @ FeignClient UserService
package com.segumentfault.spring.cloud.lesson10.user.service.client; import com.netflix.loadbalancer.IRule; import com.segumentfault.spring.cloud.lesson10.api.UserService; import com.segumentfault.spring.cloud.lesson10.user.service.client.rule.MyRule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; /** * Boot class * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 0.0.1 */ @SpringBootApplication @RibbonClient("user-service-provider") // Specify target app name @EnableCircuitBreaker // Service short circuit @EnableFeignClients(clients = UserService.class) // Declare that the UserService interface is called as Feign Client public class UserServiceClientApplication { public static void main(String[] args) { SpringApplication.run(UserServiceClientApplication.class, args); } /** * Expose {@ link MyRule} as {@ link Bean} * * @return {@link MyRule} */ @Bean public IRule myRule() { return new MyRule(); } /** * Claim load balancing capability {@ link RestTemplate} * * @return */ @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
Client: configure placeholder in @ FeignClient(name = "${user.service.name}")
Adjust application properties
##User Ribbon client application spring.application.name = user-service-client ##Service port server.port = 8080 ##Provider service name provider.service.name = user-service-provider ##Provider service host provider.service.host = localhost ##Provider service port provider.service.port = 9090 ##Close Eureka Client and register the Ribbon service address through configuration eureka.client.enabled = false ##Define the server address of the user service provider ribbon ##Provide service list for RibbonLoadBalancerClient user-service-provider.ribbon.listOfServers = \ http://${provider.service.host}:${provider.service.port} ##Extended IPing implementation user-service-provider.ribbon.NFLoadBalancerPingClassName = \ com.segumentfault.spring.cloud.lesson10.user.service.client.ping.MyPing ##Configure placeholders in @ feignclient (name = '${user. Service. Name}') ## user.service.name actually needs to specify the provider of UserService interface ##That is, user service provider. You can use ${provider.service.name} instead user.service.name = ${provider.service.name}
Server side: implement UserService, that is, expose HTTP REST services
Adjustment application: user service provider
Add Bean name of InMemoryUserService
package com.segumentfault.spring.cloud.lesson10.user.service.provider.service; import com.segumentfault.spring.cloud.lesson10.api.UserService; import com.segumentfault.spring.cloud.lesson10.domain.User; import org.springframework.stereotype.Service; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; /** * Memory implementation {@ link UserService} * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 0.0.1 */ @Service("inMemoryUserService") // Bean name public class InMemoryUserService implements UserService { private Map<Long, User> repository = new ConcurrentHashMap<>(); @Override public boolean saveUser(User user) { return repository.put(user.getId(), user) == null; } @Override public List<User> findAll() { return new ArrayList(repository.values()); } }
UserServiceProviderController implements Feign client interface UserService
UserServiceProviderController.java
package com.segumentfault.spring.cloud.lesson10.user.service.web.controller; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.segumentfault.spring.cloud.lesson10.api.UserService; import com.segumentfault.spring.cloud.lesson10.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Random; /** * User service provider Controller * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 0.0.1 */ @RestController public class UserServiceProviderController implements UserService { @Autowired @Qualifier("inMemoryUserService") // Implement Bean: InMemoryUserService private UserService userService; private final static Random random = new Random(); // Through method inheritance, URL mapping: "/ user/save" @Override public boolean saveUser(@RequestBody User user) { return userService.saveUser(user); } // Through method inheritance, URL mapping: "/ user/find/all" @Override public List<User> findAll() { return userService.findAll(); } /** * Get a list of all users * * @return */ @HystrixCommand( commandProperties = { // Command configuration // Set the operation time to 100 milliseconds @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100") }, fallbackMethod = "fallbackForGetUsers" // Set fallback method ) @GetMapping("/user/list") public Collection<User> getUsers() throws InterruptedException { long executeTime = random.nextInt(200); // Simulate execution time by hibernating System.out.println("Execute Time : " + executeTime + " ms"); Thread.sleep(executeTime); return userService.findAll(); } /** * {@link #getUsers()} fallback method for * * @return Empty set */ public Collection<User> fallbackForGetUsers() { return Collections.emptyList(); } }
Client: directly call the remote HTTP REST service using UserService
package com.segumentfault.spring.cloud.lesson10.user.service.client.web.controller; import com.segumentfault.spring.cloud.lesson10.api.UserService; import com.segumentfault.spring.cloud.lesson10.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.List; /** * {@link UserService} Client {@ link RestController} * * Note: it is officially recommended that the client and server do not implement Feign interface at the same time * The code here is just a description. In fact, it is best to use combination rather than inheritance * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 1.0.0 */ @RestController public class UserServiceClientController implements UserService { @Autowired private UserService userService; // Through method inheritance, URL mapping: "/ user/save" @Override public boolean saveUser(@RequestBody User user) { return userService.saveUser(user); } // Through method inheritance, URL mapping: "/ user/find/all" @Override public List<User> findAll() { return userService.findAll(); } }
Consolidation services: Netflix Hystrix
API: adjust UserService and implement Fallback
UserService Fallback implementation
package com.segumentfault.spring.cloud.lesson10.fallback; import com.segumentfault.spring.cloud.lesson10.api.UserService; import com.segumentfault.spring.cloud.lesson10.domain.User; import java.util.Collections; import java.util.List; /** * {@link UserService} Fallback realization * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 1.0.0 */ public class UserServiceFallback implements UserService { @Override public boolean saveUser(User user) { return false; } @Override public List<User> findAll() { return Collections.emptyList(); } }
Adjust the UserService @FeignClient fallback property:
package com.segumentfault.spring.cloud.lesson10.api; import com.segumentfault.spring.cloud.lesson10.domain.User; import com.segumentfault.spring.cloud.lesson10.fallback.UserServiceFallback; import org.springframework.cloud.netflix.feign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import java.util.List; /** * User services * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 1.0.0 */ @FeignClient(name = "${user.service.name}",fallback = UserServiceFallback.class) // Use placeholders to avoid future hard coding public interface UserService { /** * Save user * * @param user * @return */ @PostMapping("/user/save") boolean saveUser(User user); /** * Query all user lists * * @return non-null */ @GetMapping("/user/find/all") List<User> findAll(); }
Server: UserServiceProviderController#findAll() method integration @ HystrixCommand
package com.segumentfault.spring.cloud.lesson10.user.service.web.controller; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.segumentfault.spring.cloud.lesson10.api.UserService; import com.segumentfault.spring.cloud.lesson10.domain.User; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Random; /** * User service provider Controller * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 0.0.1 */ @RestController public class UserServiceProviderController implements UserService { @Autowired @Qualifier("inMemoryUserService") // Implement Bean: InMemoryUserService private UserService userService; private final static Random random = new Random(); // Through method inheritance, URL mapping: "/ user/save" @Override public boolean saveUser(@RequestBody User user) { return userService.saveUser(user); } @HystrixCommand( commandProperties = { // Command configuration // Set the operation time to 100 milliseconds @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100") }, fallbackMethod = "fallbackForGetUsers" // Set fallback method ) // Through method inheritance, URL mapping: "/ user/find/all" @Override public List<User> findAll() { return userService.findAll(); } /** * Get a list of all users * * @return */ @HystrixCommand( commandProperties = { // Command configuration // Set the operation time to 100 milliseconds @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100") }, fallbackMethod = "fallbackForGetUsers" // Set fallback method ) @GetMapping("/user/list") public List<User> getUsers() throws InterruptedException { long executeTime = random.nextInt(200); // Simulate execution time by hibernating System.out.println("Execute Time : " + executeTime + " ms"); Thread.sleep(executeTime); return userService.findAll(); } /** * {@link #getUsers()} fallback method for * * @return Empty set */ public List<User> fallbackForGetUsers() { return Collections.emptyList(); } }
Consolidated service discovery: Netflix Eureka
Create Eureka Server
pom. Add Eureka Server dependency to XML
<dependencies> <!-- Eureka Server rely on --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka-server</artifactId> </dependency> </dependencies>
Create boot class: EurekaServerApplication
package com.segumentfault.spring.cloud.lesson10.eureka.server; /** * Eureka Server Boot class * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 1.0.0 */ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
Configuring Eureka Server
application.properties
##Spring Cloud Eureka server application name spring.application.name = eureka-server ##Spring Cloud Eureka server service port server.port = 10000 ##Management port security failure management.security.enabled = false ##Spring Cloud Eureka server as the registry ##Usually, you don't need to register with other registration centers ##At the same time, it does not need to obtain client information ###Cancel registration with the registry eureka.client.register-with-eureka = false ###Cancel obtaining registration information (service and instance information) from the registration center eureka.client.fetch-registry = false ##Resolve Peer / cluster connectivity issues eureka.instance.hostname = localhost eureka.client.serviceUrl.defaultZone = http://${eureka.instance.hostname}:${server.port}/eureka
port information
user-service-client : 8080
user-service-provider: 9090
eureka-server : 10000
Client: Configure Service Discovery client
Configuration application: user service client
pom. Adding Eureka client dependency to XML
<!-- rely on Spring Cloud Netflix Eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
Activate service discovery client
UserServiceClientApplication.java
package com.segumentfault.spring.cloud.lesson10.user.service.client; import com.netflix.loadbalancer.IRule; import com.segumentfault.spring.cloud.lesson10.api.UserService; import com.segumentfault.spring.cloud.lesson10.user.service.client.rule.MyRule; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.netflix.feign.EnableFeignClients; import org.springframework.cloud.netflix.ribbon.RibbonClient; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; /** * Boot class * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 0.0.1 */ @SpringBootApplication @RibbonClient("user-service-provider") // Specify target app name @EnableCircuitBreaker // Service short circuit @EnableFeignClients(clients = UserService.class) // Declare that the UserService interface is called as Feign Client @EnableDiscoveryClient // Activate service discovery client public class UserServiceClientApplication { public static void main(String[] args) { SpringApplication.run(UserServiceClientApplication.class, args); } /** * Expose {@ link MyRule} as {@ link Bean} * * @return {@link MyRule} */ @Bean public IRule myRule() { return new MyRule(); } /** * Claim load balancing capability {@ link RestTemplate} * * @return */ @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } }
Configure Eureka registry
application.properties
##User Ribbon client application spring.application.name = user-service-client ##Service port server.port = 8080 ##Provider service name provider.service.name = user-service-provider ##Provider service host provider.service.host = localhost ##Provider service port provider.service.port = 9090 ##Activate Eureka Client eureka.client.enabled = true ##Extended IPing implementation user-service-provider.ribbon.NFLoadBalancerPingClassName = \ com.segumentfault.spring.cloud.lesson10.user.service.client.ping.MyPing ##Configure placeholders in @ feignclient (name = '${user. Service. Name}') ## user.service.name actually needs to specify the provider of UserService interface ##That is, user service provider. You can use ${provider.service.name} instead user.service.name = ${provider.service.name} ##The Spring Cloud Eureka client registers with the Eureka server eureka.client.serviceUrl.defaultZone = http://localhost:10000/eureka
Server: configure the service discovery client
Configuration application: user service provider
pom. Adding Eureka client dependency to XML
<!-- rely on Spring Cloud Netflix Eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
Activate service discovery client
UserServiceProviderApplication.java
package com.segumentfault.spring.cloud.lesson10.user.service; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.hystrix.EnableHystrix; /** * Boot class * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 0.0.1 */ @SpringBootApplication @EnableHystrix @EnableDiscoveryClient // Activate service discovery client public class UserServiceProviderApplication { public static void main(String[] args) { SpringApplication.run(UserServiceProviderApplication.class, args); } }
Configure Eureka registry
application.properties
##User service provider application information spring.application.name = user-service-provider ##Service port server.port = 9090 ##The Spring Cloud Eureka client registers with the Eureka server eureka.client.serviceUrl.defaultZone = http://localhost:10000/eureka
Consolidation configuration server: Config Server
Create Config Server
pom.xml add Config Server dependency
<dependencies> <!-- rely on Spring Cloud Config Server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> </dependencies>
File System based configuration
Note: user service client application The following contents in properties will be configured as user service in the server Properties override
Create user service properties
##Provider service name provider.service.name = user-service-provider ##Provider service host provider.service.host = localhost ##Provider service port provider.service.port = 9090 ##Configure placeholders in @ feignclient (name = '${user. Service. Name}') ## user.service.name actually needs to specify the provider of UserService interface ##You can use $. User - provider instead of $. Service} user.service.name = ${provider.service.name}
Initialize profile root path
Currently ${user.dir} points to: / users / mercy / downloads / spring-cloud-less-10/
user-service.properties relative to / config server / SRC / main / resources / configs
Execute git command on the console:
$ git init Initialized empty Git repository in /Users/Mercy/Downloads/spring-cloud-lesson-10/config-server/src/main/resources/configs/.git/ $ git add user-service.properties
Set profile root path
application.properties
##Spring Cloud Config Server application name spring.application.name = config-server ##Server service port server.port = 7070 ##Management port security failure management.security.enabled = false ##The Spring Cloud Eureka client registers with the Eureka server eureka.client.serviceUrl.defaultZone = http://localhost:10000/eureka ##Configure server file system git repository ##${user.dir} reduces Platform file system inconsistencies ##Currently ${user. Dir} / config server / SRC / main / resources / configs spring.cloud.config.server.git.uri = ${user.dir}/config-server/src/main/resources/configs
Activate service discovery client
<!-- rely on Spring Cloud Netflix Eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency>
application.properties
##The Spring Cloud Eureka client registers with the Eureka server eureka.client.serviceUrl.defaultZone = http://localhost:10000/eureka
Activate service discovery
package com.segumentfault.spring.cloud.lesson10.config.server; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.config.server.EnableConfigServer; /** * Configure server application * * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a> * @since 1.0.0 */ @EnableConfigServer @EnableDiscoveryClient @SpringBootApplication public class ConfigServerApplication { public static void main(String[] args) { SpringApplication.run(ConfigServerApplication.class, args); } }
Consolidation configuration client: Config Client
Adjust the user service client application as the config client application
pom. Adding config client dependency to XML
<!-- Rely on spring cloud config client -- > <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
Create and configure bootstrap Properties file
bootstrap.properties
##User Ribbon client application spring.application.name = user-service-client ##Configure applications associated with client applications ## spring.cloud.config.name is optional ##If not configured, ${spring.application.name} spring.cloud.config.name = user-service ##Association profile spring.cloud.config.profile = default ##Associated label spring.cloud.config.label = master ##Activate Config Server service discovery spring.cloud.config.discovery.enabled = true ##Config Server application name spring.cloud.config.discovery.serviceId = config-server ##The Spring Cloud Eureka client registers with the Eureka server eureka.client.serviceUrl.defaultZone = http://localhost:10000/eureka
application.properties are also adjusted
##Service port server.port = 8080 ##Extended IPing implementation user-service-provider.ribbon.NFLoadBalancerPingClassName = \ com.segumentfault.spring.cloud.lesson10.user.service.client.ping.MyPing ##The following contents are provided by Config Server ###Provider service name #provider.service.name = user-service-provider ###Provider service host #provider.service.host = localhost ###Provider service port #provider.service.port = 9090 ###Configure placeholders in @ feignclient (name = '${user. Service. Name}') ### user.service.name actually needs to specify the provider of UserService interface ###That is, user service provider. You can use ${provider.service.name} instead #user.service.name = ${provider.service.name}