服务注册与消费
服务注册
将微服务注册到Eureka Server上,当其他服务需要调用该服务时,只需要从Eureka Server上查询该服务信息即可
例如:创建一个provider服务,创建时选择Eureka Discovery Client依赖,
在经过简单的配置,该服务就可以被注册到Eureka上
选择Eureka Discovery Client依赖
注意:微服务应该是一个web工程,否则运行完成后会自动停止。
项目创建成功后,在配置文件中配置注册地址,配置方法类似于配置Eureka集群
#服务名称
spring.application.name=provider
#端口号
server.port=1113
#注册地址
eureka.client.service-url.defaultZone=http://localhost:111/eureka
先启动服务注册中心,在启动provider项目,即可完成服务注册,可进入Eureka控制台查看provider的注册信息。
服务消费
在provider中添加一个测试接口
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(){
return "hello cloud";
}
}
新建一个consumer模块,访问provider中的接口,若想访问provider中的接口,就需要去Eureka中查询。consumer中添加web、Eureka Discovery Client依赖,并对consumer的注册信息进行配置。
选择Eureka Discovery Client依赖
#服务名称
spring.application.name=consumer
#端口号
server.port=1114
#注册地址
eureka.client.service-url.defaultZone=http://localhost:1111/eureka
编写测试接口,访问provider服务中的hello接口
@RestController
public class UserHelloController {
@Autowired
DiscoveryClient discoveryClient;
@GetMapping("hello1")
public String hello1(){
//因为返回的服务可能是一个集群,所以返回的是一个List
List<ServiceInstance> list = discoveryClient.getInstances("provider");
//拿出list中的provider实例
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
StringBuffer sb = new StringBuffer();
sb.append("http://")
.append(host)
.append(":")
.append(port)
.append("/hello");
HttpURLConnection con = null;
try {
URL url = new URL(sb.toString());
con = (HttpURLConnection) url.openConnection();
if(con.getResponseCode()==200){
BufferedReader br = new BufferedReader(new InputStreamReader(con.getInputStream()));
String s = br.readLine();
br.close();
return s;
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return "error";
}
}
利用HttpUrlConnection发起请求,借助Eureka Client提供的DiscoveryClient工具,根据服务名称从Eureka Server中拿到服务的详细信息,并拼接成完整的地址,访问provider服务。
这里discoveryClient查询到的服务列表的是一个集合,因为查询到的服务可能是一个集群化部署的服务,所以返回的是一个List。集合中的每个元素就是一个服务的实例。
消费服务优化
在上面的代码中,http调用过于复杂,并且存在大量重复代码。这里可以用
spring提供的RestTemplate对代码进行优化
首先在当前服务的启动类中提供一个RestTemplate的实例
@Bean
RestTemplate restTemplate(){
return new RestTemplate();
}
然后在http调用时,直接使用RestTemplate
@GetMapping("hello1")
public String hello1() {
//因为返回的服务可能是一个集群,所以返回的是一个List
List<ServiceInstance> list = discoveryClient.getInstances("provider");
//拿出list中的provider实例
ServiceInstance instance = list.get(0);
String host = instance.getHost();
int port = instance.getPort();
StringBuffer sb = new StringBuffer();
sb.append("http://")
.append(host)
.append(":")
.append(port)
.append("/hello");
String s = restTemplate.getForObject(sb.toString(), String.class);
return s;
}
一行代码就可以实现http调用。
利用Ribbon实现负载均衡
首先给RestTemplate实例添加@LoadBalanced注解,开启负载均衡。
@Bean
@LoadBalanced
RestTemplate restTemplate(){
return new RestTemplate();
}
此时的RestTemplate就具备了负载均衡的能力。
之后在controller中注入RestTemplate,并调用provider中的接口
@Autowired
@Qualifier("restTemplate")
RestTemplate restTemplate;
@GetMapping("/hello2")
public String hello2() {
return restTemplate.getForObject("http://provider/hello",String class);
}
接口的url只声明是provider中的hello接口,具体地址由负载均衡后计算得到。
将provider项目打包,分别从两个端口启动项目。通过consumer调用provider服务,可以看到负载均衡后,可以通过一个地址访问多个端口的服务。
image
image