SpringCloud学习笔记(三):订阅微服务

SpringCloud学习笔记(三):订阅微服务

订阅微服务

上一节我们在Eureka上注册了一个名为APP-CARGO的微服务,现在我们就要新建一个微服务,经由Eureka访问到APP-CARGO微服务的接口。
Talk is cheap,show me the code!上代码。

新建模块

同样我们现在需要新建一个CargoAccesser模块用于访问这个Cargo模块提供的接口,新建模块的方法可以参考上一节的内容,新建一个项目也可以。
新建完基于Maven的CargoAccesser模块后,打开pom.xml,写入如下依赖

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.6.RELEASE</version>
    </parent>

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

    <dependencies>
        <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>
            <version>2.0.2.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <!-- 资源文件拷贝插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <configuration>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <!-- java编译插件 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

在java目录下新建runner、entity、controller、service四个包,首先我们先准备好实体类,在entity包下新建Cargo、CargoList、CargoListDetail三个实体类。

(其中Cargo实体在正式开发中是不必要的,微服务之间应该通过JSON来做数据传输,两个不同的微服务开发团队之间约定JSON中包含的内容即可)

。代码如下:

//Cargo.java
package entity;

public class Cargo {
    private Long id;
    private String name;
    private String price;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public Cargo() {
    }

    public Cargo(Long id, String name, String price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    @Override
    public String toString() {
        return "Cargo{"
                + "id:"
                + id
                + ",name:'"
                + name + '\''
                + ",price:'"
                + price + '\''
                + "}";
    }
}

//CargoList.java
package entity;

import java.util.List;

public class CargoList {
    private String id;//货物清单ID
    private List<CargoListDetail> detailList;
    private String comment;//清单备注

    public CargoList() {
    }
    
    public CargoList(String id, List<CargoListDetail> detailList, String comment) {
        this.id = id;
        this.detailList = detailList;
        this.comment = comment;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public List<CargoListDetail> getDetailList() {
        return detailList;
    }

    public void setDetailList(List<CargoListDetail> detailList) {
        this.detailList = detailList;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    @Override
    public String toString() {
        return "CargoList [id=" + id + ",comment='"+comment+"'"
                + "]";

    }
}

//CargoListDetail.java
package entity;

public class CargoListDetail {
    private String id;
    private Cargo cargo;

    public CargoListDetail() {
    }

    public CargoListDetail(String id, Cargo cargo) {
        this.id = id;
        this.cargo = cargo;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public Cargo getCargo() {
        return cargo;
    }

    public void setCargo(Cargo cargo) {
        this.cargo = cargo;
    }

    @Override
    public String toString() {
        return "CargoListDetail [id=" + id + ", cargo=" + cargo + "]";
    }
}

准备好了实体类,接下来我们需要写一个调用先前已经注册的微服务的Service,在service包下新建CargoService类,代码如下:

package service;

import entity.Cargo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

@Service
public class CargoService {

    @Autowired
    private RestTemplate restTemplate;//SpringBoot对Rest请求做了封装,可以通过模板快速配置请求信息

    public Cargo queryCargoById(Long id) {
        //需要在RestTemplate对象上加上@LoadBalanced注解
        String cargoUrl = "http://app-cargo/cargo/{id}";
        Cargo cargo = this.restTemplate.getForObject(cargoUrl , Cargo.class , id);
        System.out.println("CargoService is invoked,result:"+cargo);
        return cargo;
    }
}

接下来我们需要新建一个货物清单Service,来调用上面的CargoServce获取货物信息,来构成货物清单。代码如下:

package service;

import entity.Cargo;
import entity.CargoList;
import entity.CargoListDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class CargoListService {

    private static final Map<String, CargoList> CARGO_LIST_DATA = new HashMap<String, CargoList>();

    static {
        // 模拟数据库,构造测试数据
        CargoList cargoList = new CargoList();
        cargoList.setId("123");
        List<CargoListDetail> listDetails = new ArrayList<CargoListDetail>();

        Cargo cargo = new Cargo();// 此处并没有货物的数据,仅有ID,需要通过微服务获取
        cargo.setId(1L);
        listDetails.add(new CargoListDetail(cargoList.getId(), cargo));

        cargo = new Cargo(); // 构造第二个货物数据
        cargo.setId(2L);
        listDetails.add(new CargoListDetail(cargoList.getId(), cargo));

        cargoList.setDetailList(listDetails);
        cargoList.setComment("我是清单备注");
        CARGO_LIST_DATA.put(cargoList.getId(), cargoList);
    }

    @Autowired
    CargoService cargoService;

    public CargoList queryCargoListById(String id) {
        CargoList cargoList = CARGO_LIST_DATA.get(id);
        if (null == cargoList) {
            return null;
        }
        List<CargoListDetail> listDetails = cargoList.getDetailList();
        for (CargoListDetail listDetail : listDetails) {
            // 调用微服务查询货物信息
            Cargo cargo = this.cargoService.queryCargoById(listDetail.getCargo()
                    .getId());
            if (null == cargo) {
                continue;
            }
            listDetail.setCargo(cargo);
        }

        return cargoList;
    }
}

最后我们需要编写控制器、启动类和配置yml文件,启动模块,订阅者微服务就完成了。
控制器代码如下:

package controller;

import entity.CargoList;
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.RestController;
import service.CargoListService;

@RestController
public class CargoAccesserController {
    @Autowired
    private CargoListService cargoListService;

    @GetMapping(value = "cargoList/{id}")
    public CargoList queryOrderById(@PathVariable("id") String id) {
        return this.cargoListService.queryCargoListById(id);
    }
}

启动类代码如下:

package runner;

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.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@ComponentScan({"controller","entity","service"})
@EnableEurekaClient//启动Eureka客户端服务
public class CargoAccesserApp {
    public static void main(String[] args) {
        SpringApplication.run(CargoAccesserApp.class, args);
    }

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

yml配置文件如下:

server:
  port: 8095 #服务端口

spring:
  application:
    name: app-cargo-list

eureka:
  client:
    service-url:
      defaultZone: http://localhost:9090/eureka/
    ###如果要提供服务则需要注册,因为这里是服务的订阅者,注不注册都可以
    register-with-eureka: true
    ###是否需要从eureka上检索服务,这个服务需要调用别的服务,所以当然需要检索服务了
    fetch-registry: true

启动该模块,访问http://localhost:8095/cargoList/123,查看程序执行结果。
执行结果
通过结果可以发现,服务订阅者通过向http://app-cargo/cargo/xxx这个接口请求,成功获取到了货物信息,而没有使用传统硬编码的方式向localhost:8090/cargo/xxx来请求。这么做可以避免接口地址改变而带来不必要的试错成本,所有微服务都在注册中心上注册,让各个服务的开发团队都可以把注意力集中在自己的服务上,而不用去关心其他组件的实现。

由于在RestTemplate上使用了一个LoadBalance注解,为APP-CARGO服务启用了负载均衡,我们可以通过不同的端口启动多个APP-CARGO服务以达到假集群的效果,调用CargoList服务,会发现系统会使用轮询的方式逐个调用这些服务。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值