目录
- 前言
- 一、Eureka介绍
- 二、构建EurekaServer端
- 三、构建EurekaClient端-producer
- 四、构建EurekaClient端-consumer
- 五、服务剔除测试(集群)
前言
- 上一节中我们介绍了服务治理并使用HttpClient实现了RPC远程调用
- 但是还存问题,如果生产者的ip和端口号改变,消费者的代码就势必要进行修改
- 本节我们将介绍Eureka服务注册中心来解决该问题
一、Eureka介绍
- 1.Eureka是什么
- Euraka是Spring Cloud集合中一个组件,它是对Euraka的集成,用于服务注册和发现
- 2.Eureka组成
- Eureka由多个instance(服务实例)组成,这些服务实例可以分为两种:Eureka Server和Eureka Client。为了便于理解,我们将Eureka client再分为Service Provider和Service Consumer。
- Eureka Server:提供服务注册和发现
- Service Provider:服务提供方,将自身服务注册到Eureka,从而使服务消费方能够找到
- Service Consumer:服务消费方,从Eureka获取注册服务列表,从而能够消费服务
二、构建EurekaServer端
- 1.新建项目spring-cloud-eureka-server
- 2.pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-serverartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Finchley.RC2version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<repositories>
<repository>
<id>spring-milestonesid>
<name>Spring Milestonesname>
<url>https://repo.spring.io/milestoneurl>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
repositories>
server:
port: 9090 #服务注册中心端口号
spring:
application:
name: spring-cloud-eureka-server
eureka:
instance:
hostname: 127.0.0.1 #服务注册中心IP地址
client:
registerWithEureka: false #是否向服务注册中心注册自己
fetchRegistry: false #是否检索服务
serviceUrl: #服务注册中心的配置内容,指定服务注册中心的位置
defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
@SpringBootApplication
@EnableEurekaServer
public class AppEurekaServer {
public static void main(String[] args) {
SpringApplication.run(AppEurekaServer.class);
}
}
- 5.验证Eureka是否启动成功
- 访问地址:http://127.0.0.1:9090/
- 若出现如下界面,说明EurekaServer端启动成功了
三、构建EurekaClient端-producer
- 1.新建项目spring-cloud-eureka-client-producer
- 2.pom依赖
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Finchley.RC2version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<repositories>
<repository>
<id>spring-milestonesid>
<name>Spring Milestonesname>
<url>https://repo.spring.io/milestoneurl>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
repositories>
server:
port: 7070
spring:
application:
name: sjyl-producer-member #服务名称,在注册中心展示服务名称
eureka:
client:
serviceUrl: #服务注册中心接口地址
defaultZone: http://127.0.0.1:9090/eureka/
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class MemberService {
@RequestMapping("/getMember")
public String getMember() {
return "我是会员服务,我提供接口";
}
}
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class AppProducer {
public static void main(String[] args) {
SpringApplication.run(AppProducer.class);
}
}
- 5.启动producer后访问Eureka
- 访问地址:http://127.0.0.1:9090/
四、构建EurekaClient端-consumer
- 1.新建项目spring-cloud-eureka-client-consumer
- 2.pom依赖
<dependencies>
<dependency>
<groupId>org.apache.httpcomponentsgroupId>
<artifactId>httpclientartifactId>
<version>4.5.5version>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>Finchley.RC2version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<repositories>
<repository>
<id>spring-milestonesid>
<name>Spring Milestonesname>
<url>https://repo.spring.io/milestoneurl>
<snapshots>
<enabled>falseenabled>
snapshots>
repository>
repositories>
server:
port: 8080
spring:
application:
name: sjyl-consumer-order #服务名称,在注册中心展示服务名称
eureka:
client:
serviceUrl: #服务注册中心接口地址
defaultZone: http://127.0.0.1:9090/eureka/
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class HttpClientUtils {
private static final CloseableHttpClient httpClient;
public static final String CHARSET = "UTF-8";
private static final Log log = LogFactory.getLog(HttpClientUtils.class);
static {
RequestConfig config = RequestConfig.custom().setConnectTimeout(60000).setSocketTimeout(15000).build();
httpClient = HttpClientBuilder.create().setDefaultRequestConfig(config).build();
}
public static String doGet(String url, Map<String, String> params) {
return doGet(url, params, CHARSET);
}
public static String doPost(String url, Map<String, String> params) throws IOException {
return doPost(url, params, CHARSET);
}
public static String doGet(String url, Map<String, String> params, String charset) {
try {
if (params != null && !params.isEmpty()) {
List<NameValuePair> pairs = new ArrayList<NameValuePair>(params.size());
for (Map.Entry<String, String> entry : params.entrySet()) {
String value = entry.getValue();
if (value != null) {
pairs.add(new BasicNameValuePair(entry.getKey(), value));
}
}
url += "?" + EntityUtils.toString(new UrlEncodedFormEntity(pairs, charset));
}
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse response = httpClient.execute(httpGet);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200) {
httpGet.abort();
throw new RuntimeException("HttpClient,error status code :" + statusCode);
}
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
result = EntityUtils.toString(entity, "utf-8");
}
EntityUtils.consume(entity);
response.close();
return result;
} catch (Exception e) {
log.error("请求服务器端出错:" + e);
return null;
}
}
public static String doPost(String url, Map<String, String> params, String charset)
throws IOException {
List<NameValuePair> pairs = null;
if (params != null && !params.isEmpty()) {
pairs = new ArrayList<NameValuePair>(params.size());
for (Map.Entry<String, String> entry : params.entrySet()) {
String value = entry.getValue();
if (value != null) {
pairs.add(new BasicNameValuePair(entry.getKey(), value));
}
}
}
HttpPost httpPost = new HttpPost(url);
if (pairs != null && pairs.size() > 0) {
httpPost.setEntity(new UrlEncodedFormEntity(pairs, CHARSET));
}
CloseableHttpResponse response = null;
try {
response = httpClient.execute(httpPost);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200) {
httpPost.abort();
throw new RuntimeException("HttpClient,error status code :" + statusCode);
}
HttpEntity entity = response.getEntity();
String result = null;
if (entity != null) {
result = EntityUtils.toString(entity, "utf-8");
}
EntityUtils.consume(entity);
return result;
} catch (ParseException e) {
log.error("请求服务器端出错:" + e);
return null;
} finally {
if (response != null)
response.close();
}
}
}
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class OrderToMemberService {
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/orderToMember")
public String orderToMember() {
List<ServiceInstance> instances = discoveryClient.getInstances("sjyl-member");
ServiceInstance serviceInstance = instances.get(0);
String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";
return "订单服务调用会员服务:" + HttpClientUtils.doGet(memberUrl, null);
}
}
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
public class AppConsumer {
public static void main(String[] args) {
SpringApplication.run(AppConsumer.class);
}
}
- 7.Eureka注册中心
- 访问地址:http://127.0.0.1:9090/
- 8.测试
- 访问地址:http://127.0.0.1:8080/orderToMember
五、服务剔除测试(集群)
- 1.spring-cloud-eureka-client-producer中新增启动类AppProducer2
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class AppProducer2 {
public static void main(String[] args) {
SpringApplication.run(AppProducer2.class);
}
}
- 2.application.yml修改下端口号为7071
server:
port: 7071
spring:
application:
name: sjyl-producer-member #服务名称,在注册中心展示服务名称
eureka:
client:
serviceUrl: #服务注册中心接口地址
defaultZone: http://127.0.0.1:9090/eureka/
- 3.启动AppProducer2访问Dureka
- 访问地址:http://127.0.0.1:9090/
- 可以看到Producer有2个,这个也是模拟集群测试
- 4.修改spring-cloud-eureka-client-consumer的orderToMember
import com.sjyl.util.HttpClientUtils;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class OrderToMemberService {
@Autowired
private DiscoveryClient discoveryClient;
@RequestMapping("/orderToMember")
public String orderToMember() {
List<ServiceInstance> instances = discoveryClient.getInstances("sjyl-producer-member");
ServiceInstance serviceInstance = instances.get(0);
String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";
return "port=" + serviceInstance.getPort() + " 订单服务调用会员服务:" + HttpClientUtils.doGet(memberUrl, null);
}
}
- 5.测试1:AppProducer和AppProducer2同时开启
- 访问:http://127.0.0.1:8080/orderToMember
- 6.测试2:关闭AppProducer,只开启AppProducer2
- 稍等一会后,Eureka会自动将AppProducer剔除,即7070端口的生产者服务剔除
- 访问:http://127.0.0.1:8080/orderToMember