Spring Cloud_3_微服务发布与调用

微服务发布与调用

  • 认识Eureka框架
  • 运行Eureka服务器
  • 发布微服务
  • 调用微服务
  • 本章将讲述SpringCloud中Eureka的使用,包括在Eureka服务器上发布、调用微服务,Eureka的配置以及集群等内容

1、Eureka介绍

  • 提供了Eureka服务器端与客户端
  • 主要用于服务管理(维护服务列表,自动检查其状态)
  • SpringCloud集成了Netflix OSS的多个项目,形成了Spring-Cloud-Netflix项目,该项目包含了多个子模块,这些子模块对集成的Netflix旗下框架进行了封装
  • Spring Cloud Netflix提供了一系列搭建微服务基础架构的功能组件

    1. Eureka(服务注册与发现框架)
    2. Hystrix(服务容错组件):容错管理工具,旨在通过控制服务和第三方库的节点,从而对延迟和故障提供强大的容错能力
    3. Zuul(服务网关):边缘服务工具,提供动态路由、监控等边缘服务
    4. Ribbon(客户端负载均衡器):提供客服端负载均衡算法,将Netflix的中间层服务连接起来
    5. Feign(声明式Http客户端):可以创建声明式、模板化的Http客户端,进行微服务调用
  • 本小节将讲述其中一个较为重要的服务管理框架:Eureka[juˈri:kə]

1.1、关于Eureka

  • 一个基于REST风格的服务组件,用于定位服务,以实现云端的负载均衡和中间层服务器的故障转移
  • 提供了基于Java的客户端组件,使得与服务的交互更加方便
  • 客户端还有一个内置的负载均衡器,用于执行基本的轮询负载均衡,为业务组件的集群部署创造了条件
  • 使用该框架,可以将业务组件注册到Eureka容器中,进行集群部署
  • Eureka提供服务调用功能,可以发布容器中的服务并进行调用

1.2、Eureka架构

  • 一个简单的Eureka集群,需要一个Eureka服务器、若干个服务提供者
  • 将业务组件注册到Eureka服务器中,其他客户端组件可以向服务器获取服务并且进行远程调用

  • 图中有两个服务器,服务器支持集群部署,每个服务器也可以作为对方服务器的客户端进行相互注册与复制
  • 3个Eureka客户端,2个用于发布服务,1个用于调用服务
  • 不管是服务器还是客户端,都可以部署多个实例,因此,就很容易构建高可用的服务集群

Eureka服务器(114电话查询平台)
Eureka客户端服务提供者(医院、警察局电话放置114电话查询平台)
Eureka客户端服务调用者(查询电话的我们)
我们去114平台查询某处电话号码(服务查找),得到电话号码后(获取注册信息),拨打电话(服务调用)

  • Eureka Server实例作为服务注册中心的角色,负责接收来自Eureka Client的服务注册,并加以保存
  • Eureka Client内嵌于一个微服务中,会将当前实例作为服务实例注册中心(Eureka Server),注册内容包括IP、Port和服务实例名称
  • 消费者同样内嵌了Eureka Client,在进行微服务调用的时候,可以通过Eureka提供的DiscoveryClient和服务实例的名称,从服务注册中心(Eureka Server)获取服务实例列表,然后得到服务实例的IP和Port,以完成服务调用

1.3、服务器端

对于注册到服务器的服务组件,Eureka服务器并没有提供后台的存储,这些注册的服务实例被保存在内存的服务注册中心,它们通过心跳来保持其最新状态,这些操作都可以在内存中完成。
客户端存在相同的机制,同样在内存中保存了注册表信息,这样的机制提升了Eureka组件性能,每次服务的请求都不用经过服务器端的注册中心。

1.4、服务提供者

作为Eureka客户端存在的服务提供者,主要进行以下工作:
第一:向服务器注册服务
第二:发送心跳给服务器
第三:向服务器端获取注册列表
当客户端注册到服务器时,它将会提供一些关于它自己的信息给服务器端,例如:IP、Port、健康链接等

1.5、服务调用者

