spring学习

史上最详细的springcloud+eurake+ribbon+

2019-07-13  本文已影响50人  长道

本文采用当前最流行的springboot架构搭建微服务,从最开始的微服务架构和理念开始,将一步一步带大家搭建一个微服务架构,实现基本的增删改查功能,主要涉及到的技术如下:

1. springboot+springcloud(2.0 版本)

2.mybatis

3.jdk 11

4.idea 开发工具2018

1. 微服务介绍

在开始正式进入工作之前,我们先大概的介绍一下什么是微服务,微服务与传统概念下的系统有什么不同,方便大家进一步的了解。简单的说微服务是系统设计的一种分格,就是将我们传统的单体服务系统按照功能模块进行划分,然后拆解成多个小型的服务,每个小型服务都可以独立运行,服务之间通过http协议进行通信,每个小型服务都是以系统中的某一个或者几个核心服务为基础进行构建的,他们直接甚至可以用不同的语言进行构建。

2.微服务的优势与劣势

既然微服务大行其道,那么毕竟有过人之处,但任何事务都是俩面性,就像智能手机和传统的功能手机一样,智能手机这么流行这么受人欢迎说明他与功能机对比有着不可替代的作用,但智能手机也有一大缺点就是待机时间问题,那么微服务也和智能手机类似,下面我们列举一下微服务的优劣势。

2.1 优势

1. 服务可以进行独立的测试,发布,和升级。

2. 按需定制和部署,每个服务都可以根据实际需要进行多维度的扩展。

3. 提高系统的容错性,单个服务的问题,不会导致整个系统性的崩溃。

4. 系统可扩展性,每个服务都可以采用不同的语言不同的团队进行开发。

2.2 缺点

1. 提高系统的复杂度。

2. 服务之间分布式通信问题。

3. 服务直接注册和发现问题。

4.服务之间分布式事务问题。

5.服务管理的复杂性和服务维护问题。

3. 微服务架构选型

在构建微服务架构时,任何语言都可以进行构建,这几年微服务大行其道,互联网公司的贡献可以说是功不可没,很多著名的主流的服务注册、服务配置、服务跟踪等一系列软件都有国内互联网的公司的身影。他们对不同场景应用下的解决方案做出了非常优秀的贡献。比如服务治理方面有阿里巴巴开源的Dubbo和当当网在其基础上扩展的DubboX、 Netflix的Eureka、Apache的Consul等。在分布式配置管理方面有百度的Disconf、 Netflix的Archaius、360的QConf、SpringCloud的Config、 淘宝的Diamond等。而上述提到的各种框架都是基于最初问题为导向而衍生的,有的是在已有的框架的为了解决自身业务功能而进行的一些扩展,是实际开发中,如果我们要做一个完整的可用运行的微服务架构,可能要整合很多不同的框架,这个对于开发者来说,不是一件很愉快的事。

尤其对国内开发者来说,我们对程序员的选型是横向的,要求是从前到后,从架构和设计,从开发到数据库维护,每一块功能都要懂点,说实话想小编这种人的脑容量来说根部整合不了这么多技术,要做到一个全栈工程师来说换真的是不容易。所以做软件选型前的一个要求就是框架整合简单,可以把更多精力放到业务需求开发上。

而Spring Cloud是一个基千SpringBoot实现的微服务架构开发工具。它为微服务架构中涉及的配置管理、 服务治理、 断路器、 智能路由、 微代理、 控制总线、 全局锁、 决策竞选、分布式会话和集群状态管理等操作提供了 一 种简单的开发方式。

4. 微服务搭建

下面小编会从最简单的服务注册与服务调用开始,服务注册和服务调度、建立eureka集群等,一步一步的抽丝剥茧讲解。

4.1 建立一个总项目工程

首先我们创建一个总的项目工程,名称为mes_perent01,该项目工程没有任何业务逻辑代码相关的东西,总工程的packageing为一个pom,目的是在该工程下面建立多个服务注册和是服务发现模块。

file--》new--》project--》maven

image

接下来我们写groupid和Artifactid,一般groupid就是一般就是公司域名的倒序,比如说我们使用的阿里巴巴的fastjson,他的groupid就是com.alibaba。而Artifactid就是项目的名称fastjson了。

