springcloud基础入门

先了解一下springcloud和dubbo的区别

dubbo由于是二进制的传输,占用带宽会更少

springCloud是http协议传输,带宽会比较多,同时使用http协议一般会使用JSON报文,消耗会更大

dubbo的开发难度较大,原因是dubbo的jar包依赖问题很多大型工程无法解决

springcloud的接口协议约定比较自由且松散,需要有强有力的行政措施来限制接口无序升级

dubbo的注册中心可以选择zk,redis等多种,springcloud的注册中心只能用eureka或者自研

springcloud的最大的特点是可以很好的和restful模式进行交互

dubbo是基于rpc的

 

在开始SpringCloud之前,先看一下一个简单的服务提供者和服务消费者。服务提供者提供一个REST风格的HTTP接口给服务消费者。

 

1.1 普通的提供者

 

 

1.1.1 pom.xml

 

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

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.8</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-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>

1.1.1 关键代码

package com.test.springcloud.provider.pojo;

public class User {
    private Long id;
    private String username;
    //getter/setter略

}

Controller

package com.test.springcloud.provider.controller;

import com.test.springcloud.provider.pojo.User;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @GetMapping("/simple/{id}")//rest 风格,微服务一般都使用 rest 风格
    public User findById(@PathVariable Long id) {
        User user=new User();
        user.setId(id);
        user.setUsername("hello "+id);
        return user;
    }

1.1.1 application.yml

server:
  port: 8081

1.1 普通的消费者

1.1.1 pom.xml

parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.5.13.RELEASE</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
   <java.version>1.8</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-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>

实体类:

package com.test.springcloud.consumer.pojo;

public class User {
    private Long id;
    private String username;
    //getter/setter略
}

Controller

package com.test.springcloud.consumer.controller;

import com.test.springcloud.consumer.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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 UserController {
    @Autowired
    private RestTemplate restTemplate;// rest 请求模板类

    @Value("${user.userServicePath}")//从配置文件中读取指定属性,名字和配置中保持一致即可
    private String userServicePath;

    @GetMapping("/user/{id}")
    public User findById(@PathVariable Long id) {
        //调用指定的地址,传递参数过去,将返回的数据解析为 user 格式
        // return this.restTemplate.getForObject("http://localhost:7900/simple/"+ id, User.class);//硬编码,不好
        return this.restTemplate.getForObject(this.userServicePath + id, User.class);//通过配置文件注入地址的方式
    }
}

启动类

package com.test.springcloud.consumer;

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 SpringcloudTestConsumerApplication {
   @Bean
   public RestTemplate restTemplate() {
      return new RestTemplate();
   }
   public static void main(String[] args) {
      SpringApplication.run(SpringcloudTestConsumerApplication.class, args);
   }
}

1.1.1 application.yml

server:
  port: 8082
userPath: http://localhost:8080/user/

1.1 Eureka

在消费者调用服务的时候,服务提供者的地址是以硬编码的形式写在配置文件中的。如果服务端迁移就需要改变地址。我们可以将服务注册到Eureka,消费者不必关心提供者的真实地址,通过Eureka中的服务名直

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

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
   <java.version>1.8</java.version>
   <spring-cloud.version>Edgware.SR2</spring-cloud.version>
</properties>

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <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>

 

 

接调用服务即可。

 

1.1.1 启动类

 

在启动类上增加@EnableEurekaServer注解

 

server:
  port: 8083

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

启动8083端口访问

能看见一个管理的后台

 

1.1.1 修改服务提供者

pom.xml中添加SpringCloud的引用

 

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>Edgware.SR2</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

启动类上添加注解@EnableEurekaClient:

yml配置文件

server:
  port: 8081
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8083/eureka/
spring:
  application:
    name: service-provider  #这个名字就是调用服务时的名字

1.1.1 修改消费者

pom.xml同提供者一样

启动类添加注解@EnableEurekaClient还有restTemplate上的@LoadBalanced

完整的application.yml

erver:
  port: 8082
user: #此处 user没有任何含义,主要是一个名字而已
  #即便在这里也类似于硬编码, 还是不够灵活,定义提供者的位置
  #userServicePath: http://localhost:8081/simple/
  userServicePath: http://SERVICE-PROVIDER/simple/
eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8083/eureka/
spring:
  application:
    name: service-comsumer

1.1 ribbon负载均衡

在消费者中添加依赖:

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

