spring-cloud開發微服務筆記(二):高可用Eureka註冊中心的搭建與RestTemplate和Fengin客戶端調用微服務示例

 

引言:這一篇博客是將上一篇spring-cloud-eureka-server的單機模式改爲集羣模式,體現eureka的高可用特性。生產環境無論是Eureka註冊中心還是Client客戶端大多是部署在多臺機器上,也就是集羣模式,只有採用集羣模式才能體現eureka的高可用。這篇博客本人採用集羣模式實現了spring-cloud-eureka服務端和客戶端的高可用,同時使用RestTemplate和Fengin實現了微服務的調用。下面呈上乾貨代碼:

1. 新建maven子項目cloud-eureka-server2,cloud-eureka-client2

    1.1 cloud-eureka-server2.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">
    <parent>
        <artifactId>spring-boot-samples</artifactId>
        <groupId>com.hsf</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-eureka-server1</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>
    <description>spring-cloud-netflix-eureka-server cluster project demo</description>

    <dependencies>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.3</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-netflix-eureka-server</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.netflix.eureka</groupId>
            <artifactId>eureka-core</artifactId>
            <version>1.9.3</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.servlet</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
            <version>2.0.1.RELEASE</version>
        </dependency>
        <!--
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency> -->
    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

   1.2 cloud-eureka-client2.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">
    <parent>
        <artifactId>spring-boot-samples</artifactId>
        <groupId>com.hsf</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-eureka-client2</artifactId>
    <groupId>com.hsf</groupId>
    <version>0.0.1-SNAPSHOT</version>
    <description>spring-cloud-eureka client2 demo</description>
    <packaging>jar</packaging>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.0.2.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-client</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey.contribs</groupId>
                    <artifactId>jersey-apache-client4</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!-- mysql驅動依賴-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.0.2.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>com.fasterxml.jackson.core</groupId>
                    <artifactId>jackson-databind</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <!--Json轉換工具 -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.4</version>
        </dependency>
    </dependencies>


    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

1.3 修改cloud-eureka-server1和cloud-eureka-server2配置文件

     cloud-eureka-server1與cloud-eureka-server2互相註冊對方的地址

  1) cloud-eureka-server1項目的application-yaml文件

eureka:
  server:
    enable-self-preservation: false  #關閉自我保護機制
    eviction-interval-timer-in-ms: 5000 #默認 60*1000 單位:毫秒
  instance:
    hostname: peer1
  client:
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://peer2:8762/eureka/   #註冊到peer2節點的地址上
    registerWithEureka: false  #禁用自己註冊
spring:
  profiles:
    active: dev
  application:
    name: eurekaServer1
  main:
    allow-bean-definition-overriding: true
  #必須配置freemark模板引擎參數,否則啓動報錯
  freemarker:
    template-loader-path: classpath:/templates/
    prefer-file-system-access: false

2) cloud-eureka-server2項目的application.yaml文件

spring:
  profiles:
    active: dev
  application:
    name: eurekaServer
  main:
    allow-bean-definition-overriding: true
  freemarker:
    template-loader-path: classpath:/templates/
    prefer-file-system-access: false

eureka:
  server:
    enable-self-preservation: false  #關閉自我保護機制
    eviction-interval-timer-in-ms: 5000 #默認 60*1000 單位:毫秒
  instance:
    hostname: peer2
  client:
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/   #註冊到pper1服務節點的地址上
    registerWithEureka: false  #禁用自己註冊

注意:peer1和peer2域名都需要在 C:\Windows\System32\drivers\etc 目錄下的hosts文件中配置對應的域名解析

# localhost name resolution is handled within DNS itself.
    127.0.0.1       localhost
	::1             localhost
	127.0.0.1       peer1
	127.0.0.1       peer2

3) cloud-eureka-server2項目的application-dev.yaml文件

   

server:
  port: 8762
  address: 127.0.0.1

spring:
  datasource:
      type: com.zaxxer.hikari.HikariDataSource
      url: jdbc:oracle:thin:@localhost:1521:ORCL
      driverClassName: oracle.jdbc.driver.OracleDriver
      username: SYSTEM
      password: password

