消费者该如何获取服务提供者的具体信息
1.服务者启动时向eureka注册自己的信息
2.eureka保存这些信息
3.消费者根据服务名称向eureka拉去提供者的信息
如果有多个服务提供者,消费者该如何选择?
服务消费者利用负载均衡算法,从服务列表中挑选一个
消费者如何感知服务提供者的健康状态?
服务提供者每隔30s向eurekaserver发送心跳请求,报告健康状态。
eureka会更新记录服务列表信息,心跳不正常会被剔除。
消费者就可以拉取到最新的消息。
1.引入依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
dependencies>
2.在启动类加@EnableEurekaServer注解
3.编写配置文件
server:
port: 10086 #端口
spring:
application:
name: eurekaserver #应用名
eureka:
client:
service-url: #eureka注册中心地址
defaultZone: http://localhost:10086/eureka
1.加入eureka客服端的依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
2.添加客服端的配置
eureka:
client:
service-url:
defaultZone: http://localhost:10086/eureka
1.修改url访问路径,用服务名代替ip地址
package cn.itcast.order.web;
import cn.itcast.order.pojo.Order;
import cn.itcast.order.pojo.User;
import cn.itcast.order.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
@RequestMapping("order")
public class OrderController {
@Autowired
private OrderService orderService;
@Autowired
private RestTemplate restTemplate;
@GetMapping("{orderId}")
public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) {
// 根据id查询订单并返回
Order order = orderService.queryOrderById(orderId);
String url="http://userserver/user/"+order.getUserId();
User user = restTemplate.getForObject(url, User.class);
order.setUser(user);
return order;
}
}
2.加负载均衡的注解
package cn.itcast.order;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@MapperScan("cn.itcast.order.mapper")
@SpringBootApplication
public class OrderApplication {
public static void main(String[] args) {
SpringApplication.run(OrderApplication.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
/* @Bean
public IRule randomRule(){
return new RandomRule();
}*/
}
1.通过定义IRule实现可以修改负载均衡的规则
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
@Bean
public IRule randomRule(){
return new RandomRule();
}
2.通过配置文件更改负载均衡规则
userservice: # 给某个微服务配置负载均衡规则,这里是userservice服务
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
在项目中,当我们需要远程调用一个 HTTP 接口时,我们经常会用到 RestTemplate 这个类。这个类是 Spring 框架提供的一个工具类。
RestTemplate
: The original Spring REST client with a synchronous, template method API.
从上面的介绍中我们可以知道:RestTemplate 是一个同步的 Rest API 客户端。下面我们就来介绍下 RestTemplate 的常用功能。
1.创建 RestTemplate
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
return restTemplate;
}
/**
* 创建 RestTemplate 时需要一个 ClientHttpRequestFactory,
* 通过这个请求工厂,我们可以统一设置请求的超时时间,设置代理以及一些其他细节。
* 通过上面代码配置后,我们直接在代码中注入 RestTemplate 就可以使用了。
* @return
*/
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(5000);
factory.setConnectTimeout(15000);
// 设置代理
//factory.setProxy(null);
return factory;
}
2.方法介绍
getForObject
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables)
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
@Resource
private RestTemplate restTemplate;
@Test
void testGetRequestForShopById() {
String url="http://127.0.0.1:8081/shop/{id}";
Result result = restTemplate.getForObject(url, Result.class, 1);
System.out.println(result);
}
# 响应结果
Result(success=true, errorMsg=null, data={id=1, name=103茶餐厅, typeId=1, images=https://qcloud.dpfile.com/pc/jiclIsCKmOI2arxKN1Uf0Hx3PucIJH8q0QSz-Z8llzcN56-_QiKuOvyio1OOxsRtFoXqu0G3iT2T27qat3WhLVEuLYk00OmSS1IdNpm8K8sG4JN9RIm2mTKcbLtc2o2vfCF2ubeXzk49OsGrXt_KYDCngOyCwZK-s3fqawWswzk.jpg,https://qcloud.dpfile.com/pc/IOf6VX3qaBgFXFVgp75w-KKJmWZjFc8GXDU8g9bQC6YGCpAmG00QbfT4vCCBj7njuzFvxlbkWx5uwqY2qcjixFEuLYk00OmSS1IdNpm8K8sG4JN9RIm2mTKcbLtc2o2vmIU_8ZGOT1OjpJmLxG6urQ.jpg, area=大关, address=金华路锦昌文华苑29号, x=120.149192, y=30.316078, avgPrice=80, sold=4215, comments=3035, score=37, openHours=10:00-22:00, createTime=2021-12-22T18:10:39, updateTime=2023-04-06T22:18:52}, total=null)
getForEntity
public ResponseEntity getForEntity(String url, Class responseType, Object... uriVariables)
public ResponseEntity getForEntity(String url, Class responseType, Map uriVariables)
public ResponseEntity getForEntity(URI url, Class responseType)
/**
* 这个方法比getforobject多了一层包装。可以获取更多的响应信息
*/
@Test
void testGetRequestForShopById_getForEntity() {
String url="http://127.0.0.1:8081/shop/{id}";
ResponseEntity<Result> response = restTemplate.getForEntity(url, Result.class,1);
Result body = response.getBody();
System.out.println(body);
}
响应结果
Result(success=true, errorMsg=null, data={id=1, name=103茶餐厅, typeId=1, images=https://qcloud.dpfile.com/pc/jiclIsCKmOI2arxKN1Uf0Hx3PucIJH8q0QSz-Z8llzcN56-_QiKuOvyio1OOxsRtFoXqu0G3iT2T27qat3WhLVEuLYk00OmSS1IdNpm8K8sG4JN9RIm2mTKcbLtc2o2vfCF2ubeXzk49OsGrXt_KYDCngOyCwZK-s3fqawWswzk.jpg,https://qcloud.dpfile.com/pc/IOf6VX3qaBgFXFVgp75w-KKJmWZjFc8GXDU8g9bQC6YGCpAmG00QbfT4vCCBj7njuzFvxlbkWx5uwqY2qcjixFEuLYk00OmSS1IdNpm8K8sG4JN9RIm2mTKcbLtc2o2vmIU_8ZGOT1OjpJmLxG6urQ.jpg, area=大关, address=金华路锦昌文华苑29号, x=120.149192, y=30.316078, avgPrice=80, sold=4215, comments=3035, score=37, openHours=10:00-22:00, createTime=2021-12-22T18:10:39, updateTime=2023-04-06T22:18:52}, total=null)
head请求用的很少见。
Head 与服务器索与get请求一致的相应,响应体不会返回,获取包含在小消息头中的原信息(与get请求类似,返回的响应中没有具体内容,用于获取报头)
HEAD和GET本质是一样的,区别在于HEAD不含有呈现数据,而仅仅是HTTP头信息。有的人可能觉得这个方法没什么用,其实不是这样的。想象一个业务情景:欲判断某个资源是否存在,我们通常使用GET,但这里用HEAD则意义更加明确。
public HttpHeaders headForHeaders(String url, Object... uriVariables)
public HttpHeaders headForHeaders(String url, Map<String, ?> uriVariables)
public HttpHeaders headForHeaders(URI url)
@Test
void headForHeaders() throws URISyntaxException {
String url="http://127.0.0.1:8081/shop-type/list";
URI uri = new URI(url);
HttpHeaders headers = restTemplate.headForHeaders(uri);
System.out.println(headers.toString());
}
head请求的响应
[Content-Type:"application/json", Content-Length:"652", Date:"Wed, 19 Apr 2023 09:49:28 GMT", Keep-Alive:"timeout=60", Connection:"keep-alive"]
在之后的内容之前我们先看看restTemplate的拦截器设置,主要设置请求头或者一些权限认证的需要
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import java.io.IOException;
public class MyRestTemplateInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
HttpHeaders headers = request.getHeaders();
//设置请求头 做权限认证
headers.set("authorization","50da33fa5c0a4ccea49a08bcdf3ee757");
return execution.execute(request,body);
}
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
RestTemplate restTemplate = new RestTemplate(factory);
MyRestTemplateInterceptor restTemplateInterceptor = new MyRestTemplateInterceptor();
List<ClientHttpRequestInterceptor> list=new ArrayList<>(1);
list.add(restTemplateInterceptor);
restTemplate.setInterceptors(list);
return restTemplate;
}
/*@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory){
return new RestTemplate(factory);
}*/
/**
* 创建 RestTemplate 时需要一个 ClientHttpRequestFactory,
* 通过这个请求工厂,我们可以统一设置请求的超时时间,设置代理以及一些其他细节。
* 通过上面代码配置后,我们直接在代码中注入 RestTemplate 就可以使用了。
* @return
*/
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
//设置超时的时间
factory.setConnectTimeout(10000);
//客户端从服务端读取数据的超时时间
factory.setReadTimeout(10000);
// 设置代理
//factory.setProxy(null);
return factory;
}
}
postForLocation方法
public URI postForLocation(String url, @Nullable Object request, Object... uriVariables)
public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables)
/**
*不做过多的介绍了
* 主要是与上面的也大差不差。
*/
最后我们看restTemplate中最丰富的一个方法。不用配置拦截器也能实现设置请求头。
exchange这个方法的重载也不少
public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables)
public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
@Nullable HttpEntity<?> requestEntity, Class<T> responseType, Map<String, ?> uriVariables)
参数一:url 请求路径
参数二:method 请求方式
参数三:requestEntity
这个可以设置请求体和请求头,我们看一下这个类的构造器,我挑了一个参数最多的构造器。
很明显第一个参数就是请求体,第二个参数就是设置请求头的一个map。
也就是说我们不用设置拦截器就可以实现复杂的http请求
public HttpEntity(@Nullable T body, @Nullable MultiValueMap<String, String> headers) {
this.body = body;
HttpHeaders tempHeaders = new HttpHeaders();
if (headers != null) {
tempHeaders.putAll(headers);
}
this.headers = HttpHeaders.readOnlyHttpHeaders(tempHeaders);
}
参数四:responseType 响应值类型
参数五:url参数 也可以理解为请求行参数。
底下是一个实列。
/**
* get请求设置请求头!
* 设置url参数
*/
@Test
void testGetRequestForShop() {
long shopId = 1l;
/**
* authorization: ba8d06d954a04c32bc1e75e2625fe192
*/
String url="http://127.0.0.1:8081/shop/{id}";
HttpHeaders httpHeaders=new HttpHeaders();
httpHeaders.add("authorization","ba8d06d954a04c32bc1e75e2625fe192");
HttpEntity httpEntity=new HttpEntity(httpHeaders);
ResponseEntity<Result> result = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Result.class, shopId);
System.out.println(result.getStatusCode());
System.out.println("============header==============");
System.out.println(result.getHeaders());
System.out.println("=============result==============");
Object data = result.getBody().getData();
System.out.println(data);
}
Entity=new HttpEntity(httpHeaders);
ResponseEntity result = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Result.class, shopId);
System.out.println(result.getStatusCode());
System.out.println("============header==============");
System.out.println(result.getHeaders());
System.out.println("=============result==============");
Object data = result.getBody().getData();
System.out.println(data);
}