启动两次提供者(一个运行main方法,一个maven启动),修改端口,模拟同一个服务部署在不同的服务器上,如端口为8084。稍稍修改一些controller中的代码,区分两个服务:

然后访问

 

1. Feign

 

Feign是一个声明式的伪Http客户端,它使得写Http客户端变得更简单。使用Feign,只需要创建一个接口并注解。Feign默认集成了Ribbon,并和Eureka结合,默认实现了负载均衡的效果。

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.5.13.RELEASE</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
   <java.version>1.8</java.version>
   <spring-cloud.version>Edgware.SR2</spring-cloud.version>
</properties>

<dependencies>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <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>
   <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>

启动类添加@EnableEurekaClient注解和@EnableFeignClients

 

1.1 service

package com.test.springcloud.feign.consumer.service;

import com.test.springcloud.feign.consumer.pojo.User;
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 = "SERVICE-PROVIDER")
public interface UserService {
    @RequestMapping(value = "/simple/{id}", method = RequestMethod.GET)
    User getUserById(@PathVariable(value = "id") Long id);
}

@FeignClient的值是服务提供者在Eureka上的名字。

方法上@RequestMapping的值是请求服务提供者时的路径。参数的传递方式和SpringMVCController接收参数时语法一样,如@PathVariable,@RequestParam

 

User类同服务提供者中的一样。

 

1.1 Controller

package com.test.springcloud.feign.consumer.controller;

import com.test.springcloud.feign.consumer.pojo.User;
import com.test.springcloud.feign.consumer.service.UserService;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public User sayHi(@RequestParam Long id) {
        return userService.getUserById(id);
    }
}

1.1 application.yml

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8083/eureka/
server:
  port: 8085
spring:
  application:
    name: service-feign

  

1. 断路器Hystrix

1.1 Ribbon使用断路器

ribbon的消费者工程中加入断路器依赖:

 

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

 

启动类上添加注解@EnableHystrix

启动项目,在服务提供者挂掉的时候,会看到提示信息:

 

 

如果不做熔断,会在请求服务提供者超时之后报错:

 

 

 1.2Feign使用熔断器

在yml配置文件增默认自带熔断器打开

feign:
  hystrix:
    enabled: true

在消费的service层修改

@FeignClient(value = "SERVICE-PROVIDER", fallback = TestServiceFallback.class)
public interface TestService {
    @RequestMapping(value = "/user/{id}", method = RequestMethod.GET)
    User getUserById(@PathVariable(value = "id") Integer id);

}

创建TestService的实现类TestServiceFallback

@Component
public class TestServiceFallback implements TestService {
    @Override
    public User getUserById(Integer id) {
        User user = new User();
        user.setId(-2);
        user.setName("server error2");
        return user;
    }

1.3 Hystrix Dashboard (Hystrix 仪表盘)

 在pom中添加依赖(feign和robbin)

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

再启动类加

@EnableHystrix
@EnableHystrixDashboard注解

启动访问localhost:port/hystrix

 

访问服务的提供者 能看到这个界面可以清晰的看到这个请求的成功率和失败率

 

 

 

1. 路由Zuul

新建工程pom配置

<parent>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-parent</artifactId>
   <version>1.5.13.RELEASE</version>
   <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
   <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
   <java.version>1.8</java.version>
   <spring-cloud.version>Edgware.SR3</spring-cloud.version>
</properties>

<dependencies>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-eureka</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
   </dependency>
   <dependency>
      <groupId>org.springframework.cloud</groupId>
      <artifactId>spring-cloud-starter-zuul</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>

yml文件的配置

eureka:
  client:
    serviceUrl:
      defaultZone: http://localhost:8083/eureka/
server:
  port: 8086
spring:
  application:
    name: service-zuul
zuul:
  routes:
    api-a:
      path: /api-a /**
      serviceId: service-consumer
    api-b:
      path: /api-b /**
      serviceId: service-feign

routes定义了请求转发的规则。pathurl访问路径,serviceId是对应的Eureka中的服务

http://localhost:8086/api-a/user/1会发送到service-consumer对应的工程

http://localhost:8086/api-b/test?id=2会发送到feign的工程

启动类:

@SpringBootApplication
@EnableEurekaClient
@EnableZuulProxy
public class Zuul0723Application {

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

 

posted @ 2018-09-12 21:16  BlackCatFish  阅读(424)  评论(0编辑  收藏  举报