上一篇我们简单的介绍了注册中心Eureka的内容,这一篇我们接下来讲解的是服务的提供与调用。主要存在三种角色
1、注册中心
2、服务提供者提供服务并注册到注册中心
3、服务消费者从注册中心获取服务。
首先创建一个spring-boot项目vts_sc_provider。引入Maven配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
这里需要web的支持,所以引入web的jar包,注意这里引入的Eureka的jar包和注册中心引入的Jar包略有不同,是一个client的包。
新建Application启动类,直接用ide生成对应的main方法即可。
@SpringBootApplication
public class Application{
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
修改配置文件,指定注册中心和端口内容
spring:
application:
name: eureka-producer
eureka:
client:
service-url:
defaultZone: http://47.95.250.218:9001/eureka/
server:
port: 8001
新建Controller类,HelloController
@RestController
public class HelloControler {
@GetMapping("/test")
public String test(@RequestParam String name){
return "我是"+name;
}
}
然后启动项目:通过http://localhost:8001/test?name=大仙,进行访问这是可以进行提供服务的。
然后我们再次新建一个spring-boot项目vts_sc_consumer。引入相应的maven配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
创建服务消费者根据使用 API 的不同,大致分为三种方式。虽然大家在实际使用中用的应该都是 Feign,但是这里还是把这三种都介绍一下吧,如果你只关心 Feign,可以直接跳到最后。
设置配置文件内容:
spring:
application:
name: eureka-consumer
eureka:
client:
service-url:
defaultZone: http://47.95.250.218:9001/eureka/
server:
port: 8002
使用 LoadBalancerClient
从LoadBalancerClient
接口的命名中,我们就知道这是一个负载均衡客户端的抽象定义,下面我们就看看如何使用 Spring Cloud 提供的负载均衡器客户端接口来实现服务的消费。
修改启动类,初始化RestTemplate:
@SpringBootApplication
public class Application {
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Controller
创建一个接口用来消费 eureka-producer 提供的接口:
@RequestMapping("/hello")
@RestController
public class HelloController {
@Autowired
private LoadBalancerClient client;
@Autowired
private RestTemplate restTemplate;
@GetMapping("/")
public String hello(@RequestParam String name) {
name += "!";
ServiceInstance instance = client.choose("eureka-producer");
String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/hello/?name=" + name;
return restTemplate.getForObject(url, String.class);
}
}
可以看到这里,我们注入了LoadBalancerClient
和RestTemplate
,并在hello
方法中,先通过loadBalancerClient
的choose
方法来负载均衡的选出一个eureka-producer
的服务实例,这个服务实例的基本信息存储在ServiceInstance
中,然后通过这些对象中的信息拼接出访问服务调用者的/hello/
接口的详细地址,最后再利用RestTemplate
对象实现对服务提供者接口的调用。
Spring Cloud Ribbon
当 Ribbon 与 Eureka 联合使用时,ribbonServerList 会被 DiscoveryEnabledNIWSServerList 重写,扩展成从 Eureka 注册中心中获取服务实例列表。同时它也会用 NIWSDiscoveryPing 来取代 IPing,它将职责委托给 Eureka 来确定服务端是否已经启动。
修改启动类,增加注解@LoadBalanced
@LoadBalanced
@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
Controller
修改 controller,去掉LoadBalancerClient
,并修改相应的方法,直接用 RestTemplate
发起请求
@GetMapping("/")
public String hello(@RequestParam String name) {
name += "!";
String url = "http://eureka-producer/hello/?name=" + name;
return restTemplate.getForObject(url, String.class);
}
可能你已经注意到了,这里直接用服务名eureka-producer
取代了之前的具体的host:port
。那么这样的请求为什么可以调用成功呢?因为 Spring Cloud Ribbon 有一个拦截器,它能够在这里进行实际调用的时候,自动的去选取服务实例,并将这里的服务名替换成实际要请求的 IP 地址和端口,从而完成服务接口的调用。
Spring Cloud Feign
在实际工作中,我们基本上都是使用 Feign 来完成调用的。我们通过一个例子来展现 Feign 如何方便的声明对 eureka-producer 服务的定义和调用。
修改启动类:
@SpringBootApplication
@EnableFeignClients
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
新建一个Service类
@FeignClient(name = "eureka-producer")
public interface TestService {
@GetMapping("/test/")
String test(@RequestParam(value = "name") String name);
}
使用@FeignClient指定服务提供者,并且该类中的方法名和参数和远程服务提供者的controller保持一致。
新增TestController类:
@RestController
public class TestController {
@Autowired
TestService testService;
/**
* 参数做路径GET请求
* @param name
* @return
*/
@GetMapping("/test/{name}")
public String index(@PathVariable("name") String name) {
return testService.test(name + "!");
}
/**
* 参数不做路径GET请求
* @param name
* @return
*/
@GetMapping("/test1")
public String test1(String name) {
return testService.test(name + "!");
}
/**
* POST请求
* @param name
* @return
*/
@PostMapping("/pay/test2")
public String postTest(@RequestParam("name")String name){
return testService.test(name + "!");
}
}
启动应用进行访问:http://localhost:8002/test1?name=%E5%A4%A7%E4%BB%99 成功返回。