1.4 修改cloud-eureka-client1和cloud-eureka-client2項目的yaml配置文件

1) cloud-eureka-client1項目的application.yaml文件

server:
  port: 9090
  connection-timeout: 30000s
  servlet:
    context-path: /eurekaClient

spring:
  profiles:
    active: dev
  application:
    name: eurekaClient
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    driverClassName: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/test?useSSL=false
    username: root
    password: password  #mysql數據庫root用戶連接密碼
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL57Dialect

logging:
  level:
    org:
      hibernate:
        SQL: debug
        type:
          descriptor:
            sql: trace

cloud-eureka-client2項目的application.yaml文件只需要修改上述的server.port=9091即可,其他與cloud-eureka-client1項目的

application.yaml內容保持相同。

server:
  port: 9091

1.5 服務端與客戶端啓動類代碼

1)cloud-eureka-server1 與cloud-eureka-server2 spring-boot項目的啓動類代碼:

package com.hsf.cloudeurekaserver1;

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

@SpringBootApplication
@EnableEurekaServer
public class EurekaServer1Application {

    public static void  main(String[] args){

        SpringApplication.run(EurekaServer1Application.class,args);
    }
}
package com.hsf.cloudeurekaserver2;

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

@EnableEurekaServer
@SpringBootApplication
public class EurekaServer2Application {

    public static void main(String[] args){

        SpringApplication.run(EurekaServer2Application.class);
    }

}

注意:spring-cloud-eureka服務端項目均要加上@EnableEurekaServer註解

2)  cloud-eureka-client1與 cloud-eureka-client2 spring-boot項目的啓動類代碼:

package com.hsf.cloudeurekaclient1;

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

@SpringBootApplication
@EnableEurekaClient
public class CloudEurekaClient1Application {

    public static void main(String[] args) {

        SpringApplication.run(CloudEurekaClient1Application.class, args);
    }



}
package com.hsf.cloudeurekaclient2;

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

@SpringBootApplication
@EnableEurekaClient
public class EurekaClient2Application {

    public static void main(String[] args){

        SpringApplication.run(EurekaClient2Application.class,args);

    }
}

在IDEA中依次啓動cloud-eureka-server1, cloud-eureka-server1, cloud-eureka-client1, cloud-eureka-client2四個項目,項目啓動成功後,在瀏覽器地址欄中輸入http://peer1:8761後回車,出現如下畫面表示高可用服務註冊中心和服務客戶端項目啓動成功

                           圖 1  Eureka註冊中心服務註冊與服務發現效果圖

上圖中可以看到peer1的備用註冊中心地址:http://peer2:8762/eureka/ 以及一個服務實例EUREKACLIENT ,但是有兩個不同的實例ID,分別是eurekaClient1和eurekaClient2;若出現peer1節點宕機,所有的服務都將註冊到pee2節點上來。開發者可以手動關停cloud-eureka-server1應用,然後再瀏覽器地址欄中輸入http://peer2:8762回車查看效果可以看到EUREKACLIENT服務註冊到了peer2節點上來了,之前是沒有的。注意:開發環境上用的是僞集羣,用的是相同IP地址+不同端口號,而正式環境一定是不同機器IP地址+相同端口號的。

2. cloud-eureka-client項目提供RestFull Service Api服務

2.1 檢驗客戶端負載均衡的http接口

cloud-eureka-client1項目的controller包中新建DemoController.java控制器類,代碼如下

package com.hsf.cloudeurekaclient1.controller;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
    private static final Logger logger = LoggerFactory.getLogger(DemoController.class);
    @Value("${eureka.instance.hostname}")
    private String hostname;
    @Value("${server.port}")
    private String port;


    @RequestMapping(path="/remoteIndex",method= RequestMethod.GET)
    public String Index(){
        return hostname+":"+port;

    }

   
}

cloud-eureka-client2項目的DemoController同上,可直接從cloud-eureka-client1項目中複製過來

