三、Eureka服务注册中心

前言

  • 上一节中我们介绍了服务治理并使用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.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.RC2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

  • 3.application.yml
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/
  • 4.AppEurekaServer
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.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Finchley.RC2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>
  • 2.application.yml
server:
  port: 7070
spring:
  application:
    name: sjyl-producer-member #服务名称,在注册中心展示服务名称
eureka:
  client:
    serviceUrl: #服务注册中心接口地址
      defaultZone: http://127.0.0.1:9090/eureka/
  • 3.新增MemberService
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MemberService {

    /**
     * 会员服务提供接口
     */
    @RequestMapping("/getMember")
    public String getMember() {
        return "我是会员服务,我提供接口";
    }
}
  • 4.AppProducer
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.httpcomponents</groupId>
            <artifactId>httpclient</artifactId>
            <version>4.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Finchley.RC2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <repositories>
        <repository>
            <id>spring-milestones</id>
            <name>Spring Milestones</name>
            <url>https://repo.spring.io/milestone</url>
            <snapshots>
                <enabled>false</enabled>
            </snapshots>
        </repository>
    </repositories>
 
  • 3.application.yml
server:
  port: 8080
spring:
  application:
    name: sjyl-consumer-order #服务名称,在注册中心展示服务名称
eureka:
  client:
    serviceUrl: #服务注册中心接口地址
      defaultZone: http://127.0.0.1:9090/eureka/
  • 4.工具类HttpClientUtils
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);

    // 采用静态代码块,初始化超时时间配置,再根据配置生成默认httpClient对象
    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);
    }

    /**
     * HTTP Get 获取内容
     *
     * @param url     请求的url地址 ?之前的地址
     * @param params  请求的参数
     * @param charset 编码格式
     * @return 页面内容
     */
    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进行拼接
                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;
        }

    }

    /**
     * HTTP Post 获取内容
     *
     * @param url     请求的url地址 ?之前的地址
     * @param params  请求的参数
     * @param charset 编码格式
     * @return 页面内容
     * @throws IOException
     */
    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();
        }
    }
}


  • 5.OrderToMemberService
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);
        // 会员服务的ip和端口
        String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";
        return "订单服务调用会员服务:" + HttpClientUtils.doGet(memberUrl, null);
    }
}
  • 6.消费者启动类AppConsumer
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
    • 增加端口打印后,重新启动AppConsumer
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);
        // 会员服务的ip和端口
        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

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无休止符

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值