在使用spring-cloud 的时候我们在使用eureka作为注册中心(eureka-server)让服务的提供者和消费者( eureka-client)之间完成调用,而provider和consumer就是属于服务者和消费者,我们想要在consumer里面去调用provider里面的url我们如果直接调用就需要用到RestTemplate先作为一个单独的工具类添加,然后在通过@Autowired在消费房的controller里面注入,然后通过类得到他从服务方获取到的==》restTemplate.getForObject(url, 类名.class),然后在返回给服务器,就可以调用provider里面的url得到里面的值
创建提供者和消费者的时候我们创建的是maven项目,步骤如下
1.先创建一个空的项目,spring-cloud,把jdk还有maven仓库选好
2.创建一个父项目可以自由命名,这里我们命名为eureka-parent,创建的是maven的项目,创建父项目的好处是我们可以把项目真正的项目做为子项目开发而且直接久可以继承到父项目的依赖,euraka-parent的项目的pom.xml依赖导入为
<!--spring boot 环境 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
<relativePath/>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<!--spring cloud 版本-->
<spring-cloud.version>Greenwich.RELEASE</spring-cloud.version>
</properties>
<!--引入Spring Cloud 依赖-->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
3.分别创建出子模块eureka-provider和eureka-consumer,分别都先要添加springboot的依赖,因为在启动Application读取网页展示的时候需要用到这个依赖
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
4.创建好相关的模块之后我们需要把我们的provider里面框架搭建好,加包和分层,分别为:domain,controller,service,dao(eureka-provider) ;controller,domain,config(eureka-consumer)。domain:封装类的包;controller:控制类的包;service:接口类的包;dao:数据类的包;config:RestTemplate帮助调用的工具类包。
创建服务方的目的是为了将server作为注册中心,和redis差不多,然后provider里面的url存到server,这时候我们在consumer里面就可以通过server里面直接调用了,这样的好处是当我们provider里面的yml的接口发生变化的时候 ,我们consumer也能够自动的调用provider
创建eureka-server的时候我们需要用到的依赖为:
<dependencies>
<!--springboot依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-server 依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
eureka-server作为注册中心,需要存储provider的url地址需要在yml里面设置如下
server:
port: 8761
# eureka 配置
# eureka 一共有4部分 配置
# 1. dashboard:eureka的web控制台配置
# 2. server:eureka的服务端配置
# 3. client:eureka的客户端配置
# 4. instance:eureka的实例配置
eureka:
instance:
hostname: localhost #主机名
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
当eureka-server作为注册中心的时候我们在他的springboot启动app里面我们就需要加入server的注解,代码如下
package com.miracle.eureka;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication//这个注解是所有springboot的application需要启动都要加的注解
//启用EurekaServer
@EnableEurekaServer//这个就是当然作为server注册中心的时候,我们需要从这里那provider的地址的时候我们需要启动注册中心的
public class EurekaApp {
public static void main(String[] args) {
SpringApplication.run(EurekaApp.class,args);
}
}
我们在用consumer调用另外一个Eureka Client (服务提供者,服务的消费者)provider的时候我们就需要先使用到restTemplate帮助完成远程调用,这时候我们久需要先建一个工具类在config包下面,将我们的值先注册到springboot容器里面去代码如下
package com.miracle.consumer.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* 定义resttemplate的bean,可以将值存到容器里面
*/
@Configuration
public class GoodConfig {
//使用bean注解可以把值先注册到springboot容器里面去
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
注入到容器里面之后我们需要在需要调用的consumer的controller里面做注入和调用,但是这个只是固定的url,代码如下:
package com.miracle.consumer.controller;
import com.miracle.consumer.domain.Goods;
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;
import java.util.List;
/**
* 服务的调用方
*/
@RestController
@RequestMapping("/order")
public class ConsumerController {
//将得到的值注册到容器
@Autowired
private RestTemplate restTemplate;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
/**
* 调用注册中心
* 步骤
* 1.定义注册中心RestTemplate
* 2.注册RestTemplate
* 3.调用ResTemplate
*/
//这个是获取固定的url的时候得到的值
String url="http://localhost:8000/goods/findOne/"+id;
//开始调用提供方的值用url
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
做动态的调用之后我们的依赖也会新加入其他的东西需要在provider和consumer的pom.xml添加client的依赖
<dependencies>
<!--spring boot web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
除了要添加client的依赖之外我们还需要在启动的application里面添加另一个注释@EnableEurekaClient还有动态远程调用的@EnableDiscoveryClient
package com.miracle.consumer;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* 启动类
*/
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient //在做远程调用的时候我们必须要激活discoverClient
public class ConsumerApp {
public static void main(String[] args) {
SpringApplication.run(ConsumerApp.class,args);
}
}
做动态的provider和consumer的yml也需要发生改变,除了port和application。name不一样其他的基本是一样的
server:
port: 9000
eureka:
instance:
hostname: localhost #主机名
client:
service-url:
defaultZone: http://localhost:8761/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-consumer #这个是在server调用中心里面的application的名称,需要用这个名称来获取路径
当我们用到注册中心server之后我们久可以把这个地址改成动态的了,首先我们就需要添加eureka-server的yml如上面的一样在里面设置动态的localhost和端口port,这时候我们的eureka-consumer里面的代码就需要被改造如下:
package com.miracle.consumer.controller;
import com.miracle.consumer.domain.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
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;
import java.util.List;
/**
* 服务的调用方
*/
@RestController
@RequestMapping("/order")
public class ConsumerController {
//将得到的值注册到容器
@Autowired
private RestTemplate restTemplate;
@Autowired
private DiscoveryClient discoveryClient;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id){
System.out.println("findGoodsById:"+id);
//注册和调用,这里做的是远程调用,所以需要provider调用过来这时候我们在yml里面定义的application的那么发挥他的作用了
//这个得到的值是一个集合是因为有时候我们可以在provider里面得有多个url,所以这里返回的是一个集合
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
//因为是集合所以这时候我们是需要判断集合里面是不是空的,如果是空的那么我们返回一个固定的值,如果不是那么我们就返回里面集合的值,通过下标取值
if(instances==null || instances.size()==0){
//如果返回的值都是为空的那么我们返回一个空值
return null;
}
//如果返回的值不是为空的那么我们急需要取值
ServiceInstance serviceInstance = instances.get(0);
//通过取值的到里面的url的相关的值
String host = serviceInstance.getHost();
int port = serviceInstance.getPort();
//现在控制台打印,看看得到的数据是不是我们对应的localhost以及对应的端口号
System.out.println(host);
System.out.println(port);
/**
* 调用注册中心
* 步骤
* 1.定义注册中心RestTemplate
* 2.注册RestTemplate
* 3.调用ResTemplate
*/
//然后动态的获取我们得到的url做拼接
String url="http://"+host+":"+port+"/goods/findOne/"+id;
//开始调用提供方的值用url
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}