image

接下来就是一路next了,一直到项目的完成。

image

项目创建完成后,有可能看到最右边的maven插件没有加载上,这个没有关系,大家点击一下上面的功能按钮重新加载一下就可以了。

image

接下来,我们需要修改俩个地方,一个是在总工程目录下的pom文件中,增加一个<packaging>pom</packaging>配置,表示该项目是一个pom类型,还有其他的jar类型,表示该项目是一个可执行程序或者服务程序,后面我们基于微服务架构下创建的子模块都是jar类型。War类型表示该项目是一个部署类型项目,比如说我们需要部署到tomcat上,就需要家项目打成war包。同时将src目录删除。

image

4.2 创建一个mes_provider01微服务

接下来我们创建一个服务提供者,项目称为mes_provider01,因为后面我会循序渐进的创建微服务集群,所有在命名上从01开始。项目创建采用springboot引导项目创建。

在总工程下,即mes_parent01下创建第一个微服务mes_provider01模块。

New -> Maven -> Maven Module

image

初始化采用spring.io网站下面的引导项目创建。大家也可以打开https://start.spring.io/网站,在这里创建后下载到本地进行加载。

image

项目创建时候,packaging这里注意了,我们需要打包成可运行的jar包,所有这里选择jar包

image

因为我们创建的是服务提供者与消费者,以服务的方式启动,并且要依托controller。所有在这里我们选择web然后右边选择spring web starter即可,其他的先不需要选择。

image

服务创建完成后,我们看一下对应的pom.xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>2.1.6.RELEASE</version>
       <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.ht305</groupId>
   <artifactId>mes_provider01</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>mes_provider01</name>
   <description>Demo project for Spring Boot</description>

   <properties>
       <java.version>11</java.version>
   </properties>

   <dependencies>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter</artifactId>
       </dependency>

       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-devtools</artifactId>
           <scope>runtime</scope>
           <optional>true</optional>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-test</artifactId>
           <scope>test</scope>
       </dependency>
   </dependencies>

   <build>
       <plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
       </plugins>
   </build>

</project>

然后我们修改application.yml 配置文件。这里需要大家注意一下,application.yml第一不能直接房子src目录下,否则在启动过程中报错,第二application.yml会自动扫描与他同一目录下或者子目录下的相关文件。

# 服务端口名称
server:
 port: 8081

#配置服务名称
spring:
 application:
   name: mes_provider01

接着,我们在com.ht305.mes_provider01目录下(application.yml目录下)增加pojo包用来存放pojo对象,service包用来存放service接口,impl包用来存放接口的实现,controller包用户存储api访问控制。


image.png

在pojo包中,我们增加一个Person对象。

package com.ht305.mes_provider01.pojo;

import java.io.Serializable;

public class Person  implements Serializable {
   private Integer id;
   private String name;
   private String address;

   public Integer getId() {
       return id;
   }

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

   public String getName() {
       return name;
   }

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

   public String getAddress() {
       return address;
   }

   public void setAddress(String address) {
       this.address = address;
   }
}

在service接口包中,增加一个PersonService接口,接口中包含一个getPersonById方法。

package com.ht305.mes_provider01.service;

import com.ht305.mes_provider01.pojo.Person;

public interface PersonService {

    public Person getPersonById(Integer id);
}

在impl包中,增加一个PersonServiceImpl类,该类为PersonService的接口实现,在该方法中,我们简单的new Person对象。同时记得在spring针对接口编程,要求在接口的实现上增加@Service 注解。

package com.ht305.mes_provider01.impl;

import com.ht305.mes_provider01.pojo.Person;
import com.ht305.mes_provider01.service.PersonService;
import org.springframework.stereotype.Service;

@Service("personService")
public class PersonServiceImpl implements PersonService {
    @Override
    public Person getPersonById(Integer id) {
        Person person = new Person();
        person.setId(id);
        person.setName("张三丰");
        person.setAddress("武当山");
        return person;
    }
}

