SpringCloud——服务调用
Spring Cloud Feign
- 依赖: org.springframework.cloud:spring-cloud-starter-feign
- **: @EnableFeignClients
- 申明: @FeignClient
添加User服务
在此之前,我们改造一下工程,添加User服务模块,然后改下现有模块的名称
根据这个结构图来进行改造,这里为了简便,暂时不配置配置服务器。
添加user-api模块
作为user服务定义方
添加依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
申明Feign客户端
@FeignClient(name = "${user.service.name}",fallback = UserServiceFallback.class)
public interface UserService {
@PostMapping("/user")
boolean saveUser(User user);
@GetMapping("/user")
List<User> findAll();
}
添加fallback实现
package com.learn.userapi.fallback;
import com.learn.userapi.api.UserService;
import com.learn.userapi.domain.User;
import java.util.Collections;
import java.util.List;
/**
* fallback实现
*/
public class UserServiceFallback implements UserService{
@Override
public boolean saveUser(User user) {
return false;
}
@Override
public List<User> findAll() {
return Collections.emptyList();
}
}
修改ribbon-client
将模块名改为user-service-client, 意思是user服务调用方
添加@EnableFeignClients
/**
* RibbonClients定义多个Ribbon
*/
@SpringBootApplication
@RibbonClients({
@RibbonClient(name = "user-service-provider")
})
@EnableDiscoveryClient
@EnableCircuitBreaker //使用服务短路
@EnableFeignClients(clients = UserService.class) //申明UserService接口作为Feign Client调用
public class RibbonClientApplication {
添加Controller:
package com.learn.ribbonclient.controller;
import com.learn.ribbonclient.hystrix.UserRibbonClientHystrixCommand;
import com.learn.userapi.domain.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.LoadBalancerClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
/**
* 用户 Ribbon Controller
*
* @author <a href="mailto:[email protected]">Mercy</a>
* @since 0.0.1
*/
@RestController
public class UserRibbonController {
/**
* 负载均衡器客户端
*/
@Autowired
private LoadBalancerClient loadBalancerClient;
@Value("${service-provider.name}")
private String providerServiceName;
@Autowired
private RestTemplate restTemplate;
@GetMapping("")
public String index() throws IOException {
User user = new User();
user.setId(UUID.randomUUID().toString());
user.setName("Saint");
// 选择指定的 service Id
ServiceInstance serviceInstance = loadBalancerClient.choose(providerServiceName);
return loadBalancerClient.execute(providerServiceName, serviceInstance, instance -> {
//服务器实例,获取 主机名(IP) 和 端口
String host = instance.getHost();
int port = instance.getPort();
String url = "http://" + host + ":" + port + "/user/save";
RestTemplate restTemplate = new RestTemplate();
return restTemplate.postForObject(url, user, String.class);
});
}
/**
* 调用 user-service-provider "/user/list" REST 接口,并且直接返回内容
* 增加 短路功能
*/
@GetMapping("/user-service-provider/user/list")
public List<User> getUsersList() {
return new UserRibbonClientHystrixCommand(providerServiceName, restTemplate).execute();
}
}
添加UserRibbonClientHystrixCommand
package com.learn.ribbonclient.hystrix;
import com.netflix.hystrix.HystrixCommand;
import com.netflix.hystrix.HystrixCommandGroupKey;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
import java.util.List;
public class UserRibbonClientHystrixCommand extends HystrixCommand<List> {
private final String providerServiceName;
private final RestTemplate restTemplate;
public UserRibbonClientHystrixCommand(String providerServiceName, RestTemplate restTemplate) {
super(HystrixCommandGroupKey.Factory.asKey(
"User-Ribbon-Client"),
100);
this.providerServiceName = providerServiceName;
this.restTemplate = restTemplate;
}
/**
* 主逻辑实现
*
* @return
* @throws Exception
*/
@Override
protected List run() throws Exception {
return restTemplate.getForObject("http://" + providerServiceName + "/user/list", List.class);
}
/**
* Fallback 实现
*
* @return 空集合
*/
protected List getFallback() {
return Collections.emptyList();
}
}
修改config-client
改名为user-service-provider
实现UserService,暴露HTTP REST服务
添加UserService实现类
package com.learn.configclient.service;
import com.learn.userapi.api.UserService;
import com.learn.userapi.domain.User;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service("userService")
public class UserServiceInMemory implements UserService {
private Map<String,User> map = new ConcurrentHashMap<>();
@Override
public boolean saveUser(User user) {
return map.put(user.getId(),user) == null;
}
@Override
public List<User> findAll() {
return new ArrayList<>(map.values());
}
}
添加Controller
@RestController
public class UserServiceProviderController implements UserService{
@Autowired
@Qualifier("userService")
private UserService userService;
private final static Random random = new Random();
// 通过方法继承,URL 映射 :POST "/user"
@Override
public boolean saveUser(@RequestBody User user) {
return userService.saveUser(user);
}
@HystrixCommand(
commandProperties = { // Command 配置
// 设置操作时间为 100 毫秒
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100")
},
fallbackMethod = "fallbackForGetUsers" // 设置 fallback 方法
)
// 通过方法继承,URL 映射 :GET "/user"
@Override
public List<User> findAll() {
return userService.findAll();
}
/**
* 获取所有用户列表
*
* @return
*/
@HystrixCommand(
commandProperties = { // Command 配置
// 设置操作时间为 100 毫秒
@HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "100")
},
fallbackMethod = "fallbackForGetUsers" // 设置 fallback 方法
)
@GetMapping("/user/list")
public List<User> getUsers() throws InterruptedException {
long executeTime = random.nextInt(200);
// 通过休眠来模拟执行时间
System.out.println("Execute Time : " + executeTime + " ms");
Thread.sleep(executeTime);
return userService.findAll();
}
/**
* {@link #getUsers()} 的 fallback 方法
*
* @return 空集合
*/
public List<User> fallbackForGetUsers() {
return Collections.emptyList();
}
}
注意这里的Controller继承了
@PostMapping("/user")
boolean saveUser(User user);
@GetMapping("/user")
List<User> findAll();
可以省略相应的url配置。
修改配置文件
spring:
application:
name: user-service-provider
server:
port: 9090
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka