SpringCloud学习(三、父子项目、服务注册、服务关联)

这一节开始,我们将通过代码逐步解决我们上一节中关于分布式和集群的几个问题!实际的编码会让我们对SpringCloud、微服务、分布式、集群了解的更深刻。

一、父子项目

接下来就要开始做 springcloud 项目了。 springcloud 比较特别,它由多个微服务组成, 所谓的微服务,就是 springboot,。 
所以可以说 springcloud 由多个 springboot 项目组成, 而这些 springboot 之间又是围绕一个共同目的而存在的。 
所以,为了便于组织这些 springboot 项目,我们会采用 maven 父子-聚合 项目的方式来开发。下面 我们来看一下如何使用IDEA创建maven父子聚合项目。

通过 maven 可以创建父子-聚合项目。 所谓的父子项目,即有一个父项目,有多个子项目。
这些子项目,在业务逻辑上,都归纳在这个父项目下,并且一般来说,都会有重复的jar包共享。
所以常用的做法会把重复的 jar 包都放在父项目下进行依赖,那么子项目就无需再去依赖这些重复的 jar 包了。

1、新建一个父maven项目

 

SpringCloud学习(三、父子项目、服务注册、服务关联)_第1张图片

SpringCloud学习(三、父子项目、服务注册、服务关联)_第2张图片

这里我们给它命名位父maven项目。

 SpringCloud学习(三、父子项目、服务注册、服务关联)_第3张图片

2、修改pom文件

idea 自动生成的 pom.xml 有一大堆东西,很多都用不着。 修改为如下的内容。
2.1. 默认是 jar, 修改为pom。 这样才可以作为父项目存在。

pom
2.2. 增加 hutool jar 和 junit 包的依赖,用于后来子项目里观察对其的调用。

pom文件代码如下:



  4.0.0
  com.topmap
  parentMavenProject
  1.0-SNAPSHOT
  parentMavenProject
  parentMavenProject
  pom


  
    
      junit
      junit
      4.11
      test
    
    
      cn.hutool
      hutool-all
      4.3.1
    
  


3、创建一个子项目

所谓的子项目,其实是maven module.
右键点击 parentMavenProject->New->Module.

å建å­é¡¹ç®

SpringCloud学习(三、父子项目、服务注册、服务关联)_第4张图片

SpringCloud学习(三、父子项目、服务注册、服务关联)_第5张图片

 

SpringCloud学习(三、父子项目、服务注册、服务关联)_第6张图片

这样我们就在父maven项目下面新建了子maven项目。

SpringCloud学习(三、父子项目、服务注册、服务关联)_第7张图片

子项目的pom文件中多了一个,这是对父项目的依赖。

SpringCloud学习(三、父子项目、服务注册、服务关联)_第8张图片

父maven项目多了一个,这表示对子项目的关联。

下面我们来测试一下子项目是否已经跟父项目取得关联(这里在子项目中使用父项目依赖的jar包进行测试)

在 childMavenProject 下新建 TestHutool类,并运行。

SpringCloud学习(三、父子项目、服务注册、服务关联)_第9张图片

SpringCloud学习(三、父子项目、服务注册、服务关联)_第10张图片

这里我们在子项目中使用了父项目中调价的依赖中的方法,并且运行成功了!这说明子项目,能够使用 父项目中的 jar 包了。

4、父子项目整体架构

SpringCloud学习(三、父子项目、服务注册、服务关联)_第11张图片

这就是我们的整体目录结构,可以发现 childMavenProject 是位于 parentMavenProject下面的。 所以如果将来有 childMavenProject1, childMavenProject2, childMavenProject3 也会放在这么一个目录下,就方便管理了。

二、服务注册中心

下面我们根据上面新建父子项目的流程,再新建父项目---springcloud,子项目---eureka-server,这里eureka-server就是服务注册中心。

SpringCloud学习(三、父子项目、服务注册、服务关联)_第12张图片