接着我们在controller包中定义api接口控制层的controller。在这里因为我们是接口的提供者,提供的接口一般都是返回json格式字符串,所有我们通过@RestController注解标注controller类,这样该类下面所有的方法都会返回json格式的字符串,@RestController是@Controller和@ResponseBody的合体,我们也可以分别通过这俩个注册来实现@RestController注解的功能。

package com.ht305.mes_provider01.controller;


import com.ht305.mes_provider01.pojo.Person;
import com.ht305.mes_provider01.service.PersonService;
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;

@RestController
public class PersonController {
    @Autowired
    private PersonService personService;

    @GetMapping("/person/{id}")
    public Person getPerson(@PathVariable Integer id){
        Person person = personService.getPersonById(id);
        return person;
    }
}

接下来我们启动一个springboot引导类,该类在创建springboot项目的时候自动在项目groupid+artifact包下面。该类就是一个主程序的入口类,在类的上面包含一个@SpringBootApplication注解,此注解是分别是@Configuration,@EnableAutoConfiguration,@ComponentScan注解的合体。

package com.ht305.mes_provider01;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class MesProvider01Application {

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

}

我们启动MesProvider01Application 类后,在浏览器输入localhost:8081/person/1 就可以看到调用getPersonById接口查询出相关的数据。


image.png

到此,服务接口提供者我们创建成功了,接下来我们创建一个服务接口的调用者,调用mes_provider01提供的接口。

4.3、创建一个mes_customer01消费微服务

mes_customer01服务的创建和mes_provider01步骤类似,创建完成后,我们看pom.xml文件。

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ht305</groupId>
    <artifactId>mes_customer01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mes_customer01</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

接着我们修改application.yml文件。服务消费程序的端口我们统一9091开始。

#服务端口
server:
  port: 9091

#服务名称
spring:
  application:
    name: mes_customer01

在com.ht305.mes_customer01目录下,我们只需要增加俩个包,一个是controller包,一个是pojo包,用来存放接口返回的数据,这样我们就可以做到真正的服务分离。其实在实际生产环境中,我们是把公共的类单独做成一个服务。


image.png

pojo包中我们新建一个Person对象,该Person对象是为了接受来自mes_provider01接口中的数据。

package com.ht305.mes_customer01.pojo;

import java.io.Serializable;

public class Person implements Serializable {
    private Integer id;
    private String name;
    private String address;

    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

controller包中用来调用mes_provider01中的接口。并且用restTemplate模板模拟RESTful的api调用。

package com.ht305.mes_customer01.controller;

        import com.ht305.mes_customer01.pojo.Person;
        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 org.springframework.web.client.RestTemplate;
@RestController
public class PersonController {

    @Autowired
    private RestTemplate restTemplate;
    String url = "http://localhost:8081";
    @GetMapping("/person/{id}")
    public Person getPerson(@PathVariable Integer id){

        Person person = restTemplate.getForObject(url+"/person/"+id,Person.class);

        return person;
    }
}

接下来,我们启动mes_customer01程序。并且在启动程序中添加restTemplate方法。

package com.ht305.mes_customer01;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class MesCustomer01Application {

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

    @Bean
    public RestTemplate template(){
        return new RestTemplate();
    }
}

程序启动后,我们访问localhost:9091/person/1,同时为了很直观的看到mes_customer01调用了mes_provider01模块中的方法,我们将mes_provider01以debug的模式启动,然后在PersonServiceImpl中增加断点。


image.png
image.png

可以看到,他的确进入到了mes_provider01微服务的接口提供者里面了,当debug完成后,我们可以看到页面输出了相关的数据。


image.png

4.4 与mybatis结合,连接数据库

在微服务提供者的模块中mes_provider01,我们增加数据的访问,通过mybatis对数据库进行增删改查功能。首先我们在mysql数据库中增加一个表cm_person.


image.png

接下来,我们通过mybatis 的generator插件将数据库中的表自动生产pojo、mapper接口以及mapperxml映射文件,需要我们在mes_provider01的pom文件中增肌org.mybatis.generator的插件。数据连接池我们采用阿里巴巴的druid。

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ht305</groupId>
    <artifactId>mes_provider01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mes_provider01</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <!--spring boot 集成mybaits-->
        <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>
        <!--spring boot 集成阿里巴巴 druid连接池-->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.17</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <!--配置文件的位置-->
                    <configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
                <!--避免每次打包都执行自动生成文件,将原来的文件覆盖问题-->
                <executions>
                    <execution>
                        <id>Generate MyBatis Artifacts</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <!--mysql驱动包-->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.16</version>
                    </dependency>
                </dependencies>

