天天看点

Spring Cloud NetflixSpring Cloud

Spring Cloud

简介

Spring Cloud 包含了许多子项目,提供了一些工具来快速构建分布式系统中一些常用模式,分布式配置管理、服务注册和发现、断路器、智能路由、全局锁等;

主要项目

  • Spring Cloud Config
  • Spring Cloud Netflix
  • Spring Cloud Bus
  • Spring Cloud Zookeeper

Spring Cloud Netflix

简介

Spring Cloud Netflix通过自动配置集成到Spring Boot应用中,用几个简单的注解可以快速启用和配置您的应用程序来构建大型分布式系统。提供包括服务发现、断路器、智能路由和客户端负载均衡等。

特性

  • Eureka实例可以注册和发现使用spring管理的bean
  • 嵌入式Eureka服务器可以用声明式的Java配置创建
  • Hystrix客户端可以用简单的注解驱动
  • Java配置可以启用嵌入的Hystrix指示面板
  • 客户端负载均衡

快速开始

Eureka服务器

Spring Cloud Netflix使用Eureka服务器来注册/发现服务

建立SpringBoot应用程序

pom.xml

<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>
    <groupId>org.pretent.spring.cloud</groupId>
    <artifactId>eurekaServer</artifactId>
    <version>0.0.1-SNAPSHOT</version>

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

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-netflix</artifactId>
                <version>1.2.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

</project>
           

Application.java

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

@SpringBootApplication
@EnableEurekaServer
public class Application {

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

application.properties

server.port = 
spring.application.name = eureka
eureka.client.registerWithEureka = false
eureka.client.fetchRegistry = false
           

至此Eureka服务器就搭建好了,只需要启动此SpringBoot应用即可。

在浏览器输入:http://localhost:8761/就可以看到eureka服务指示面板了

Spring Cloud NetflixSpring Cloud

@EnableEurekaServer

只要在SpringBoot应用使用@EnableEurekaServe注解,就可以配置此应用为一个Eureka服务器了,用来提供服务注册/发现中心。
           

Eureka服务器高可用

为了避免Eureka服务器的单点故障,可以启用多个Eureka服务器来实现Eureka服务器集群,达到高可用的目的,任何一个Eureka服务器故障不会导致Eureka服务注册中心不可用

假设有两个Eureka服务端,分别为http://localhost:8761/eureka/ 和http://localhost:8762/eureka/

只需要修改8761和8762的Eureka服务分别指向另一个即可。

  • 8761上的application.properties
server.port = 
spring.application.name = eureka
eureka.client.registerWithEureka = false
eureka.client.fetchRegistry = false
eureka.client.serviceUrl.defaultZone = http://localhost:/eureka/
           
  • 8762上的application.properties
server.port = 
spring.application.name = eureka
eureka.client.registerWithEureka = false
eureka.client.fetchRegistry = false
eureka.client.serviceUrl.defaultZone = http://localhost:/eureka/
           
  • Eureka客户端上的application.properties

Eureka 客户端

相对于Eureka服务端,向Eureka注册自己的服务和从Eureka获取服务发现服务统称为Eureka 客户端。

Eureka Client 服务提供者

pom.xml

<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>
    <groupId>org.pretent.spring.cloud</groupId>
    <artifactId>eurekaClient</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.3.RELEASE</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-netflix</artifactId>
                <version>1.2.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

</project>
           

Application.java

import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@SpringBootApplication
@EnableEurekaClient
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello world";
    }

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }
}
           

application.properties

server.port = 
spring.application.name = user-service
eureka.client.serviceUrl.defaultZone = http://localhost:/eureka/
           

至此Eureka客户端就配置好了,此SpringBoot应用既有Eureka客户端的功能。

eureka.client.serviceUrl.defaultZone:用来制定eureka服务器地址。

再次打开我们的eureka服务端http://localhost:8761/可以看到我们的user-service已经注册到eureka服务器了。

Spring Cloud NetflixSpring Cloud

@EnableEurekaClient

@EnableEurekaClient:只要在SpringBoot应用使用@EnableEurekaClient注解,就可以配置此应用为一个Eureka客户端了,既可以想Eureka服务器注册自己的服务,也可以查询定位其他服务;
@EnableDiscoveryClient:使用@EnableEurekaClient只能连接到Enable Server。也可以试用@EnableDiscoveryClient。
           
Eureka Client 服务消费者

Feign是一个声明式的Web Service客户端,它使得访问web服务更加简单。我们只需要使用Feign来创建一个接口并用注解来配置它既可完成。它具备可插拔的注解支持,Feign也支持可插拔的编码器和解码器。Spring Cloud为Feign增加了对Spring MVC注解的支持,还整合了Ribbon和Eureka来提供均衡负载的HTTP客户端实现。

pom.xml

<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>
    <groupId>org.pretent.spring.cloud</groupId>
    <artifactId>eureka-consumer</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.4.3.RELEASE</version>
    </parent>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-netflix</artifactId>
                <version>1.2.3.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

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

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

UsersService.java

import java.util.List;
import java.util.Map;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient("user-service")
public interface UsersService {

    @RequestMapping(method = RequestMethod.GET, value = "/users")
    List<Map> find();

    @RequestMapping(method = RequestMethod.GET, value = "/users/{userId}")
    Map get(@PathVariable("userId") String userId);

}
           

UsersController.java

import java.util.List;
import java.util.Map;

import org.pretent.spring.cloud.service.UsersService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/users")
public class UsersController implements UsersService {

    @Autowired
    private UsersService usersService;

    @RequestMapping
    public List<Map> find() {
        System.out.println(usersService.getClass().getName());
        return usersService.find();
    }

    @RequestMapping("{userId}")
    public Map get(@PathVariable String userId) {
        return usersService.get(userId);
    }
}
           

Application.java

import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;

@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class Application {

    public static void main(String[] args) {
        new SpringApplicationBuilder(Application.class).web(true).run(args);
    }
}
           

application.properties

spring.application.name = user-consumer
eureka.client.serviceUrl.defaultZone = http://localhost:/eureka/
           

启动此服务消费端,访问http://localhost:8080/users 就可以访问上面服务提供这提供的服务了,如果user-service启动了多个服务提供者,是被轮训调用的。

Hystrix 断路器

用来在服务调用失败后调用

Feign客户端已经支持Hystrix 断路器

UsersService.java

import java.util.List;
import java.util.Map;

import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@FeignClient(value = "user-service", fallback = UsersServiceFallback.class)
public interface UsersService {

    @RequestMapping(method = RequestMethod.GET, value = "/users")
    List<Map> find();

    @RequestMapping(method = RequestMethod.GET, value = "/users/{userId}")
    Map get(@PathVariable("userId") String userId);

}
           

改造加入UsersService

fallback = UsersServiceFallback.class

@FeignClient(value = “user-service”, fallback = UsersServiceFallback.class)

UsersServiceFallback.java

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.stereotype.Component;

@Component
public class UsersServiceFallback implements UsersService {

    public List<Map> find() {
        System.out.println("UsersService.find调用失败");
        return new ArrayList();
    }

    public Map get(String userId) {
        System.out.println("UsersService.get调用失败");
        return new HashMap();
    }
}
           

实现UsersService 接口并注册为Spring的bean

@Component