上面的父子项目创建好了之后把父项目springcloud的 src 目录删了,因为父项目里用不到,看一下父项目的pom:


  4.0.0
  com.topmap
  springcloud
  0.0.1-SNAPSHOT
  springcloud
  springcloud
  pom

  
    org.springframework.boot
    spring-boot-starter-parent
    2.0.3.RELEASE
    
  

  
    UTF-8
    UTF-8
    1.8
    Finchley.RELEASE
  

  
    
      org.springframework.boot
      spring-boot-starter-test
      test
    
    
      cn.hutool
      hutool-all
      4.3.1
    
  

  
    
      
        org.springframework.cloud
        spring-cloud-dependencies
        ${spring-cloud.version}
        pom
        import
      
    
  


这个pom里有几点重要信息:
1. 依赖 springboot 版本是 2.0.3
2. 有基于 hutool 的依赖, hutool 是一个工具类,用起来很方便
3. springcloud 用的版本是 Finchley

再新建子项目 eureka-server

SpringCloud学习(三、父子项目、服务注册、服务关联)_第13张图片

再来看一下子项目的pom文件:




    
        springcloud
        com.topmap
        0.0.1-SNAPSHOT
    
    4.0.0

    eureka-server

    
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-server
        
    


这里添加了springcloud的spring-cloud-starter-netflix-eureka-server jar 包,就是用来做服务注册的一个jar包。

然后我们新建一个EurekaServer 启动类。

SpringCloud学习(三、父子项目、服务注册、服务关联)_第14张图片

EurekaServer ,它扮演的角色是注册中心,用于注册各种微服务,以便于其他微服务找到和访问。

EurekaServer 本身就是个 Springboot 微服务, 所以它有 @SpringBootApplication 注解。
@EnableEurekaServer 表示这是个 EurekaServer 。
启动的时候,端口号没有在配置文件里,而是直接放在代码里,这么做是为了提示同学这个端口号是否被占用了,否则有时候端口号被占用了,老是启动不了,搞得自己晕头转向的。
NetUtil 是 Hutool 的工具,在父项目的 pom.xml 里已经依赖了。

最后我们来配置yml文件,提供 eureka 的相关信息。

eureka:
  instance:
    hostname: localhost
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

spring:
  application:
    name: eureka-server

来解释一下上面的信息:

hostname: localhost 表示主机名称。

registerWithEureka:false. 表示是否注册到服务器。 因为它本身就是服务器,所以就无需把自己注册到服务器了。

fetchRegistry: false. 表示是否获取服务器的注册信息,和上面同理,这里也设置为 false。

defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ 自己作为服务器,公布出来的地址。 比如后续某个微服务要把自己注册到 eureka server, 那么就要使用这个地址: http://localhost:8761/eureka/

name: eurka-server 表示这个微服务本身的名称是 eureka-server

最后启动EurekaServerApplication:

SpringCloud学习(三、父子项目、服务注册、服务关联)_第15张图片

然后访问:http://127.0.0.1:8761/

SpringCloud学习(三、父子项目、服务注册、服务关联)_第16张图片

 这就是注册中心的管理界面,主要看 :Instances currently registered with Eureka, 可以发现信息是:No instances available。

这表示 暂时还没有微服务注册进来。

下面我们会进行微服务的注册!

三、注册数据微服务

创建子项目 product-data-service。

SpringCloud学习(三、父子项目、服务注册、服务关联)_第17张图片

修改 pom.xml 为如下:
spring-cloud-starter-netflix-eureka-client 表示这是个 eureka 客户端。
spring-boot-starter-web: 表示这是个web服务,会提供控制层




    
        springcloud
        com.topmap
        1.0-SNAPSHOT
    
    4.0.0

    product-data-service


    
        
        
            org.springframework.cloud
            spring-cloud-starter-netflix-eureka-client
        

        
        
            org.springframework.boot
            spring-boot-starter-web
        
    


然后我们编写product的实体类:

package com.topmap.pojo;

/**
 * @Author: MaHuadong
 * @Date: 2019/12/30 15:22
 * @Version 1.0
 */
public class Product {
    private int id;
    private String name;
    private int price;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getPrice() {
        return price;
    }

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

    }

    public Product(int id,String name,int price){
        super();
        this.id=id;
        this.name = name;
        this.price = price;
    }

}

再新建service:

service类提供一个 Product 集合。 

package com.topmap.service;

import com.topmap.pojo.Product;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @Author: MaHuadong
 * @Date: 2019/12/30 15:39
 * @Version 1.0
 */
