zoukankan      html  css  js  c++  java
  • SpringCloud如何创建一个服务提供者provider

    SpringCloud如何创建一个服务提供者provider

    创建子moudle provider-demo

    创建一个子module,项目名叫provider-demo. 填充springboot和springcloud依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    <dependencies>
      <!--springboot 依赖start-->
      <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-actuator</artifactId>
      </dependency>
      <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-devtools</artifactId>
       <optional>true</optional>
      </dependency>
      <dependency>
       <groupId>com.fasterxml.jackson.datatype</groupId>
       <artifactId>jackson-datatype-jsr310</artifactId>
      </dependency>
      <dependency>
       <groupId>org.springframework.cloud</groupId>
       <artifactId>spring-cloud-starter-eureka</artifactId>
      </dependency>
      <!--springboot 依赖结束-->
     
     
      <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger2</artifactId>
      </dependency>
      <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger-ui</artifactId>
      </dependency>
     
     
      <!--工具类 start-->
      <dependency>
       <groupId>com.google.guava</groupId>
       <artifactId>guava</artifactId>
      </dependency>
      <dependency>
       <groupId>org.projectlombok</groupId>
       <artifactId>lombok</artifactId>
       <optional>true</optional>
      </dependency>
     
      <dependency>
       <groupId>net.logstash.logback</groupId>
       <artifactId>logstash-logback-encoder</artifactId>
      </dependency>
      <!--工具类end-->
     
     
     </dependencies>

    spring-boot-starter-web 提供web能力,必须spring-boot-starter-actuator 提供项目统计和基础的监控endpoint, 想要使用spring-boot-admin监控就必须添加了 spring-boot-devtools 开发模式 jackson-datatype-jsr310 可以解决Java8新的时间APILocalDate解体 spring-cloud-starter-eureka eureka客户端,负责维护心跳和注册 swagger 提供Restful契约 lombok 看起来很清爽的编译级别getter setter工具 guava 大而全的Java必备类库 logstash-logback-encoder 想要收集日志到ELK,使用这个appender

    启动类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @EnableDiscoveryClient
    @SpringBootApplication
    public class ProviderDemoApplication {
     
      public static void main(String[] args) {
        SpringApplication.run(ProviderDemoApplication.class, args);
      }
     
    }

    @EnableDiscoveryClient 来启用服务注册

    这个ProviderDemoApplication应该放置于项目包的最外层,因为@SpringbootAppliatin包含了@ComponentScan的注解,默认扫描本类包下,否则必须手动指定scan。

    Swagger

    swagger就是一个配置类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    @EnableSwagger2
    @Configuration
    public class SwaggerConfiguration {
     
      private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
          .title("服务提供者 API")
          .description("提供用户信息查询")
          .termsOfServiceUrl("")
          .version("1.0.0")
          .build();
      }
     
      /**
       * 定义api配置.
       */
      @Bean
      public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
          .select()
          .apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
          .build()
          .apiInfo(apiInfo());
      }
     
    }

    对于swagger页面的路由,需要我们来引导下:

    创建一个controller来导航

    1
    2
    3
    4
    5
    6
    7
    8
    @Controller
    public class HomeController {
      @GetMapping(value = {"/api", "/"})
      public String api() {
        return "redirect:/swagger-ui.html";
      }
     
    }

    来一个Controller 接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Api
    @RestController
    @RequestMapping("/api/v1/users")
    public class UserController{
     
      private List<User> users = Lists.newArrayList(
        new User(1, "谭浩强", 100, LocalDate.now()),
        new User(2, "严蔚敏", 120, LocalDate.now()),
        new User(3, "谭浩强", 100, LocalDate.now()),
        new User(4, "James Gosling", 150, LocalDate.now()),
        new User(6, "Doug Lea", 150, LocalDate.now())
      );
     
      @GetMapping("/")
      public List<UserVo> list() {
        return users.stream()
          .map(u -> new UserVo(u.getId(), u.getName(), u.getAge(), u.getBirth()))
          .collect(Collectors.toList());
      }
    }

    一些简单的环境配置

    application.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    spring:
     application:
      name: provider-demo
     jackson:
      serialization:
       WRITE_DATES_AS_TIMESTAMPS: false
      default-property-inclusion: non_null
     
    #服务过期时间配置,超过这个时间没有接收到心跳EurekaServer就会将这个实例剔除
    #注意,EurekaServer一定要设置eureka.server.eviction-interval-timer-in-ms否则这个配置无效,这个配置一般为服务刷新时间配置的三倍
    #默认90s
    eureka.instance.lease-expiration-duration-in-seconds: 15
    #服务刷新时间配置,每隔这个时间会主动心跳一次
    #默认30s
    eureka.instance.lease-renewal-interval-in-seconds: 5
     
    server:
     port: 8082
     
     
    springfox:
     documentation:
      swagger:
       v2:
        path: /swagger-resources/api-docs
     
    log:
     path: logs

    application-dev.yml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    management:
     security:
      enabled: false
    eureka:
     client:
      serviceUrl:
     
     
    logstash:
     url: localhost:4560

    这里需要提一点,由于我集成了logstash, 所以必须安装好logstash, 见ELK入门使用。 当然可以跳过,只要不提供logback.xml的配置就行,把依赖中logstash移除即可。

    Log配置

    默认采用logback作为日志框架,简单配置如下,对于不想使用logstash的,移除logstash的appender即可。

    在resource下新建logback-spring.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    <?xml version="1.0" encoding="UTF-8"?>
    <configuration scan="true" scanPeriod="60 seconds" debug="false">
     
     <springProperty scope="context" name="appName" source="spring.application.name"
      defaultValue="unknown"/>
     <springProperty scope="context" name="log.path" source="log.path"
      defaultValue="logs"/>
     <springProperty scope="context" name="logstashurl" source="logstash.url"
      defaultValue="localhost:4560"/>
     
     <include resource="org/springframework/boot/logging/logback/base.xml"/>
     <!--输出到控制台-->
     <appender name="console" class="ch.qos.logback.core.ConsoleAppender">LoggingInterceptor
     
      <encoder>
       <pattern>%d{HH:mm:ss.SSS} %X{req.remoteHost} %X{req.requestURI}
        ${appName} [%thread] %-5level %logger{36} - %msg%n
       </pattern>
      </encoder>
     </appender>
     
     <!--输出到文件-->
     <appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
       <fileNamePattern>${log.path}/${appName}.%d{yyyy-MM-dd}.log</fileNamePattern>
      </rollingPolicy>
      <encoder>
       <pattern>%d{HH:mm:ss.SSS} ${appName} %X{req.remoteHost} %X{req.requestURI}
        %X{req.userAgent}
        %X{req.method} - [%thread] %-5level %logger{36} - %msg%n
       </pattern>
      </encoder>
     </appender>
     
     <!-- 输出到logstash-->
     <appender name="LOGSTASH" class="net.logstash.logback.appender.LogstashTcpSocketAppender">
      <destination>${logstashurl}</destination>
      <encoder charset="UTF-8" class="net.logstash.logback.encoder.LogstashEncoder"/>
     </appender>
     
     
     <springProfile name="dev">
      <root level="info">
       <appender-ref ref="console"/>
       <appender-ref ref="file"/>
       <appender-ref ref="LOGSTASH"/>
      </root>
     
     </springProfile>
     <springProfile name="test, prod">
      <root level="info">
       <appender-ref ref="file"/>
       <appender-ref ref="LOGSTASH"/>
      </root>
     </springProfile>
    </configuration>

    启动

    确保eureka已启动,admin最好也启动,方便查看app状态,ELK的日志系统也最好可以使用。当然,只有eureka是刚需。

    编译打包

    1
    mvn clean install package spring-boot:repackage

    运行main方法,指定profile为dev, 可以在idea中编辑运行配置,添加参数

    1
    --spring.profiles.active=dev

    或者命令行jar启动

    复制代码代码如下:
    java -Xms256m -Xmx1g -XX:+UseG1GC -jar ./target/provider-demo-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev

    启动后,访问eureka

    访问admin

    访问provider-demo

     

    暴露我们的API给consumer

    既然有服务提供者,必然是为了consumer消费。consumer应该如何消费?手动调用这个http请求即可。前面提到swagger Restful契约,就是服务提供者提供请求访问的参数和要求。consumer如果手动去开发这个client必然耗时,而且容易出错。所以,作为服务提供者,理应提供sdk或者client给consumer来用。

    在spring cloud技术体系中,远程调用自然是重中之重。目前我找到的具体用法为Feign+Ribbon+Hystrix.

    通过Feign的声明式接口对接,实现了consumer对provider的调用。ribbon客户端负载均衡,hystrix作健康熔断。

    在这里,我们就首先要提供Feign的接口了。

    把controller的api提炼成一个接口。首先,我们创建一个新的项目

    https://github.com/Ryan-Miao/spring-cloud-Edgware-demo/tree/master/provider-api

    将这个项目放到provider-demo的依赖列表里

    1
    2
    3
    4
    5
    6
    7
    <!--内部依赖-->
    <dependency>
     <groupId>com.test</groupId>
     <artifactId>provider-api</artifactId>
     <version>0.0.1-SNAPSHOT</version>
    </dependency>
    <!--内部依赖end-->

    抽离UserApi接口道provider-api项目中

    1
    2
    3
    4
    5
    6
    @RequestMapping("/api/v1/users")
    public interface UserApi {
     
      @GetMapping("/")
      List<UserVo> list();
    }

    在provider-demo的controller里改造如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    @Api
    @RestController
    public class UserController implements UserApi {
     
      private List<User> users = Lists.newArrayList(
        new User(1, "谭浩强", 100, LocalDate.now()),
        new User(2, "严蔚敏", 120, LocalDate.now()),
        new User(3, "谭浩强", 100, LocalDate.now()),
        new User(4, "James Gosling", 150, LocalDate.now()),
        new User(6, "Doug Lea", 150, LocalDate.now())
      );
     
      @Override
      public List<UserVo> list() {
        return users.stream()
          .map(u -> new UserVo(u.getId(), u.getName(), u.getAge(), u.getBirth()))
          .collect(Collectors.toList());
      }
    }

    这样,controller没有变化,只是被抽离了api路径。而独立出来的module provider-api就是我们给consumer提供的client。下一节使用consumer消费。

  • 相关阅读:
    HDU 2544 最短路
    HDU 3367 Pseudoforest
    USACO 2001 OPEN
    HDU 3371 Connect the Cities
    HDU 1301 Jungle Roads
    HDU 1879 继续畅通工程
    HDU 1233 还是畅通工程
    HDU 1162 Eddy's picture
    HDU 5745 La Vie en rose
    HDU 5744 Keep On Movin
  • 原文地址:https://www.cnblogs.com/lykbk/p/tyutyuhz345345345.html
Copyright © 2011-2022 走看看