对于发布到Eureka服务器的服务,使用调用者可对其进行服务查找和调用,服务调用者也是作为客户端存在,但是其职责主要是发现和调用服务。
在实际情况中,有可能出现本身既是服务提供者,又是服务调用者的情况,例如:传统的企业应用三层架构中,服务层(service)会调用数据访问层(dao)的接口进行数据操作,它本身也会提供服务给控制层(controller)使用。

2、Eureka应用

2.1、构建服务器

  • 创建一个maven项目:atm-eureka-server

2.1.1、添加依赖
  • 在pom.xml中添加Spirng Cloud的依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.atm.cloud</groupId>
  <artifactId>atm_enreka_server</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>atm_enreka_server Maven Webapp</name>
  <url>http://maven.apache.org</url>

  <!-- Spring Cloud -->
  <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>


    <!--不需要再引入-->
    <!--
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    -->

     <!--Eureka-->
     <!--
        加入的spring-cloud-starter-eureka-server会自动引入spring-boot-starter-web
        因此只需要加入该依赖,我们的项目就具有 Web 容器的功能
     -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka-server</artifactId>
    </dependency>


  </dependencies>

  <build>
    <finalName>atm_enreka_server</finalName>
  </build>
</project>
2.1.2、编写启动类
package com.atm.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

@SpringBootApplication
@EnableEurekaServer
public class MyApplicationServer {

    public static void main(String[] args) {
        SpringApplication.run(MyApplicationServer.class, args);
    }

}
  • 可以发现与SpringBoot的启动类基本没有差异,只是加入了@EnableEurekaServer,声明这是一个 Eureka 服务器。直接运行 FirstServer 即可启动 Eureka 服务器
  • application.yml(Eureka默认 localhost:8761)
server:
  port: 8761
  • 执行main方法,启动,虽然启动成功,但是出现了异常

  • 异常暂时不管,先进行访问

  • 可以看到服务的实例列表,目前我们并没有注册服务,因此列表为空
2.1.3、服务器注册开关(解决异常)
  • 在上面我们已经发现,启动的时候会出现异常
  • 这是由于在服务器启动时,服务器会把自己当作一个客户端,去 Eureka 服务器注册,并且会到 Eureka 服务器抓取注册信息,它自己本身只是一个服务器,而不是服务的提供者(客户端),因此可以修改application.yml 文件,修改以下两个配置:
server:
  port: 8761

eureka:
 client:
  registerWithEureka: false
  fetchRegistry: false

2.2、编写服务提供者

  • 新创建一个maven项目:atm_eureka_provider

2.2.1、添加依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.atm.cloud</groupId>
    <artifactId>atm_enreka_provider</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>atm_enreka_provider Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <!-- Spring Cloud -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!-- 服务提供者 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <!-- 服务提供者 -->

    </dependencies>
    <build>
        <finalName>atm_enreka_provider</finalName>
    </build>
</project>
2.2.2、配置文件
server:
 port: 8080
spring:
 application:
  name: first-service-provider  
eureka:
 client:
  serviceUrl:
   defaultZone: http://localhost:8761/eureka/
 instance:
  hostname: localhost
2.2.3、编写控制器
  • Person类
package com.atm.cloud;

public class Person {

    private Integer id;

    private String name;

    private Integer age;

    //...省略setter/getter...
}
  • MyController类
