今天写一个自己提供服务自己消费服务的项目

依赖

<dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Hoxton.SR1</version>
                <scope>import</scope>
                <type>pom</type>
    </dependency>

项目目录

springcloud 父gradle编写 springcloud实例_User

首先是注册中心Eureka

springcloud 父gradle编写 springcloud实例_spring_02

server:
  port: 7001

# 服务名称, 在Spring Cloud非常重要, 可以使用它查找其它服务
spring:
  application:
    name: eureka-server

eureka:
  server:
    # 关闭自我保护模式
    enable-self-preservation: false
  client:
    # 单机情况下不需要在eureka server上获取注册信息
    fetch-registry: false
    # 单机的eureka server不需要向注册中心注册
    register-with-eureka: false
    service-url:
      # 如果是集群, 这里需要写其它几个节点的地址
      defaultZone: http://localhost:7001/eureka

启动类

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

}

启动注册中心

springcloud 父gradle编写 springcloud实例_ci_03

提供者(主要干活的人)

提供者的Controller->Service->Dao其实和之前SpringBoot的那一套流程是一样的,主要是让注册中心发现这个服务,@EnableDiscoveryClient把服务搞到注册中心中
依赖

<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-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>commons-codec</groupId>
            <artifactId>commons-codec</artifactId>
        </dependency>
        <!-- 添加Hystrix依赖 一会要用 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
    </dependencies>

springcloud 父gradle编写 springcloud实例_spring_04

server:
  port: 8080
  servlet:
    context-path: /user_sys

# 注册到Eureka Server的服务名称
spring:
  application:
    name: user-service

  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql:///et2009?serverTimezone=UTC
    username: root
    password: etoak

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

