一、首先创建一个父项目,名称 springcloud
注意,springcloud和springboot的版本是有对应的,(如,本项目中,springboot版本为 2.3.7.BUILD-SNAPSHOT ,springcloud 版本为 Hoxton.BUILD-SNAPSHOT),如果不一致,会出现很多问题,我这里是项目创建时,自动匹配的;
也可以以下网址查找对应的;
在线访问
https://start.spring.io/actuator/info
https://spring.io/projects/spring-cloud
二、创建服务提供者 在父工程下,创建一个子module,项目名称 eureka-provider
创建一个接口,我们这里直接返回数据
package com.hnyc.eurekaprovider.controller;
import com.hnyc.eurekaprovider.bean.Goods;
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;
/**
* create by hyq on 2020/11/18
*/
@RestController
@RequestMapping("/goods")
public class GoodsController {
@GetMapping("/findOne/{id}")
public Goods findOne(@PathVariable("id") int id) {
Goods goods = new Goods();
goods.setId(1);
goods.setTitle("华为手机");
goods.setPrice(10000);
goods.setCount(10000);
return goods;
}
}
package com.hnyc.eurekaprovider.bean;
import lombok.Data;
/**
* create by hyq on 2020/11/18
*/
@Data
public class Goods {
private int id;
private String title;//商品标题
private double price;//商品价格
private int count;//商品库存
}
application.yml配置端口
server:
port: 8000
三、创建服务消费者
项目名称 eureka-consumer,项目创建方法参考 eureka-provider。
添加以下三个类
package com.hnyc.eurekaconsumer.bean;
import lombok.Data;
/**
* create by hyq on 2020/11/18
*/
@Data
public class Goods {
private int id;
private String title;//商品标题
private double price;//商品价格
private int count;//商品库存
}
package com.hnyc.eurekaconsumer.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
/**
* create by hyq on 2020/11/18
*/
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
package com.hnyc.eurekaconsumer.controller;
import com.hnyc.eurekaconsumer.bean.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;
/**
* create by hyq on 2020/11/18
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id) {
String url = "http://localhost:8080/goods/findOne/" + id;
// 3. 调用方法
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
四、访问消费者接口
http://localhost:8081/order/goods/1 ,返回成功
但可以看到,访问服务访问路径的代码写死了,我们需要系统能动态获取路径。
五、使用Eureka配置动态路径
创建一个新module ,名 eureka-server
修改pom.xml文件
<!-- 父项目 -->
<parent>
<groupId>com.hnyc</groupId>
<artifactId>springcloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 添加 eureka-server端jar包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
启动类上添加注解
package com.hnyc.eurekaserver;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
// 启用EurekaServer ,如果 springboot 和 springcloud版本不对应,这里会找不到或者无法引入这个注解
@EnableEurekaServer
public class EurekaServerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApplication.class, args);
}
}
application.yml添加配置
server.port: 9090
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://${eureka.instance.hostname}:${server.port}/${spring.application.name} # eureka服务端地址,将来客户端使用该地址和eureka进行通信
register-with-eureka: false # 是否将自己的路径 注册到eureka上。eureka server 不需要的,eureka provider client 需要
fetch-registry: false # 是否需要从eureka中抓取路径。eureka server 不需要的,eureka consumer client 需要
spring:
application:
name: eureka
六、调整 服务提供方 eureka-provider
pom.xml 修改
<parent>
<groupId>com.hnyc</groupId><!-- 父项目 -->
<artifactId>springcloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 添加 eureka-client 端jar包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
启动类添加配置
package com.hnyc.eurekaprovider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApplication.class, args);
}
}
application.yml 添加配置
server:
port: 8080
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://localhost:9090/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
七、修改 服务消费端 eureka-consumer
pom.xml 修改
<parent>
<groupId>com.hnyc</groupId><!-- 父项目 -->
<artifactId>springcloud</artifactId>
<version>0.0.1-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!-- 添加 eureka-client 端jar包 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
启动类添加配置
package com.hnyc.eurekaconsumer;
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 // 激活DiscoveryClient
public class EurekaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
}
application.yml添加配置
server:
port: 8081
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://localhost:9090/eureka # eureka服务端地址,将来客户端使用该地址和eureka进行通信
spring:
application:
name: eureka-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
修改原来controller,改为动态获取访问路径
package com.hnyc.eurekaconsumer.controller;
import com.hnyc.eurekaconsumer.bean.Goods;
import java.util.List;
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;
/**
* create by hyq on 2020/11/18
*/
@RestController
@RequestMapping("/order")
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient;
// @GetMapping("/goods/{id}")
// public Goods findGoodsById(@PathVariable("id") int id) {
// String url = "http://localhost:8080/goods/findOne/" + id;
// // 3. 调用方法
// Goods goods = restTemplate.getForObject(url, Goods.class);
// return goods;
// }
@Autowired
private RestTemplate restTemplate;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id) {
//演示discoveryClient 使用
List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
//判断集合是否有数据
if (instances == null || instances.size() == 0) {
//集合没有数据
return null;
}
ServiceInstance instance = instances.get(0);
String host = instance.getHost();//获取ip
int port = instance.getPort();//获取端口
String url = "http://" + host + ":" + port + "/goods/findOne/" + id;
// 调用方法
Goods goods = restTemplate.getForObject(url, Goods.class);
return goods;
}
}
八、至此,eureka基本配置完成
尝试 启动 eureka-server、eureka-provider、eureka-consumer 三个项目
启动后,访问尝试调用消费者接口
http://localhost:8081/order/goods/1
调用成功。
九、整合feign
如果你觉得 刚刚 controller层 的写法稍显复杂,可以使用 feign 代替 RestTemplate
修改服务调用方 eureka-consumer 的代码
pom.xml 添加以下jar包
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
<version>11.0</version>
</dependency>
启动类添加注解
package com.hnyc.eurekaconsumer;
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;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableEurekaClient
@EnableDiscoveryClient // 激活DiscoveryClient
@EnableFeignClients //添加 feign
public class EurekaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
}
application.yml添加配置
feign:
hystrix:
enabled: true
compression:
request:
enabled: true
mime-types: ["text/xml","application/xml","application/json"]
min-request-size: 2048
response:
enabled: true
client:
config:
default:
logger-level: basic
feign-provider-demo1:
logger-level: full
hystrix:
command:
default: #default全局有效,service id指定应用有效
execution:
timeout:
enabled: true
isolation:
thread:
timeoutInMilliseconds: 20000 #断路器超时时间,默认1000ms
添加需要调用的接口声明类 RemoteService
package com.hnyc.eurekaconsumer.feign;
import com.hnyc.eurekaconsumer.bean.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* create by hyq on 2020/11/18
*/
@FeignClient("eureka-provider") //调用端服务名
public interface RemoteService {
@GetMapping(value = "/goods/findOne/{id}")
Goods findGoodsById(@PathVariable("id") int id);
}
修改原来controller的调用方法
package com.hnyc.eurekaconsumer.controller;
import com.hnyc.eurekaconsumer.bean.Goods;
import com.hnyc.eurekaconsumer.feign.RemoteService;
import org.springframework.beans.factory.annotation.Autowired;
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;
/**
* create by hyq on 2020/11/18
*/
@RestController
@RequestMapping("/order")
public class OrderController {
// @Autowired
// private DiscoveryClient discoveryClient;
// @GetMapping("/goods/{id}")
// public Goods findGoodsById(@PathVariable("id") int id) {
// String url = "http://localhost:8080/goods/findOne/" + id;
// // 3. 调用方法
// Goods goods = restTemplate.getForObject(url, Goods.class);
// return goods;
// }
// @Autowired
// private RestTemplate restTemplate;
//
// @GetMapping("/goods/{id}")
// public Goods findGoodsById(@PathVariable("id") int id) {
// //演示discoveryClient 使用
// List<ServiceInstance> instances = discoveryClient.getInstances("EUREKA-PROVIDER");
//
// //判断集合是否有数据
// if (instances == null || instances.size() == 0) {
// //集合没有数据
// return null;
// }
//
// ServiceInstance instance = instances.get(0);
// String host = instance.getHost();//获取ip
// int port = instance.getPort();//获取端口
// String url = "http://" + host + ":" + port + "/goods/findOne/" + id;
// // 调用方法
// Goods goods = restTemplate.getForObject(url, Goods.class);
// return goods;
// }
@Autowired
private RemoteService remoteService;
@GetMapping("/goods/{id}")
public Goods findGoodsById(@PathVariable("id") int id) {
return remoteService.findGoodsById(id);
}
}
再次启动 eureka-server、eureka-provider、eureka-consumer 三个项目,访问接口 http://localhost:8081/order/goods/1
返回成功,