您的位置:首页 > 编程语言 > Java开发

Spring Cloud学习笔记2——客户端服务调用及负载均衡

2017-11-28 16:16 555 查看
全部代码见:

注册中心(EurekaServer):https://gitee.com/wudiyong/EurekaServer.git

服务提供者(userInfoService):https://gitee.com/wudiyong/userInfoService.git

服务调用者(ribbonConsumer):https://gitee.com/wudiyong/ribbonConsumer.git

通过RestTemplate进行服务调用

在RestTemplate基础上加上负载均衡:

Ribbon是一个基于HTTP和TCP的负载均衡工具,可以让我们轻松的将面向服务的Rest模板请求自动转换成客户端负载均衡的服务调用。它不像注册中心、配置中心和网关那样需要独立部署,它几乎存在于每一个微服务应用中,因为微服务间的调用、网关的请求转发都需要用到ribbon。

1、使用Ribbon实现负载均衡调用只需3步:

1)在pom.xml文件中加入Ribbon依赖

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>

2)创建一个被@LoadBalanced注解修饰的RestTemplate实例

可以在自定义的配置类中创建,但通常会放在入口类处(入口类本身也是一个配置类,因为@SpringBootApplication包含了@SpringBootConfiguration,@SpringBootConfiguration包含@Configuration),因为RestTemplate是一个与业务无关的基础bean。

@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}

3)调用服务

@RestController
public class ConsumerController {
@Autowired
RestTemplate restTemplate;
@RequestMapping(value="/userInfo", method = RequestMethod.GET)
public String userInfo(@RequestParam String name, @RequestParam String age) {
//如果是post请求,可以用postForEntity
Map<String , Object> params = new HashMap<String , Object>();
params.put("name", name);
params.put("age", age);
return restTemplate.getForEntity("http://USERINFO-SERVICE/userInfo?name={name}&age={age}",
String.class,params).getBody();
}
}



2、各种调用服务的方法

1)GET请求

GET请求有两种:getForEntity和getForObject

getForEntity:

该方法有3中重载实现,常用的是以下两种:

1、ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)

2、ResponseEntity<T> getForEntity(String url, Class<T> responseType,  Object... uriVariables)

第一个参数是请求的url,如果有参数,要写成如下方式:
http://USERINFO-SERVICE/userInfo?name={name}&age={age}http://USERINFO-SERVICE/userInfo?name={1}&age={2}
第二个参数是返回类型,如,返回字符串则为String.class,返回UserPojo对象则是UserPojo.class

第三个参数是url中的参数值,第一种采用map的方式,第二种采用变长参数的方式,map方式中,通过key与{xxx}中的字符串xxx对应,变长方式中,{n}对应第n个变长参数,n从1开始。

该方法返回的是ResponseEntity对象,通过调用其getBody()方法可以返回与第二个参数类型相同的对象,如第二个参数是UserPojo.class,则getBody()返回UserPojo对象,如:

ResponseEntity<UserPojo> responseEntity = restTemplate.getForEntity(
"http://USERINFO-SERVICE/userInfo?name={1}&age={2}", UserPojo.class,"谢谢谢","12");
UserPojo userPojo = responseEntity.getBody();


getForObject:

与getForEntity参数一样,只是返回值不同,getForObject直接返回与第二个参数相同的对象,即相当于getForEntity(....).getBody():

UserPojo userPojo = restTemplate.getForObject(
"http://USERINFO-SERVICE/userInfo?name={name}&age={age}", UserPojo.class,params);


2)POST请求

POST请求也有两种:postForEntity和postForObject

getForEntity:

有三种实现,常用以下两种:

1、ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)

2、ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)

其它参数与GET请求相同,只有第二个参数不一样,第二个参数可以是一个普通的对象,如UserPojo,也可以是一个HttpEntity对象,如果是普通对象,则该参数被当做成完整的body来处理,如果是HttpEntity对象,则该对象不仅包含body内容,还包含header内容。

第四个参数是用来对url中的参数进行绑定的,如果url中没有参数需要绑定,则可为空。

postForObject与getForEntity类似。

值得注意的是,POST请求发送json数据时,需要设置头部:

RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
HttpEntity<String> formEntity = new HttpEntity<String>(requestJsonStr, headers);
String jsonStr = restTemplate.postForEntity(url, formEntity,String.class).getBody();


声明式服务调用Feign

声明式服务调用Feign,整合了RestTemplate(用于服务调用)、Ribbon(处理负载均衡)、Hystrix(服务容错保护)

代码:https://gitee.com/wudiyong/ribbonConsumer.git

1、引入Feign+Hystrix依赖

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>

2、开启Feign及Hystrix功能

入口类加上如下注解:

@EnableFeignClients
@EnableHystrix也可以用feign.hystrix.enabled=true配置代替@EnableHystrix注解
3、创建调用远程服务的调用类

通常放在client包下,可以命名为RemoteServerName+Client

package com.ribbonConsumer.client;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.ribbonConsumer.client.fallback.UserInfoClientFallback;

/*
* name:被调用服务的服务名
* fallback:调用失败之后的回调类
*/
@FeignClient(name = "userInfo-service", fallback = UserInfoClientFallback.class)
public interface UserInfoClient {

/**
* userInfo-service服务中的/userInfoStr接口
* 写法与被调用的接口一样,只是没有方法体
* 注意:
* 1、如果通过@RequestParam接收参数,一定要加上(value="xxx"),否则启动报错,
* 这是因为spring-cloud-feign处理@RequestParam和Spring mvc的不一样,
* Spring mvc在@RequestParam的value为空的时候会通过反射得到参数的名字作为value
* 如果通过@RequestBody接收map或某个对象,则与普通接口一样
*/
@RequestMapping(value = "/userInfoStr", method = RequestMethod.GET)
public String userInfoStr(@RequestParam(value = "name") String name, @RequestParam(value = "age") String age);
}
4、创建调用失败的回调类

回调类是实现调用接口的一个普通类,没有任何特别,该类只有在调用失败的时候会被调用,如果请求能到达远程服务,只是远程服务返回一些错误信息,这种情况不属于调用失败,调用失败如网络不通、服务不可用情况
package com.ribbonConsumer.client.fallback;
import org.springframework.stereotype.Component;
import com.ribbonConsumer.client.UserInfoClient;
@Component
public class UserInfoClientFallback implements UserInfoClient{
@Override
public String userInfoStr(String name, String age) {
return "调用失败";
}
}
至此,Hystrix配置完成,可以开始测试了

可以在controller上加上如下代码用于测试:

@Autowired
private UserInfoClient userInfoClient;
/**
* 使用Feign方式调用服务
*/
@RequestMapping(value = "/userInfoStr", method = RequestMethod.GET)
public String userInfoStr(@RequestParam String name, @RequestParam String age){
return userInfoClient.userInfoStr(name, age);
}

可以分别测试userInfo-service服务可用和不可用两种情况




内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