            </plugin>
        </plugins>
    </build>

</project>


在mes_provider01服务提供者模块中的application.yml文件中,增加数据库连接配置。在这里如果连接MySQL的话,注意url的配置,后面一定要加上时区的配置,否则在程序执行的过程中,由于时区的不一致会报错。

# 服务端口名称
server:
  port: 8081

#配置服务名称
spring:
  application:
    name: mes_provider01

#数据库连接相关配置

  datasource:
    #使用mysql数据库
    name: gas
    url: jdbc:mysql://localhost:3306/gas?serverTimezone=UTC&useUnicode=true$characterEncoding=utf8
    username: root
    password: 123456
    # 使用druid数据l连接池
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver
    filters: stat
    maxActive: 20
    initialSize: 1
    maxWait: 60000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20
#mybatis相关配置
mybatis:
  #制定mybatis mapper文件加载路径
  mapper-locations: classpath:/mapper/*Mapper.xml
  #mybatis配置文件加载路径
  config-location: classpath:mybatis/mybatis.cfg.xml
  #指定mapper文件中实体路径
  type-aliases-package: com.ht305.mes_provider01.dao


然后我们在resource下建立相关的目录,mapper目录用来存放生成的mapper.xml文件,generator目录用户存放mybatis自动生成配置文件。mybatis目录用来存放mybatis相关配置。


image.png

generatorConfig.xml配置文件配置了从mysql数据库到程序中的一些映射关系。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包-->

    <context id="mysql"  targetRuntime="MyBatis3">
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <!-- 是否去除自动生成的注释 true:是 : false:否 -->
            <property name="suppressAllComments" value="false"/>
        </commentGenerator>
        <!--数据库连接驱动类,URL,用户名、密码 -->
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1/gas?serverTimezone=GMT%2B8" userId="root" password="123456">
        </jdbcConnection>
        <javaTypeResolver>
            <property name="forceBigDecimals" value="false"/>
        </javaTypeResolver>
        <!-- 生成(实体)模型的包名和位置-->
        <javaModelGenerator targetPackage="com.ht305.mes_provider01.pojo" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成XML映射文件的包名和位置-->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <!-- 生成DAO接口的包名和位置-->
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.ht305.mes_provider01.dao" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名-->
        <table tableName="cm_person" domainObjectName="Person" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table>

    </context>
</generatorConfiguration>

mybatis目录下mybatis.cfg.xml的配置。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>

    <!-- 开启二级缓存 -->
    <settings>
        <setting name="cacheEnabled" value="true"/>
    </settings>

</configuration>

接下来,我们将generatorConfig配置成一个可用户的maven项目,

image.png

运行mybatisGenerator后,可以看到在dao和mapper目录下生成了对于的文件。
我们先来看dao中的mapper接口文件。

package com.ht305.mes_provider01.dao;

import com.ht305.mes_provider01.pojo.Person;

public interface PersonMapper {
    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table cm_person
     *
     * @mbggenerated
     */
    int deleteByPrimaryKey(Integer id);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table cm_person
     *
     * @mbggenerated
     */
    int insert(Person record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table cm_person
     *
     * @mbggenerated
     */
    int insertSelective(Person record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table cm_person
     *
     * @mbggenerated
     */
    Person selectByPrimaryKey(Integer id);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table cm_person
     *
     * @mbggenerated
     */
    int updateByPrimaryKeySelective(Person record);

    /**
     * This method was generated by MyBatis Generator.
     * This method corresponds to the database table cm_person
     *
     * @mbggenerated
     */
    int updateByPrimaryKey(Person record);
}

生成对应的mapper文件。大家感觉是不是很方便呢。

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ht305.mes_provider01.dao.PersonMapper">
  <resultMap id="BaseResultMap" type="com.ht305.mes_provider01.pojo.Person">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    <id column="id" jdbcType="INTEGER" property="id" />
    <result column="name" jdbcType="VARCHAR" property="name" />
    <result column="address" jdbcType="VARCHAR" property="address" />
  </resultMap>
  <sql id="Base_Column_List">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    id, name, address
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Integer" resultMap="BaseResultMap">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    select 
    <include refid="Base_Column_List" />
    from cm_person
    where id = #{id,jdbcType=INTEGER}
  </select>
  <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    delete from cm_person
    where id = #{id,jdbcType=INTEGER}
  </delete>
  <insert id="insert" parameterType="com.ht305.mes_provider01.pojo.Person">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    insert into cm_person (id, name, address
      )
    values (#{id,jdbcType=INTEGER}, #{name,jdbcType=VARCHAR}, #{address,jdbcType=VARCHAR}
      )
  </insert>
  <insert id="insertSelective" parameterType="com.ht305.mes_provider01.pojo.Person">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    insert into cm_person
    <trim prefix="(" suffix=")" suffixOverrides=",">
      <if test="id != null">
        id,
      </if>
      <if test="name != null">
        name,
      </if>
      <if test="address != null">
        address,
      </if>
    </trim>
    <trim prefix="values (" suffix=")" suffixOverrides=",">
      <if test="id != null">
        #{id,jdbcType=INTEGER},
      </if>
      <if test="name != null">
        #{name,jdbcType=VARCHAR},
      </if>
      <if test="address != null">
        #{address,jdbcType=VARCHAR},
      </if>
    </trim>
  </insert>
  <update id="updateByPrimaryKeySelective" parameterType="com.ht305.mes_provider01.pojo.Person">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    update cm_person
    <set>
      <if test="name != null">
        name = #{name,jdbcType=VARCHAR},
      </if>
      <if test="address != null">
        address = #{address,jdbcType=VARCHAR},
      </if>
    </set>
    where id = #{id,jdbcType=INTEGER}
  </update>
  <update id="updateByPrimaryKey" parameterType="com.ht305.mes_provider01.pojo.Person">
    <!--
      WARNING - @mbggenerated
      This element is automatically generated by MyBatis Generator, do not modify.
    -->
    update cm_person
    set name = #{name,jdbcType=VARCHAR},
      address = #{address,jdbcType=VARCHAR}
    where id = #{id,jdbcType=INTEGER}
  </update>
</mapper>

接下来,我修改mes_provider01微服务模块中的PersonServiceImpl实现,根据传入的id查询数据库。


image.png

在这里我们可以看到idea提示一个错误信息,说是找到不到这个注册的bean,这个没有关系,我们将将这个错误提示修改为typo即可,同时在mes_provider01微服务模块的的启动类上增加@MapperScan("com.ht305.mes_provider01.dao")注解,也可以在每个单独的mapper接口类上增加@Mapper注解。二选其一即可,@MapperScan注解的好处是指定扫描一个包后,不需要在单独的每个mapper接口类增加@mapper注解。

package com.ht305.mes_provider01;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@MapperScan("com.ht305.mes_provider01.dao")
public class MesProvider01Application {

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

}

然后我们从新启动mes_provider01微服务模块后,通过访问服务调用者接口([http://127.0.0.1:9091/person/2](http://127.0.0.1:9091/person/{id})传入不同参数就会在数据库访问到不同的数据。

image.png image.png

然后我们通过maven clean install打包成jar 后,通过java -jar xxx.jar 命令启动mes_provider01微服务提供者与mes_customer01微服务调用,在感受一下微服务的理念。


image.png
image.png
image.png

大家可以看到,每一个模块都可以做到单独的一个服务运行。如果不是核心服务停止的话,他们当中任何一个微服务stop了,不会影响整个系统的运行,这是我们传统意义上的单体服务无法比拟的。
这只是一个非常简单的服务注册和服务调用的实例,让大家有一个直观的印象,有了这个基础后,我们才可以进一步学习eureka等相关技术。

4.5 创建eureka进行服务注册与发现

eureka是springcloud的一个组件,主要用户做服务的注册和发现,前面我们创建了俩个微服务,一个是mes_provider01作为服务的提供者,另一个mes_customer01作为服务的消费者,实际应用中,我们不会直接调用mes_provider01的微服务,没法做到服务的负载均衡和中间层服务故障的转移。这时候我们就需要一个中间服务层能帮我们做负载均衡和故障转移。而Eureka包含两个组件:Eureka Server和Eureka Client。(来源百度,实在是没有力气打了)
Eureka Server提供服务注册服务,各个节点启动后,会在Eureka Server中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到。
Eureka Client是一个java客户端,用于简化与Eureka Server的交互,客户端同时也就是一个内置的、使用轮询(round-robin)负载算法的负载均衡器。
在应用启动后,将会向Eureka Server发送心跳,默认周期为30秒,如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,Eureka Server将会从服务注册表中把这个服务节点移除(默认90秒)。
Eureka Server之间通过复制的方式完成数据的同步,Eureka还提供了客户端缓存机制,即使所有的Eureka Server都挂掉,客户端依然可以利用缓存中的信息消费其他服务的API。综上,Eureka通过心跳检查、客户端缓存等机制,确保了系统的高可用性、灵活性和可伸缩性。
在总工程下面我们添加mes_eurekaservice01.
New -> Maven -> Maven Module


image.png

packaging为jar类型。其他的和之前创建的项目方式一致。


image.png
在jar包依赖这里我们只需要选择springcloudDiscovery下的EurekaServer即可。
image.png
生成的pom.xml文件如下。其中spring-cloud-starter-netflix-eureka-server表明该服务是一个server服务,后面换有client服务。
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ht305</groupId>
    <artifactId>mes_eurekaservice01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mes_eurekaservice01</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

mes_eurekaservice01的application.yml配置文件。

#服务端口
server:
  port: 80
#服务名称
spring:
  application:
    name: mes_eurekaservice01
#实例主机名称
eureka:
  instance:
    hostname: localhost
    #eureka默认是采用hostname注册的,如果使用ip注册,则增加下面的一行
   # prefer-ip-address: true

  client:
    #是否将自己注册到eureka service中,现在我们只有一个注册服务中心,所以设置为false
    register-with-eureka: false
    #是否从eureka service中获取注册的服务,现在我们只有一个注册服务中心,所以设置为false
    fetch-registry: false
    service-url:
      defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

然后在启动类中增加@EnableEurekaServer注解

package com.ht305.mes_eurekaservice01;

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

@SpringBootApplication
@EnableEurekaServer
public class MesEurekaservice01Application {

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

}

启动mes_eurekaservice01服务注册模块,但是在启动的过程中,我们发现提示java.lang.TypeNotPresentException: Type javax.xml.bind.JAXBContext not present错误信息。


image.png

原因是从jdk9之后引用了模块化概念,JAXB模块没有被加载,本项目采用的jdk11的,需要手动将相关的依赖加入。

<dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
</dependency>

引入后,完整的pom文件如下。

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ht305</groupId>
    <artifactId>mes_eurekaservice01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mes_eurekaservice01</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>com.sun.xml.bind</groupId>
            <artifactId>jaxb-impl</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.0</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

从新启动后,我们访问http://localhost后,可以看eureka控制页面。此时没有任何服务注册进来。一定要记得添加@EnableEurekaServer注解,该注解用于激活eureka的服务端。

image.png

接下来,我们修改mes_provider01服务提供者模块,将相关的接口注册到mes_eurekaservice01模块中,首先修改mes_provider01模块中额pom文件,在文件中添加spring-cloud-starter-netflix-eureka-client依赖,同时需要注意一下,我在一开始创建mes_provider01的时候,没有添加

   <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

所有后续的pom文件中添加依赖的时候都需要指定版本号,因为他没有从parent的pom里面继承,为了方便和避免jar的冲突,我在这里还是添加的parent的pom依赖,完整的pom如下。

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ht305</groupId>
    <artifactId>mes_provider01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mes_provider01</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    </properties>

    <dependencies>

        <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-eureka-client -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <!--spring boot 集成mybaits-->
        <!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.1</version>
        </dependency>
        <!--spring boot 集成阿里巴巴 druid连接池-->
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.17</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>

            <plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.2</version>
                <configuration>
                    <!--配置文件的位置-->
                    <configurationFile>src/main/resources/generator/generatorConfig.xml</configurationFile>
                    <verbose>true</verbose>
                    <overwrite>true</overwrite>
                </configuration>
                <!--避免每次打包都执行自动生成文件,将原来的文件覆盖问题-->
                <executions>
                    <execution>
                        <id>Generate MyBatis Artifacts</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <dependencies>
                    <!--mysql驱动包-->
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.16</version>
                    </dependency>
                </dependencies>

            </plugin>
        </plugins>
    </build>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

接着修改mes_provider01服务提供者模块的application.yml文件,增加服务注册的url。

eureka:
  client:
    service-url:
      defaultZone:http://localhost/eureka/

完整的application.yml文件如下。

# 服务端口名称
server:
  port: 8081

#配置服务名称
spring:
  application:
    name: mes_provider01

#数据库连接相关配置

  datasource:
    #使用mysql数据库
    name: gas
    url: jdbc:mysql://localhost:3306/gas?serverTimezone=UTC&useUnicode=true$characterEncoding=utf8
    username: root
    password: 123456
    # 使用druid数据l连接池
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat
    maxActive: 20
    initialSize: 1
    maxWait: 60000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20
#mybatis相关配置
mybatis:
  #制定mybatis mapper文件加载路径
  mapper-locations: classpath:/mapper/*Mapper.xml
  #mybatis配置文件加载路径
  config-location: classpath:mybatis/mybatis.cfg.xml
  #指定mapper文件中实体路径
  type-aliases-package: com.ht305.mes_provider01.dao

#eureka 服务注册配置
eureka:
  client:
    service-url:
      defaultZone:http://localhost/eureka/

接着在mes_provider01服务提供者模块的启动类中增加@EnableEurekaClient注解,表示mes_provider01服务提供者模块启动的时候就启动了eureka的客户端,同时将相关的服务注册到eureka server中。其中@EnableEurekaClient注解只能用于eureka,而@EnableDiscoveryClient注解可以用于zookeeper等其他服务注册组件。

package com.ht305.mes_provider01;

import org.mybatis.spring.annotation.MapperScan;
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
@MapperScan("com.ht305.mes_provider01.dao")
public class MesProvider01Application {

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

}

我们从新启动mes_provider01服务提供者模块后,在刷新http://localhost 页面,就可以看到mes_provider01服务注册到了mes_eurekaservice01模块中。

image.png
接下来我们看一下这个几个代表什么意思。其中1表是的我们在我们mes_provider01服务提供者模块中yml文件的应用名称. image.png
#配置服务名称
spring:
application:
 name: mes_provider01

2部分是有主机名称+应该名称+端口号组成,如果我们更改显示的名称,则在mes_provider01服务提供者模块中yml文件的增加.

#eureka 服务注册配置
eureka:
client:
 service-url:
   defaultZone: http://localhost/eureka/
instance:
 instance-id: mes_provider01:8081

其中我们点击服务注册名称后,会提示错误信息。为了显示的更加友好,修改一下配置。


image.png

首先我们在mes_provider01服务提供者模块中的pom文件中增加

      <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

然后在mes_provider01服务提供者模块中的yml文件中增加

info:
  app.name: mes_provider01
  company.name: http://ht305.com
  build.artifactId: com.ht305.mes_provider01
  build.version: 1.0

然后重新启动mes_eurekaservice01模块,打开浏览器可以看到。


image.png

点击进去后可以正常显示。


image.png

4.6修改mes_customer服务消费模块访问eureka

之前,我们mes_customer服务消费模块是直接通过http://localhost:8081去直接访问mes_provider01服务提供者模块,现在将通过eureka服务注册和发现与访问mes_provider01服务提供者模块。由于篇幅太长,可能每个模块的功能和端口大家忘记了,我在这里在列举一下:
mes_provider01服务提供者模块,端口8081
mes_customer01服务消费者模块, 端口8091
mes_eurekaservice01服务注册和发现模块,端口80

image.png
现在我们修改为下图模式。
image.png

接下来,我们首先在mes_customer01模块中增

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

完整的pom文件如下。

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.6.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.ht305</groupId>
    <artifactId>mes_customer01</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>mes_customer01</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

接着修改mes_customer01服务消费者模块中的yml文件,增加eureka和info信息。
完整的yml文件如下。

#服务端口
server:
  port: 9091

#服务名称
spring:
  application:
    name: mes_customer01

#增加eureka配置
#eureka 服务注册配置
eureka:
  client:
    service-url:
      register-with-eureka: false
      defaultZone: http://localhost/eureka/

info:
  app.name: mes_customer01
  company.name: http://ht305.com
  build.artifactId: com.ht305.mes_customer01
  build.version: 1.0

修改mes_customer01模块的中的启动程序,在模板RestTemplate方法上增加@LoadBalanced注解。

package com.ht305.mes_customer01;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class MesCustomer01Application {

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

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

在接口调用的时候,我们就可以通过服务名称进行调用。现在我们修改mes_customer01模块中的controller调用方法。

package com.ht305.mes_customer01.controller;

       import com.ht305.mes_customer01.pojo.Person;
       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 org.springframework.web.client.RestTemplate;
@RestController
public class PersonController {

   @Autowired
   private RestTemplate restTemplate;
   //String REST_URL = "http://localhost:8081";
  private static String REST_URL = "http://mes-provider01";

   @GetMapping("/person/{id}")
   public Person getPerson(@PathVariable Integer id){

       Person person = restTemplate.getForObject(REST_URL+"/person/"+id,Person.class);

       return person;
   }
}

重启服务后,我们访问http://127.0.0.1:9091/person/1,不出意外,发现提示500错误,为什么我们同ip直接访问没有问题,用http://mes_provider01服务名访问提示500错误呢?难道是不支持服务名访问,不是的,其实的我们服务名在命名的时候包含下划线"_"导致的,eureka支持中斜杠,但是不支持下划线。

image.png
接着,我们修改mes_provider01模块的注册名,将其中修改成中斜杠。
# 服务端口名称
server:
  port: 8081

#配置服务名称
spring:
  application:
    name: mes-provider01

#数据库连接相关配置

  datasource:
    #使用mysql数据库
    name: gas
    url: jdbc:mysql://localhost:3306/gas?serverTimezone=UTC&useUnicode=true$characterEncoding=utf8
    username: root
    password: 123456
    # 使用druid数据l连接池
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.cj.jdbc.Driver
    filters: stat
    maxActive: 20
    initialSize: 1
    maxWait: 60000
    minIdle: 1
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: select 'x'
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true
    maxOpenPreparedStatements: 20
#mybatis相关配置
mybatis:
  #制定mybatis mapper文件加载路径
  mapper-locations: classpath:/mapper/*Mapper.xml
  #mybatis配置文件加载路径
  config-location: classpath:mybatis/mybatis.cfg.xml
  #指定mapper文件中实体路径
  type-aliases-package: com.ht305.mes_provider01.dao

#eureka 服务注册配置
eureka:
  client:
    service-url:
      defaultZone: http://localhost/eureka/


info:
  app.name: mes-provider01
  company.name: http://ht305.com
  build.artifactId: com.ht305.mes-provider01
  build.version: 1.0

然后在mes-customer01服务调用模块的控制层修改调用url为:private static String REST_URL = "http://mes-provider01"。

package com.ht305.mes_customer01.controller;

        import com.ht305.mes_customer01.pojo.Person;
        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 org.springframework.web.client.RestTemplate;
@RestController
public class PersonController {

    @Autowired
    private RestTemplate restTemplate;
    //String REST_URL = "http://localhost:8081";
   private static String REST_URL = "http://mes-provider01";

    @GetMapping("/person/{id}")
    public Person getPerson(@PathVariable Integer id){

        Person person = restTemplate.getForObject(REST_URL+"/person/"+id,Person.class);

        return person;
    }
}

重启服务后,我们访问http://127.0.0.1:9091/person/1,发现可以正常访问,为了后面我们显示eureka集群功能,在这里我把三个模块的服务名下斜杠统一修改成中斜杠。

image.png

4.7创建基于eureka集群

上一篇下一篇

猜你喜欢

热点阅读