• 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消费。

  • 相关阅读:
    运算符优先级
    Tips—查询某结构体
    在线词典--(一、流程分析)
    数据库—SQLite3
    回调函数(转载)
    UNIX域套接字
    进程间通信小结
    HDU_oj_2027 统计元音
    HDU_oj_2026 首字母变大写
    HDU_oj_2025 查找最大字母
  • 原文地址:https://www.cnblogs.com/lykbk/p/tyutyuhz345345345.html
Copyright © 2020-2023  润新知