3. 新建服務消費端項目cloud-web子項目並引入eureka-client和openfengin的依賴

3.1 cloud-web.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">
    <parent>
        <artifactId>spring-boot-samples</artifactId>
        <groupId>com.hsf</groupId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>cloud-web</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
       <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>2.0.2.RELEASE</version>
            <exclusions>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-client</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey</groupId>
                    <artifactId>jersey-core</artifactId>
                </exclusion>
                <exclusion>
                    <groupId>com.sun.jersey.contribs</groupId>
                    <artifactId>jersey-apache-client4</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
            <version>2.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.3</version>
        </dependency>
        <!-- apache commons加密解密工具類 -->
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
            <version>1.10</version>
        </dependency>

    </dependencies>

    <build>
        <finalName>${project.artifactId}</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <mainClass>com.hsf.samplesimpl.MySpringApplication</mainClass>
                </configuration>
            </plugin>
            <!-- 跳過單元測試 -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.1</version>
            </plugin>
        </plugins>
    </build>

</project>

3.2 cloud-web服務消費端項目yaml配置文件

1) application-dev.yaml

server:
  address: 127.0.0.1
  port: 8080

rpcServices:
  serviceName: eurekaClient
  contextPath: /eurekaClient
  indexUrl: /remoteIndex
  userInfoUrl: /userInfo

spring:
  datasource:        #配置數據源,必配,否則項目啓動報錯
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:oracle:thin:@localhost:1521:ORCL
    driverClassName: oracle.jdbc.driver.OracleDriver
    username: SYSTEM
    password: password   #oracle數據庫SYSTEM用戶登陸密碼


eureka:
  client:
    serviceUrl:
      defaultZone: http://peer1:8761/eureka/,http://peer2:8762/eureka/  #服務中心註冊地址
  instance:
    hostname: localhost
    instance-id: cloud-web  #實例註冊到eureka服務器上的唯一實例ID
    prefer-ip-address: true   #顯示IP地址
    lease-renewal-interval-in-seconds: 30 #過多長時間發送心跳給eureka服務器,表明它仍然活着,默認爲30s

注意:服務消費方方也要註冊到註冊中心去,不然調用其他微服務時會報No Instances Available for eurekaClient 異常,導致調用微服務失敗,http接口報500錯誤
 

2) application.yaml

server:
  servlet:
    context-path: /myApp
    session:
      cookie:
        name: customCookie
        max: 30m
  connection-timeout: 30000ms
spring:
  profiles:
    active: dev
  application:
    name: myApplication
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.Oracle10gDialect

logging:
  level:
    org:
      hibernate:
        SQL: debug
        type:
          descriptor:
            sql: trace

4 服務提供方cloud-eureka-client1和cloud-eureka-client2項目開發Restful接口

分別提供一個證明負載均衡和從數據庫查詢數據的接口,mysql表用的之前建的userinfo表,持久層框架用的spring-data-jpa框架,代碼如下

4.1 Controller層代碼

package com.hsf.cloudeurekaclient1.controller;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.hsf.cloudeurekaclient2.model.UserInfo;
import com.hsf.cloudeurekaclient2.service.UserInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
    private static final Logger logger = LoggerFactory.getLogger(DemoController.class);
    @Value("${eureka.instance.hostname}")
    private String hostname;
    @Value("${server.port}")
    private String port;
    @Autowired
    private UserInfoService userInfoService;

    private static Gson gson = new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").create();


    @RequestMapping(path="/remoteIndex",method= RequestMethod.GET)
    public String Index(){
        return hostname+":"+port;

    }

    @RequestMapping(path="/userInfo",method = RequestMethod.GET)
    public ResponseEntity<UserInfo> queryUserInfo(@RequestParam("userAccount") String userAccount){
        logger.info("/userInfo request begin:----------");
        UserInfo userInfo = userInfoService.findByUserAccount(userAccount);
        String jsonInfo = gson.toJson(userInfo);
        logger.info("userInfo:"+jsonInfo);
        ResponseEntity<UserInfo> entity = new ResponseEntity(userInfo, HttpStatus.OK);
        return entity;
    }
    
}

