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

SpringCloud如何创建一个服务提供者provider的更多相关文章

  1. SpringCloud学习5-如何创建一个服务提供者provider

    前几篇主要集中在注册中心eureka的使用上,接下来可以创建服务提供者provider来注册到eureka. demo源码见: https://github.com/Ryan-Miao/spring- ...

  2. SpringCloud学习6-如何创建一个服务消费者consumer

    上一节如何创建一个服务提供者provider已经启动了一个provider的server,提供用户信息查询接口.接下来,我们启动另一个provider,由于是同一台机器本地测试,我们换一个端口 --s ...

  3. 微服务配置内容《网上copy》=========》如何创建一个高可用的服务注册中心

    前言:首先要知道什么是一个高可用的服务注册中心,基于spring boot建成的服务注册中心是一个单节点的服务注册中心,这样一旦发生了故障,那么整个服务就会瘫痪,所以我们需要一个高可用的服务注册中心, ...

  4. 【Android Developers Training】 94. 创建一个空内容提供器(Content Provider)

    注:本文翻译自Google官方的Android Developers Training文档,译者技术一般,由于喜爱安卓而产生了翻译的念头,纯属个人兴趣爱好. 原文链接:http://developer ...

  5. laravel5.5源码笔记(二、服务提供者provider)

    laravel里所谓的provider服务提供者,其实是对某一类功能进行整合,与做一些使用前的初始化引导工作.laravel里的服务提供者也分为,系统核心服务提供者.与一般系统服务提供者.例如上一篇博 ...

  6. 简单创建一个SpringCloud2021.0.3项目(三)

    目录 1. 项目说明 1. 版本 2. 用到组件 3. 功能 2. 上俩篇教程 3. Gateway集成sentinel,网关层做熔断降级 1. 超时熔断降级 2. 异常熔断 3. 集成sentine ...

  7. .Net开发笔记(十九) 创建一个可以可视化设计的对象

    阅读本篇博客之前需要了解VS窗体设计器的工作原理,详细可参见本系列博客(十).(十一).(十二).必须需要知道的一条结论就是:处于窗体设计器(Form Designer)中的任何组件(包含控件,下同) ...

  8. 无废话Android之listview入门,自定义的数据适配器、采用layoutInflater打气筒创建一个view对象、常用数据适配器ArrayAdapter、SimpleAdapter、使用ContentProvider(内容提供者)共享数据、短信的备份、插入一条记录到系统短信应用(3)

    1.listview入门,自定义的数据适配器 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/and ...

  9. 【转】怎样创建一个Xcode插件(Part 2)

    原文:How To Create an Xcode Plugin: Part 2/3 原作者:Derek Selander 译者:@yohunl 译者注:原文使用的是xcode6.3.2,我翻译的时候 ...

随机推荐

  1. vector 内存释放相关

    在使用vector 存储char 类型时 new的数据 在vecto 执行rerase的时候或者 单项执行clear 内存是不能被释放的. 比如有下面的一个测试: class SnapshotInfo ...

  2. C#与.NET概述

    .NET Framework是一个支持生成和运行下一代应用程序和web服务的集成在Windows中的组件. 关键组建为CLR和FCL. 为其运行的应用程序提供各种服务的托管执行环境,简化的开发和部署以 ...

  3. C++指针理解

    指针是C/C++编程中的重要概念之一,也是最容易产生困惑并导致程序出错的问题之一.利用指针编程可以表示各种数据结构,通过指针可使用主调函数和被调函数之间共享变量或数据结构,便于实现双向数据通讯:指针能 ...

  4. ReactiveX 学习笔记(6)条件操作符

    Conditional and Boolean Operators 本文的主题为处理 Observable 的条件和布尔操作符. 这里的 Observable 实质上是可观察的数据流. RxJava操 ...

  5. python模块sys

    #!/bin/env python #-*- encoding=utf8 -*- import sys if __name__=="__main__": # 在解释器启动后, ar ...

  6. 将IP地址字符串转为32位二进制

    def str2bin(s): temp = s.split('.') result = '' for i in range(len(temp)): temp[i] = str(bin(int(tem ...

  7. 循环取到json中的字段数据,加到html中

    $.ajax({ type:'post', data:{specialName:specialName,count:count}, url:"admin/pcAdminGetArticleL ...

  8. idea git 把本地项目上传到github上

    创建一个项目,在项目文件夹下执行以下命令 第二种方法: 先在idea上创建一个项目 注意以上只是在本地建立了本地仓库,代码都放在本地仓库. 现在上传到github上 到此才上传成功

  9. C# CefSharp MemoryStreamResponseFilter这个类使用过程中遇到的bug,dataIn.CopyTo(dataOut)异常

    使用这个类,可以获取请求的所有数据,可用来下载网站的图片.js等 cef给出的源码 dataIn.CopyTo(dataOut);这句代码,有时候会有问题.问题是这个:dataIn.length 会大 ...

  10. C# 中文判断

    原地址忘了,也是博客园的 /// <summary> /// 是否是 中文 /// </summary> /// <param name="CString&qu ...