@Service
public class ProductService {
    @Value("${server.port}")
    String port;

    public List listProducts(){
        List ps = new ArrayList<>();
        ps.add(new Product(1,"product a from port:"+port, 50));
        ps.add(new Product(2,"product b from port:"+port, 150));
        ps.add(new Product(3,"product c from port:"+port, 250));
        return ps;
    }
}

需要注意的是,这里把 端口号 放进了产品信息里。 这个数据服务会做成集群,那么访问者为了分辨到底是从哪个数据微服务取的数据,就需要提供个端口号,才能意识到是从不同的微服务得到的数据。

再新建Controller:

控制类,把 Product 集合转换成 json 数组。

SpringCloud学习(三、父子项目、服务注册、服务关联)_第18张图片

下面我们再来写这个子项目product-data-service的启动类:

启动类, 考虑到要做集群。 所以让用户自己输入端口,推荐 8001,8002,8003.
但是每次测试都要输入端口号又很麻烦,所以做了个 Future类,如果5秒不输入,那么就默认使用 8001端口。

package com.topmap;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.thread.ThreadUtil;
import cn.hutool.core.util.NetUtil;
import cn.hutool.core.util.NumberUtil;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

import java.util.Scanner;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * @Author: MaHuadong
 * @Date: 2019/12/30 15:54
 * @Version 1.0
 */
@SpringBootApplication
//代表这是一个Eureka客户端
@EnableEurekaClient
public class ProductDataServiceApplication {
    public static void main(String[] args){
        int port=0;
        int defaultPort=8001;
        Future future= ThreadUtil.execAsync(() ->{
            int p=0;
            System.out.println("请于5秒钟内输入端口号, 推荐  8001 、 8002  或者  8003,超过5秒将默认使用 " + defaultPort);
            Scanner scanner=new Scanner(System.in);
            while(true){
                String strPort=scanner.nextLine();
                if (!NumberUtil.isInteger(strPort)){
                    System.err.println("只能是数字");
                    continue;
                }else {
                    p = Convert.toInt(strPort);
                    scanner.close();
                    break;
                }
            }
            return p;
        });
        try {
            port=future.get(5, TimeUnit.SECONDS);
        }  catch (InterruptedException | ExecutionException | TimeoutException e){
            port = defaultPort;
        }
        if (!NetUtil.isUsableLocalPort(port)){
            System.err.printf("端口%d被占用了,无法启动%n", port );
            System.exit(1);
        }

        new SpringApplicationBuilder(ProductDataServiceApplication.class).properties("server.port=" + port).run(args);

    }


}

最后我们来配置子项目product-data-service的配置文件yml:

#   server:
#   port: 因为会启动多个 product-data-service, 所以端口号由用户自动设置,推荐 8001,8002,8003

spring:
  application:
#  微服务的名称
    name: product-data-service
eureka:
  client:
    serviceUrl:
#    注册中心的地址
      defaultZone: http://localhost:8761/eureka/

好了,我们现在父子项目都写好了,即微服务的注册中心和客户端应用都写好了。

现在再来看一下http://localhost:8761/中的Instances currently registered with Eureka:

SpringCloud学习(三、父子项目、服务注册、服务关联)_第19张图片

仍然还未有微服务进行注册,因为我们的微服务 product-data-service还未启动,下面我们进行启动!

启动两次 ProductDataServiceApplication, 分别输入 8001和8002.
可以在注册中心 http://127.0.0.1:8761/ 看到, product-data-service 这个微服务,有两个实例,分别是8001和8002端口。

在上面给了两行红色警示,下面我们设置一下去掉它:

 把注册中心重新启动一下或者在配置里把自我保护模式关了

eureka.server.enable-self-preservation # 设为false,关闭自我保护

这样就不会再有那个红色提醒了。

 可以如此访问: http://127.0.0.1:8001/products ,http://127.0.0.1:8002/products,并看到如图所示的数据。

 

 但是这种方式是通过 http 协议 访问微服务本身,和注册中心没有关系,也观察不到集群的效果,接下来我们就会讲如何用微服务,访问另一个微服务。

这一节就先到这儿!

你可能感兴趣的:(SpringCloud,springboot框架,java)