1. RestTemplate直连消费服务
-
核心依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--HttpClient-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
</dependency>
复制代码
-
相关bean准备
@Configuration
public class RestConfiguration {
@Autowired
private RestTemplateBuilder restTemplateBuilder;
@Bean
public RestTemplate restTemplate(){
return restTemplateBuilder.build();
}
}
复制代码
-
访问http服务
/**
* 将数据放在缓存中
* @param uri
*/
private String saveWeatherData(String uri){
ResponseEntity<String> respString = restTemplate.getForEntity(uri,String.class);
String strBody = null;
if(HttpStatus.OK.equals(respString.getStatusCode())){
strBody = respString.getBody();
}
//TODO 对返回值做校验
stringRedisTemplate.opsForValue().set(uri,strBody,TIME_OUT, TimeUnit.SECONDS);
return strBody;
}
复制代码
-
微服务中使用RestTemplate访问其他服务的三种方式
@Component
public class RestTemplateConfig {
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
@RestController
@Slf4j
public class ClientController {
// @Autowired
// private LoadBalancerClient loadBalancerClient;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/getProductMsg")
public String getProductMsg() {
//1.第一种方式(直接使用restTemplate, url写死)
// RestTemplate restTemplate = new RestTemplate();
// String response = restTemplate.getForObject("http://localhost:8080/msg", String.class);
//2. 第二种方式(利用loadBalancerClient通过应用名获取url, 然后再使用restTemplate)
// RestTemplate restTemplate = new RestTemplate();
// ServiceInstance serviceInstance = loadBalancerClient.choose("PRODUCT");
// String url = String.format("http://%s:%s", serviceInstance.getHost(), serviceInstance.getPort()) + "/msg";
// String response = restTemplate.getForObject(url, String.class);
//3. 第三种方式(利用@LoadBalanced, 可在restTemplate里使用应用名字)
String response = restTemplate.getForObject("http://PRODUCT/msg", String.class);
log.info("response={}", response);
return response;
}
}
复制代码
客户端负载均衡服务器:Ribbon
使用了Ribbon的通信器
- RestTemplate (@LoadBalanced 使用了Ribbon)
- Feign
- Zuul
Ribbon实现客户端软负载均衡核心
- 服务发现 (依据服务的名字,把该副本下所有的实例都找出来)
- 服务选择规则 (依据规则测量,从多个服务中选择一个有效的服务)
- 服务监听 (服务监听,检测失效的服务做到高效剔除)
主要组件
- ServerList (首先通过ServerList 获取所有的可用服务列表)
- ServerListFilter (然后通过ServerListFilter 过滤掉一部分地址)
- IRule (最后剩下的地址中通过IRule选择一个实例作为最终目标结构)
追踪源码自定义负载均衡策略
通过上文第二种方式追踪
1.通过ServerList 获取所有的可用服务列表
2.负载均衡策略
使用默认策略
使用其他策略的方式,规则为IRule的实现类
IDEA观察类之间关系的方法
3.feign消费服务
-
声明式REST客户端(RPC)
-
采用了基于借口的注解
-
核心依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
复制代码
-
相关实现代码
在启动类加入````@EnableFeignClients``注解
/**
* 启动类
* @author gaowenfeng
*/
@SpringBootApplication
@EnableScheduling
@EnableDiscoveryClient
@EnableFeignClients
public class MsaWeatherCollectionWeatherApplication {
public static void main(String[] args) {
SpringApplication.run(MsaWeatherCollectionWeatherApplication.class, args);
}
}
复制代码
服务消费bean
import com.gwf.weather.vo.City;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import java.util.List;
/**
* @author gaowenfeng
* @package com.gwf.weather.service
* @describe Feign访问城市数据API服务接口
* @date 2018/2/21
*/
@FeignClient("msa-weather-city-server") // 要访问的微服务名称
public interface CityClient {
/**
* GetMapping 的参数是要访问的服务方法名(基于http协议接口)
* @return 返回值可以自己定义,会自动讲返回字符串做转型,转型失败会抛异常
*/
@GetMapping("cities")
List<City> listCitys() throws Exception;
}
复制代码
使用
...
@Autowired
private CityClient cityClient;
...
cityList = cityClient.listCitys();
复制代码
-
相关配置
feign:
client:
config:
feignName:
# 连接超时时间,单位为ms
connectTimeout: 50000
# 读取超时时间,单位为ms
readTimeout: 50000
复制代码