mybatis:
  mapper-locations: classpath:mapper/*.xml
  type-aliases-package: com.etoak.bean

logging:
  level:
    com.etoak.mapper: debug

启动类注意我刚才说的@EnableDiscoveryClient,@EnableHystrix两个注解

@SpringBootApplication
@EnableDiscoveryClient // 应用于Eureka、zookeeper、Nacos...
@MapperScan(basePackages = "com.etoak.mapper")
@EnableCircuitBreaker // 启动断路器
public class UserServiceApp {
    public static void main(String[] args) {
        SpringApplication.run(UserServiceApp.class, args);
    }
}

启动项目看注册中心

springcloud 父gradle编写 springcloud实例_spring_05


消费方(皮包公司)

feign

<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-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>

springcloud 父gradle编写 springcloud实例_spring_06

server:
  port: 8081
  servlet:
    context-path: /order_sys

spring:
  application:
    name: order-service

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

Controller+启动类

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients // 启动OpenFeign的自动配置
@RestController
public class OrderServiceApp {

    @Autowired
    UserService userService;

    @GetMapping("/user/{id}")
    public Result<User> getUser(@PathVariable int id) {
        return userService.getUser(id);
    }

    @GetMapping("postkv")
    public Result<User> postkv(User user) {
        return userService.addUser(user.getName(),
                user.getEmail(),
                user.getAge());
    }

    @GetMapping("postjson")
    public Result<User> postjson(User user) {
        return userService.addUser2(user);
    }

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

接口 (核心)–>负责去调服务提供者的服务 @FeignClient,没有实现类 相当于直接去映射提供方的Controller中的方法

@FeignClient("user-service") //spring name
@RequestMapping("/user_sys/user")//context-path/类
public interface UserService {
    @GetMapping("/getUser")//服务提供者controller中的方法
     Result getUser(@RequestParam int id);
    @PostMapping("/addUser")//服务提供者controller中的方法
     Result addUser(@RequestParam("name")String name);
    @PostMapping("/add")//服务提供者controller中的方法
     Result addUser2(@RequestBody User user);
}

我们执行以下比如我们访问/user/{id}这个路由下的方法localhost8081:order_sys/user/1

springcloud 父gradle编写 springcloud实例_User_07


ok 没什么问题

但是在提供端加上断点你会发现真正干活的还是提供段,他会指派提供端真正的去操作数据库

resttemplate

依赖

<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-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
        </dependency>

目录结构

springcloud 父gradle编写 springcloud实例_ci_08

server:
  port: 8083
  servlet:
    context-path: /goods_sys
spring:
  application:
    name: goods-service
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

启动类+Controller

@SpringBootApplication
@EnableDiscoveryClient
@RestController
public class GoodsServiceApp {
    @Autowired
    RestTemplate restTemplate;
    private static final String USER_SERVICE_URL="http://user-service/user_sys";
    @GetMapping("/user/{id}")
    public Result getUser(@PathVariable int id){
        //请求地址 请求方法 请求参数
        String url =USER_SERVICE_URL +"/user/getUser?id="+id;
        return restTemplate.getForObject(url,Result.class);
    }
    @GetMapping("/postjson")
    public Result postJson(User user){
        String url =USER_SERVICE_URL+"/user/add";
        //默认发json
        return restTemplate.postForObject(url,user,Result.class);
    }
    @GetMapping("/postkv")
    public Result postkv(User user){
        String url =USER_SERVICE_URL+"/user/addUser";
        MultiValueMap<String,Object> param =new LinkedMultiValueMap<>();
        param.add("name",user.getName());
        return restTemplate.postForObject(url,param,Result.class);
    }
    @Bean
    @LoadBalanced //RestTemplate添加负载均衡功能
    public RestTemplate restTemplate(){
        //发起请求的工具
        return new RestTemplate();
    }
    public static void main(String[] args) {
        SpringApplication.run(GoodsServiceApp.class,args);
    }
}

启动看注册中心是否有我们注册的消费方

springcloud 父gradle编写 springcloud实例_ci_09


运行localhost:8083:goods_sys/user/1

springcloud 父gradle编写 springcloud实例_spring_10


ok也是没有任何问题的

网关zuul(中转站)

  • 跳过消费者直接中转到提供者
    依赖
<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-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
    </dependencies>

springcloud 父gradle编写 springcloud实例_spring_11


application.yml

server:
  port: 9002
  servlet:
    context-path: /zuul
spring:
  application:
    name: zuul
eureka:
  client:
    service-url:
      defaultZone: http://localhost:7001/eureka

启动类

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

启动之后的注册中心zuul也是没有问题的

springcloud 父gradle编写 springcloud实例_ci_12


访问url的路径 http://localhost:9002/zuul/user-service/user_sys/user/getUser?id=1直接绕过消费者直接去调提供方的controller

网关地址:端口号/contextpath/提供方springname/contextpath/类url/方法url+参数

熔断器

当一时间访问某个接口的访问量过大,那我们用一个熔断器去做一个熔断,熔断这个操作一定是在提供方的Conrtoller的某些方法上,在提供方的启动类上需要@EnableHystrix这个注解来开启熔断

springcloud 父gradle编写 springcloud实例_User_13

@HystrixCommand(fallbackMethod = "getUserFallback", commandProperties = {
            @HystrixProperty(name = "circuitBreaker.enabled", value = "true"),   //是否开启断路器
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),  // 在一个滑动窗口内,开启熔断器检查统计条件,默认为20/10s。需要注意,如果在十秒内,有19个请求,都出现错误,也不会,触发熔断。
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "50"), // 失败率达到多少百分比后熔断。默认50%
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "20000") // 熔断多久以后开始尝试是否恢复。默认5s
    })

如果的请求老是出异常 那这个方法就会被熔断,5秒后在自动修复

以下是今天写的所有东西的一个概况

springcloud 父gradle编写 springcloud实例_User_14

总结

一个SpringCloud的小例子带着大家写一遍,主要还是摸流程,后面会带着大家实际操练的
最后总结一下SpringCloud用到的注解:

  • @EnableEurekaServer :加在注册中心的启动类
  • @EnbaleDiscoverClient:加在所有服务的启动类,让注册中心发现这个服务
  • @EnableHystrix:加在服务提供者的启动类,表示开启熔断器
  • @EnableFeignClients:加在FeignClients类型的消费方的启动类
  • @LoadBalanced :RestTemplate添加负载均衡功能
  • @EnableZuulProxy:网关对象的启动类上,开启网关动态代理