4.2 Service層代碼

1)  接口類

package com.hsf.cloudeurekaclient1.service;

import com.hsf.cloudeurekaclient1.model.UserInfo;

public interface UserInfoService {

    UserInfo findByUserAccount(String userAccount);


}


2) 實現類

package com.hsf.cloudeurekaclient1.service.impl;

import com.hsf.cloudeurekaclient1.dao.UserInfoRepository;
import com.hsf.cloudeurekaclient1.model.UserInfo;
import com.hsf.cloudeurekaclient1.service.UserInfoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserInfoServiceImpl implements UserInfoService {
    @Autowired
    private UserInfoRepository userDao;
    @Override
    public UserInfo findByUserAccount(String userAccount) {
        return userDao.findByUserAccount(userAccount);
    }
}

4.3 Dao層代碼

package com.hsf.cloudeurekaclient1.dao;

import com.hsf.cloudeurekaclient1.model.UserInfo;
import org.springframework.data.repository.CrudRepository;

public interface UserInfoRepository extends CrudRepository<UserInfo,Integer> {

    UserInfo findByUserAccount(String userAccount);

}

cloud-eureka-client2項目的Restful接口開發代碼同上,可知直接複製過來

代碼結構如下圖所示

服務提供方代碼結構

4.4 實體類代碼

package com.hsf.cloudeurekaclient1.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.io.Serializable;
import java.util.Date;

@Entity
@Table(name="userinfo")
public class UserInfo implements Serializable {

    @Id
    private Integer Id;
    @Column(name="user_account")
    private String userAccount;
    private String password;
    @Column(name="nick_name")
    private String nickName;
    @Column(name="dept_no")
    private Integer deptNo;
    @Column(name="email_address")
    private String emailAddress;
    @Column(name="birth_day")
    private Date birthDay;

   //省略set,get方法
}

 

4.5 cloud-web項目啓動類

package com.hsf.samplesimpl;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class MySpringApplication {
    private static final Logger logger = LoggerFactory.getLogger(MySpringApplication.class);
    public static void main(String[] args) {
        SpringApplication application = new SpringApplication(MySpringApplication.class);
        application.run(args);
    }
   

    @Bean
    @LoadBalanced    //客戶端添加支持負載均衡註解
    public RestTemplate restTemplate(){
        return  new RestTemplate();
    }


}

5 服務消費方接口開發

5.1 採用RestTemplate調用微服務

1) Controller層代碼

IUserService接口

package com.hsf.samplesimpl.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;


@RestController
public class UserController extends BaseController {
    
   
   @Autowired
   private RestTemplate restTemplate;    //注入RestTemplate bean實例

    @Value("${rpcServices.serviceName}")   //取自配置文件的遠程微服務名
    private String serviceName;

    @Value("${rpcServices.contextPath}")   //微服務上下文路徑
    private String contextPath;

    @Value("${rpcServices.indexUrl}")     // 驗證負載均衡URL
    private String indexUrl;

  
    //驗證客戶端調用微服務實現了負載均衡接口

    @RequestMapping(path="/localIndex",method = RequestMethod.GET)
    public String index(){
        logger.info("/localIndex request start");
        StringBuilder builder = new StringBuilder("http://");
        builder.append(serviceName).append(contextPath).append(indexUrl);
        String uri = builder.toString();
        logger.info("uri:"+uri);
        ResponseEntity<String> entity = restTemplate.getForEntity(uri,String.class);
        return entity.getBody();
    }

