1. 程式人生 > >SpringCloud入門(eureka叢集和feign負載均衡)

SpringCloud入門(eureka叢集和feign負載均衡)

什麼是springcloud?

這是spring官網對springcloud的介紹,大致意思就是:讓分散式系統簡單化。springcloud是建立在springboot之上的,也就是說他是需要依賴springboot的,因此學習springcloud首先就要了解springboot。在上一篇文章中有介紹到springboot。

這張圖說明了Spring Cloud是實施微服務的一系列套件,包括:服務註冊與發現、斷路器、服務狀態監控、配置管理、智慧路由、一次性令牌、全域性鎖、分散式會話管理、叢集狀態管理等。

下面就用IDEA搭建springcloud專案,來看看springcloud是如何整合這些元件。

搭建一個小型的springcloud專案

1.首先使用IDEA建立一個maven父工程,在pom.xml裡引入需要的jar包依賴,dependencyManagement用來管理jar包版本。

<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>1.5.9.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>5.0.4</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.0.31</version>
            </dependency>

            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.3.0</version>
            </dependency>
            <dependency>
                <groupId>ch.qos.logback</groupId>
                <artifactId>logback-core</artifactId>
                <version>1.2.3</version>
            </dependency>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>${junit.version}</version>
                <scope>test</scope>
            </dependency>
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>${log4j.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

2.然後建立子工程,首先建立一個provider工程,作為服務提供者。

右鍵選中父工程後new一個module,選擇maven就可以新建一個子工程了。

每建立一個新工程首先在pom.xml裡新增一些基礎的依賴。

 <dependencies>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId><!--簡化javabean開發的jar,用註解的方式快速寫setter,getter,-->
        </dependency>

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

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

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

        <!-- actuator監控資訊完善 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Dalston.SR1</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId><!--eureka元件,後面沒帶server,即為客戶端client-->
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>1.5.9.RELEASE</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.0.4</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.31</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId><!--因該是將javabean變為配置檔案的jar包-->
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-core</artifactId>
            <version>1.2.3</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>${junit.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>${log4j.version}</version>
        </dependency>
    </dependencies>

接著是編寫application.yml檔案

server:
  port: 8001
spring:
  application:
    name: userapi       #服務提供者名字,最終會顯示在eureka註冊中心的名字上,消費者通過這個名字找到服務並呼叫
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/testspringboot
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource  #阿里巴巴的連線池
    dbcp2:
      max-total: 5                                 #最大維持連線數
      min-idle: 5                                   #最小維持連線數
      initial-size: 5                               #初始化大小
      max-wait-millis: 200                           #等待連接獲取的最大等待時間
  jpa:
    hibernate:
      ddl-auto: update                              #若資料庫中有表,則不建立。
    show-sql: true

這裡的持久層框架使用的是SpringJPA,比較方便。

下面看下provide工程的目錄結構:

 這裡provider8001代表是執行在8001埠上的服務提供者,後面要實現負載均衡還會建立多個服務提供者。

注意每個子工程都是一個獨立的springboot專案,因此每次新建完一個子module都要編寫springboot的啟動類。且啟動類的位置要包含其他所有的包,這樣這個啟動類在能在啟動時載入其他的需要放入spring容器中的bean,也就是對其他的包進行管理。

啟動類的通用寫法:

package com.tellhow;

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

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

controller層程式碼:

package com.tellhow.controller;

import com.tellhow.repository.UserRepository;
import com.tellhow.entity.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserRepository userRepository;

    @RequestMapping("test")
    public String testProvider(){
        return "Hello world";
    }

    @RequestMapping(value = "/users",method = RequestMethod.GET)
    public List<User> getUsers(){
        return userRepository.findAll();
    }

    @RequestMapping(value = "/user",method = RequestMethod.POST)
    public boolean addUser(User user){
        userRepository.save(user);
        return true;
    }

    @RequestMapping(value = "/user",method = RequestMethod.PUT)
    public boolean updateUser(User user){
        userRepository.save(user);//如果主鍵存在則修改。
        return true;
    }


}

主要就是查詢資料庫裡的user列表,用來展示分散式呼叫的。持久層實現參見上一篇文章springboot整合jpa.

服務層就大致寫完了,寫完之後需要驗證一下是否正常可用,保證下寫消費者呼叫時能正常執行。

代表服務消費者可以正常啟動,下面就可以來寫消費者了。

1.與建立服務提供者同樣的操作,右鍵父工程,新建module,新增pom.xml依賴,編寫applicaton.yml檔案。編寫啟動類

applicaton.yml檔案裡只需要配置一個埠即可

server:
  port: 80

啟動類:

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


@SpringBootApplication
@ComponentScan(basePackages = {"com.tellhow"})//指定啟動時掃描哪些需要管理的包,若將啟動類放在需要管理的包的上一級,則不需要此註解
public class ConsumerApplicationRun {
    public static void main(String args[]){
        SpringApplication.run(ConsumerApplicationRun.class,args);
    }
}

conctroller層:通過RestTemplate呼叫服務提供者。由此可以看出,springcloud的分散式呼叫,是用rest來進行呼叫,不同於dubbo的RPC呼叫。

使用RestTemplate之前需要將其注入到spring容器中。

package com.tellhow.cfgBean;

import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
import com.netflix.loadbalancer.RetryRule;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ConfigBean {
    @Bean
    public RestTemplate getRestTemplate(){
        return new RestTemplate();
    }
}

controller:

package com.tellhow.controller;

import com.tellhow.beans.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class UserController {
    @Autowired
    public RestTemplate restTemplate;

    //public static final String PREX="http://localhost:8001";
    public static final String PREX="http://USERAPI";//通過eureka上註冊的服務名來呼叫

    @RequestMapping(value = "/consumer/user",method = RequestMethod.GET)
    public List<User> getUsers(){
        return restTemplate.getForObject(PREX+"/user/users",List.class);
    }
}

然後先啟動服務提供者,再啟動服務消者,檢視結果,因為消費者工程的埠後是80,因此可以訪問地址可以省略埠

可以看到,成功呼叫。

加入eureka註冊中心

eureka是用來做服務註冊與發現的,也就是服務提供者將服務註冊到eureka註冊中心,然後消費者在註冊中心對服務進行呼叫消費。例如:想要開淘寶店需要先到淘寶平臺註冊店鋪,然後買家才可以在淘寶上找到該店鋪進行消費購買。

當然eureka還有很多功能:通過心跳檢測、健康檢查、客戶端快取等機制,保證了系統具有高可用和靈活性。

接下來建立一個eureka的子工程。建立module的過程不做贅述了。

pom.xml依賴

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

application.yml

server:
  port: 7000
eureka:
  instance:
    hostname: eureka7000.com  #eureka主機名
  client:
    register-with-eureka: false   #表示不向註冊中心註冊自己
    fetch-registry: false          # 表示自己端就是註冊中心,職責就是維護服務例項,不需要檢索服務。
    service-url:
      defaultZone: http://eureka7001.com:7000/eureka/

啟動類:

package com.tellhow;

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

@SpringBootApplication
@EnableEurekaServer         //Eureka服務類,接受其他服務註冊進來。
public class EurekaApplicationRun {
    public static void main(String args[]){
        SpringApplication.run(EurekaApplicationRun.class,args);
    }
}

如此,eureka註冊中心就建立完成了,之後需要在privoder工程裡新增向註冊中心註冊的相關東西。pom.xml新增eureka依賴

首先provider工程啟動類上添加註解:@EnableEurekaClient //啟動eureka客戶端

然後application.yml改為如下:

server:
  port: 8001
spring:
  application:
    name: userapi       #服務提供者名字,最終會顯示在eureka註冊中心的名字上,消費者通過這個名字找到服務並呼叫
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://localhost:3306/testspringboot
    username: root
    password: root
    type: com.alibaba.druid.pool.DruidDataSource  #阿里巴巴的連線池
    dbcp2:
      max-total: 5                                 #最大維持連線數
      min-idle: 5                                   #最小維持連線數
      initial-size: 5                               #初始化大小
      max-wait-millis: 200                           #等待連接獲取的最大等待時間
  jpa:
    hibernate:
      ddl-auto: update                              #若資料庫中有表,則不建立。
    show-sql: true
eureka:
  client:
    service-url:
      defaultZone: http://eureka7000.com:7000/eureka  #後面必須加個eureka 才能註冊上去。

  instance:
    instance-id: userAPI-8001 #註冊在eureka上的服務的例項的id
    prefer-ip-address: true    #顯示IP地址,方便查詢
info:
  app.name: TestMaven
  company.name: www.tellhow.com
  .artifactId: $project.artifactId$
  buibuildld.version: $project.version$

消費者工程裡也做相似的改動:啟動類添加註解:

@EnableEurekaClient //eureka是服務註冊中心,所以對用向服務中心註冊服務的,和向服務中心消費服務的,都是eureka客戶端

application.yml

server:
  port: 80
eureka:
  client:
    register-with-eureka: false #消費者 不向服務端註冊
    service-url:
      defaultZone: http://eureka7000.com:7000/eureka/

修改完成後先啟動註冊中心工程,再啟動服務提供者工程,接著是消費者。

啟動完成後訪問:http://127.0.0.1:7000如果能出現一下畫面則代表eureak註冊中心工程建立成功。

 今天先寫到這裡,明天繼續寫eureka高可用