一,SpringCloud注册中心
1, SpringCloud支持三种注册中心:Eureka,Zookeeper,Consul。本篇对Eureka进行演示
2,Eureka注册中心分为三个部分实现服务间发现和调用:Eureka注册中心服务端,Eureka注册中心客户端_生产者,Eureka注册中心客户端_消费者。如下图所示,Eureka服务通过两台服务构建集群,集群间信息复制,实现Eureka注册中心的服务高可用;三个客户端服务可以互为生产者和消费者,在Eureka注册中心注册自身服务或获取服务路径实现服务调用。
二,代码变现
1,服务结构
* 两个Eureka服务端项目,实现集群效果
* 两个Member项目为客户端生产者,实现负载均衡(SpringCloud默认通过Ribbon实现负载均衡)
* Order项目为客户端消费者,实现服务调用
2,Eureka服务端
a,Maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<!-- 管理依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.M7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!--SpringCloud eureka-server -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
b,配置文件
* server_1配置信息
###服务端口号
server:
port: 8000
###eureka 基本信息配置
eureka:
instance:
###注册到eureka ip地址
hostname: 127.0.0.1
client:
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:7900/eureka/
###注册自身到其他Server服务器,单点为false
register-with-eureka: true
fetch-registry: true
* server_2配置信息
###服务端口号
server:
port: 7900
###eureka 基本信息配置
eureka:
instance:
###注册到eureka ip地址
hostname: 127.0.0.1
client:
serviceUrl:
defaultZone: http://${eureka.instance.hostname}:8000/eureka/
###注册自身到其他Server服务器,单点为false
register-with-eureka: true
fetch-registry: true
c,启动Main函数
package com.gupao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
/**
* @author pj_zhang
* @create 2019-01-08 21:23
**/
// 开启Eureka服务
@EnableEurekaServer
@SpringBootApplication
public class EurekaServerApp {
public static void main(String[] args) {
SpringApplication.run(EurekaServerApp.class, args);
}
}
d,启动效果
* ERROR:com.netflix.discovery.shared.transport.TransportException: Cannot execute request on any known server;该问题是因为集群服务互相注册,单服务启动有先后顺序,先启动服务不能注册到未启动服务,服务未发现,稍等即可,无需处理!
* 启动后,直接访问服务,页面效果如下
3,Eureka客户端_生产者
a,生产者为Member_1、Member_2两个,用来演示SpringCloud默认支持的Ribbon负载均衡
b,Maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<!-- 管理依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.M7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot整合eureka客户端, eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
<!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
c,Member_1配置信息
###服务启动端口号
server:
port: 8200
###服务名称(服务注册到eureka名称)
spring:
application:
name: app-itmayiedu-member
###服务注册到eureka地址, 因为是集群, 注册到两个注册中心, 用逗号隔开
eureka:
client:
service-url:
defaultZone: http://localhost:8000/eureka,http://localhost:7900/eureka
###因为该应用为注册中心,不会注册自己
register-with-eureka: true
###是否需要从eureka上获取注册信息
fetch-registry: true
d,Member_2配置信息
###服务启动端口号
server:
port: 8300
###服务名称(服务注册到eureka名称)
spring:
application:
name: app-itmayiedu-member
###服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:8000/eureka,http://localhost:7900/eureka
###因为该应用为注册中心,不会注册自己
register-with-eureka: true
###是否需要从eureka上获取注册信息
fetch-registry: true
e,生产者服务接口
package com.gupao.springcloud.test.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author pj_zhang
* @create 2019-01-08 21:52
**/
@RestController
public class MemberController {
@Value("${server.port}")
private Integer port;
// RestTemplate方式进行调用
@RequestMapping("/sendMessage")
public String sendMessage() {
return "MemberController sendMessage, port : " + port;
}
// Feign客户端方式调用
@RequestMapping("/getMemberByFeign")
public String getMemberByFeign() {
return "MemberController getMemberByFeign, port : " + port;
}
}
f,启动Main函数
package com.gupao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
/**
* @author pj_zhang
* @create 2019-01-08 21:49
**/
// Eureka客户端
@EnableEurekaClient
@SpringBootApplication
public class MemberApp {
public static void main(String[] args) {
SpringApplication.run(MemberApp.class, args);
}
}
g,启动效果
* 此时在8000端口服务上存在服务注册信息,而7900端口服务上不存在;这是因为注册中心服务的主从关系,如果8000服务宕机,则会复制信息到7900端口服务上;注册信息复制可能存在30S的时差
* 直接通过SpringBoot方式访问接口;如图,生产者服务启动成功
4,Eureka客户端_消费者
a,消费者服务可以通过两种方式进行服务访问:RestTemplate方式和声明式Feign方式,此处会分别进行演示
b,Maven依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.1.RELEASE</version>
</parent>
<!-- 管理依赖 -->
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Finchley.M7</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- SpringBoot整合Web组件 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot整合eureka客户端 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 声明式feign方式进行服务调用 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
</dependencies>
<!-- 注意: 这里必须要添加, 否者各种依赖有问题 -->
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/libs-milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
c,配置文件
###服务启动端口号
server:
port: 8100
###服务名称(服务注册到eureka名称)
spring:
application:
name: app-itmayiedu-order
###服务注册到eureka地址
eureka:
client:
service-url:
defaultZone: http://localhost:8000/eureka,http://localhost:7900/eureka
###因为该应用为注册中心,不会注册自己
register-with-eureka: true
###是否需要从eureka上获取注册信息
fetch-registry: true
d,RestTemplate方式访问
* 服务接口调用
package com.gupao.springcloud.test.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
/**
* @author pj_zhang
* @create 2019-01-08 21:46
**/
@RestController
public class OrderController {
@Autowired
private DiscoveryClient discoveryClient;
@Autowired
private RestTemplate restTemplate;
@RequestMapping("/orderToMember")
public String orderToMember() {
// 获取所有服务, 此处只是展示
System.out.println(discoveryClient.getServices());
String result = restTemplate.getForObject("http://app-itmayiedu-member/sendMessage", String.class);
return result;
}
}
* 启动Main函数
package com.gupao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author pj_zhang
* @create 2019-01-08 21:45
**/
@EnableEurekaClient
@SpringBootApplication
@EnableFeignClients
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class, args);
}
/**
* 服务调用如果通过ip:port进行调用, 该步骤可省略
* 服务调用如果通过application_name进行调用,如当前演示,则必须手动添加RestTemplate的Bean实现
* 并添加@LoadBalanced注解:此处以为,使用application_name进行服务发现后,
* 可能存在服务名称对应下的多个服务节点,添加该注解用来实现负载均衡
* @return
*/
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
* 启动效果如下
e,Feign客户端访问
* 项目结构如下;Maven依赖已经在上一步引入,可以回头查看
* 声明式feign接口
package com.gupao.springcloud.test.feign;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author pj_zhang
* @create 2019-01-09 22:20
**/
// 需要调用的目标服务服务名称
@FeignClient(name = "app-itmayiedu-member")
public interface MemberFeign {
// 目标服务服务路径, 该路径需要与服务端路径统一, 用来实现路由处理
@RequestMapping("/getMemberByFeign")
String getMemberByFeign();
}
* 服务调用接口
package com.gupao.springcloud.test.controller;
import com.gupao.springcloud.test.feign.MemberFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author pj_zhang
* @create 2019-01-09 22:29
**/
@RestController
public class OrderFeignController {
@Value("${server.port}")
private Integer serverPort;
// 注入声明式Feign接口
@Autowired
private MemberFeign memberFeign;
@RequestMapping("/getMemberByFeign")
public String feignGetMember() {
// 通过注入的Feign接口直接调用服务, 底层会进行服务访问路径拼接并访问服务
return memberFeign.getMemberByFeign();
}
}
* 启动Main函数
package com.gupao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author pj_zhang
* @create 2019-01-08 21:45
**/
@EnableEurekaClient
@SpringBootApplication
// 允许通过声明式Feign客户端启动
@EnableFeignClients
public class OrderApp {
public static void main(String[] args) {
SpringApplication.run(OrderApp.class, args);
}
}
* 启动效果如下