   // 驗證從微服務提供方數據庫獲取數據接口
   @RequestMapping(path="/remoteUserInfo",method = RequestMethod.GET)
    public ResponseEntity<MySqlUserInfo> 
    queryMysqlUserInfo(@RequestParam("userAccount") String userAccount) {
        logger.info("/remoteUserInfo request start");
        logger.info("userAccount:"+userAccount);
        StringBuilder builder = new StringBuilder("http://");
        builder.append(serviceName).append(contextPath).append(userInfoUrl).append("? 
        userAccount={userAccount}");
        String uri = builder.toString();
        logger.info("uri:"+uri);
        Map<String,String> paramMap = new HashMap<>();
        paramMap.put("userAccount",userAccount);
        ResponseEntity<MySqlUserInfo> entity =  
        restTemplate.getForEntity(uri,MySqlUserInfo.class,paramMap);
          return entity;
    }



}

MysqlUserInfo實體類

package com.hsf.samplesimpl.model;

import java.io.Serializable;
import java.util.Date;

public class MySqlUserInfo implements Serializable {
    private Integer Id;
    private String userAccount;
    private String password;
    private String nickName;
    private Integer deptNo;
    private String emailAddress;
    private Date birthDay;

   //此處省略set和get方法
}

 

2) 在IDEA中啓動兩個Eureka服務端項目和Eureka客戶端項目後,再啓動服務消費方cloud-web項目,均爲Debug模式啓動,Eureka服務端和客戶端以及服務消費方項目啓動成功後如下圖所示:

3) 在來看一下服務註冊中心的服務實例信息

我們發現cloud-web項目的實例也註冊到了服務註冊中心上來了

4) postman測試RestTemplate調用eurekaClient服務的/remoteIndex接口驗證客戶端負載均衡

第一次調用效果圖

第二次調用效果圖

連續調用循環出現9090和9091端口,驗證了客戶端負載均衡

5) postman測試RestTemplate調用eurekaClient服務的獲取mysql數據庫用戶信息接口

 5.2 採用Fengin調用微服務

1)  Fengin服務接口層代碼

package com.hsf.samplesimpl.service;

import com.hsf.samplesimpl.model.MySqlUserInfo;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;


@FeignClient(name="eurekaClient")    //name對應服務提供方的服務名,也就是yaml配置文件中spring.application.name對應的value值
public interface FeignService {

    //RequestMapping 註解中的value值對用url映射,method對應請求方法,根據官方文檔提示這裏不能用GetMapping註解
    @RequestMapping(value = "/eurekaClient/remoteIndex",method = RequestMethod.GET)
    String getUrl();

    @RequestMapping(value="/eurekaClient/userInfo",method = RequestMethod.GET)
    MySqlUserInfo getUserInfo(@RequestParam("userAccount") String userAccount);

}

2) Controller層代碼

UserController類中注入FenginService實例並新增兩個Fengin調用的接口
@Resource
private FeignService feignService;


@GetMapping(value="/remoteUrl")
    public String getRemoteUri(){
        return feignService.getUrl();
    }

    @GetMapping(value="/feignUserInfo")
    public MySqlUserInfo getRemoteUserInfo(String userAccount){

        return  feignService.getUserInfo(userAccount);
    }


3) postman測試Fengin調用eurekaClient微服務的驗證負載均衡接口

4) postman測試Fengin調用eurekaClient微服務獲取Mysql數據庫用戶信息接口

總結:

  • 本文采用spring cloud的spring-cloud-netflix-eureka-server模塊搭建了兩個服務註冊中心,實現註冊中心高可用,服務註冊中心項目的啓動類需要加上@EnableEurekaServer註解使當前服務成爲一個服務註冊中心;
  • 採用spring-cloud-netflix-eureka-client模塊搭建了微服務提供方項目和微服務調用方項目,並且微服務提供方項目構建了兩個實例以驗證客戶端負載均衡,微服務客戶端項目的啓動類上都要加上@EnableEurekaClient註解或者@DiscoveryClient註解,讓當前項目啓動後其服務註冊到註冊中心;
  • 通過將各自系統的服務註冊到服務註冊中心,不同系統之間可以實現系統代碼無耦合地調用,獲取其他註冊到註冊中心服務的接口,從而可以方便地通過服務名調用不通系統不通數據源的接口;
  • 需要注意的是無論是服務註冊中心、服務提供方還是服務消費方都需要配置數據源項目啓動時纔不會報錯,無論是服務提供方還是服務消費方都需要註冊到Eureka註冊中心上去才能實現微服務的正常調用
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章