package com.atm.cloud;

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class MyController {


    @RequestMapping(value = "/info", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public Person findPerson(){
        Person person=new Person();

        person.setId(1);
        person.setAge(18);
        person.setName("atm");

        return person;
    }

    @RequestMapping(value = "/person/{personId}", method = RequestMethod.GET,
            produces = MediaType.APPLICATION_JSON_VALUE)
    public Person findPerson(@PathVariable("personId")Integer personId){
        Person person=new Person();

        person.setId(personId);
        person.setAge(18);
        person.setName("atm");

        return person;
    }
}

2.2.4、编写启动类
  • @EnableEurekaClient,默认注册到8761的服务器上
package com.atm.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class MyApplicationProvider {

    public static void main(String[] args) {
        SpringApplication.run(MyApplicationProvider.class, args);
    }

}
  • 启动服务器MyApplicationServer、启动服务提供者MyApplicationProvider

2.3、编写服务调用者

  • 服务被注册、发布到Euraka服务器后,就需要程序去发现它,并且进行调用
  • 此处所说的调用者,是指同样注册到Eureka的客户端,来调用其他客户端发布的服务,简单来说,就是Eureka内部调用
  • 由于同一个服务,可能会部署多个实例,调用过程可能涉及负载均衡,服务器查找等问题,Netflix已经帮我们解决了这个问题,并且SpringCloud已经封装了一次
  • 创建新maven项目:atm_eureka_invoker

2.3.1、添加依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.atm.cloud</groupId>
    <artifactId>atm_enreka_invoker</artifactId>
    <packaging>war</packaging>
    <version>0.0.1-SNAPSHOT</version>
    <name>atm_enreka_invoker Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <!-- Spring Cloud -->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!-- 服务调用者 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency><!-- 负载均衡框架 -->
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-ribbon</artifactId>
        </dependency>
        <!-- 服务调用者 -->

    </dependencies>
    <build>
        <finalName>atm_enreka_invoker</finalName>
    </build>
</project>
2.3.2、配置文件
server:
 port: 9000
spring:
 application:
  name: first-service-invoker
eureka:
 instance:
  hostname: localhost
 client:
  serviceUrl:
   defaultZone: http://localhost:8761/eureka/
  • 在配置文件中,配置了应用名称为 “first-service-invoker”,这个调用者的访问端口为9000,需要注意的是,这个调用本身也可以对外提供服务
  • 与提供者一样,使用eureka的配置,将调用者注册到“atm_enreka_server”
2.3.3、编写控制器
package com.atm.cloud;

import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

@RestController
@Configuration
public class InvokerController {

    @Bean
    @LoadBalanced
    public RestTemplate getRestTemplate() {
        return new RestTemplate();
    }

    @RequestMapping(value="/router",method=RequestMethod.GET,
            produces=MediaType.APPLICATION_JSON_VALUE)
    public String router() {
        RestTemplate restTemplate = getRestTemplate();

        // 根据应用名称调用服务
        String json = restTemplate.getForObject(
                "http://first-service-provider/person/1", String.class);

        return json;
    }
}
  • 在控制器中,配置了RestTemplate的bean,RestTemplate本来是spring-web模块下的类,主要用调用REST服务,本身并不具备调用分布式服务的能力,但是RestTemplate的bean被@LoadBalanced注解修饰后,这个RestTemplate实例就具备访问分布式服务的能力
2.3.4、编写启动类
  • 在控制器中,新建了一个router的测试方法,用来对外发布REST服务,该方法只是一个路由的作用
  • 实际上,使用RestTemplate来调用“first-service-provider”(服务者提供)的服务
  • 需要注意的是,仅仅是通过服务名称来进行调用
package com.atm.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class MyApplicationInvoker {

    public static void main(String[] args) {
        SpringApplication.run(MyApplicationInvoker.class, args);
    }

}
  • 启动类中,使用@EnableDiscoveryClient注解来修饰启动类
  • 该注解使得服务调用者,有能力去Eureka中发现服务
  • 需要注意的是@EnableEurekaClient中已经包含@EnableDiscoveryClient的功能
  • 也就是说,一个Eureka客户端,本身就具有发现服务的能力

  • 启动服务器(atm_eureka_server)
  • 启动服务提供者(atm_eureka_provider)
  • 启动服务调用者(atm_eureka_invoker)

  • 在 浏 览 器 中 访 问 服 务 调 用 者 发 布 的 “ router ” 服 务 :http://localhost:9000/router,可以看到在浏览器输出如下:

  • 根据输出可知,实际上调用了服务提供者的person/1

2.4、程序结构

  • 本案例新建了三个项目

  • Eureka 服 务 为 本 例 的 “ atm_eureka_server ”,服务发布者为“atm_eureka_provider”,服务调用者为“atm_eureka_invoker”
  • 用户通过浏览器访问调用者的9000端口的router服务,router服务中查找服务器提供者的服务并进行调用
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

'嗯哼。

生生不息,“折腾”不止,Thx

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

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

打赏作者

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

抵扣说明:

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

余额充值