文档章节

sbc(二)高可用Eureka+声明式服务调用

crossoverJie
 crossoverJie
发布于 2017/07/21 09:58
字数 2055
阅读 46
收藏 1
点赞 0
评论 0

pexels-photo-516961.jpeg

前言

上一篇简单入门了SpringBoot+SpringCloud 构建微服务。但只能算是一个demo级别的应用。 这次会按照实际生产要求来搭建这套服务。

Swagger应用

上次提到我们调用自己的http接口的时候采用的是PostMan来模拟请求,这个在平时调试时自然没有什么问题,但当我们需要和前端联调开发的时候效率就比较低了。

通常来说现在前后端分离的项目一般都是后端接口先行。

后端大大们先把接口定义好(入参和出参),前端大大们来确定是否满足要求,可以了之后后端才开始着手写实现,这样整体效率要高上许多。

但也会带来一个问题:在接口定义阶段频繁变更接口定义而没有一个文档或类似的东西来记录,那么双方的沟通加上前端的调试都是比较困难的。

基于这个需求网上有各种解决方案,比如阿里的rap就是一个不错的例子。

但是springCould为我们在提供了一种在开发springCloud项目下更方便的工具swagger

实际效果如下:

01.png

<!--more-->

配置swagger

sbc-order为例我将项目分为了三个模块:

├── order                                    // Order服务实现  
│   ├── src/main
├── order-api                                // 对内API
│   ├── src/main
├── order-client                             // 对外的clientAPI
│   ├── src/main
├── .gitignore                               
├── LICENSE                
├── README.md               


因为实现都写在order模块中,所以只需要在该模块中配置即可。

首先需要加入依赖,由于我在order模块中依赖了:

<dependency>
    <groupId>com.crossoverJie</groupId>
    <artifactId>order-api</artifactId>
    <version>${target.version}</version>
</dependency>

order-api又依赖了:

<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <scope>compile</scope>
</dependency>

接着需要配置一个SwaggerConfig

@Configuration
@EnableSwagger2
/** 是否打开swagger **/
@ConditionalOnExpression("'${swagger.enable}' == 'true'")
public class SwaggerConfig {
	
    
	@Bean
    public Docket createRestApi() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.crossoverJie.sbcorder.controller"))
                .paths(PathSelectors.any())
                .build();
    }
	
    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("sbc order api")
                .description("sbc order api")
                .termsOfServiceUrl("http://crossoverJie.top")
                .contact("crossoverJie")
                .version("1.0.0")
                .build();
    }
    
}

其实就是配置swagger的一些基本信息。 之后启动项目,在地址栏输入http://ip:port/swagger-ui.html#/即可进入。 可以看到如上图所示的接口列表,点击如下图所示的参数例子即可进行接口调用。

02.jpg

自定义开关Swagger

swagger的便利能给我们带来很多好处,但稍有不慎也可能出现问题。

比如如果在生产环境还能通过IP访问swagger的话那后果可是不堪设想的。 所以我们需要灵活控制swagger的开关。

这点可以利用spring的条件化配置(条件化配置可以配置存在于应用中,一旦满足一些特定的条件时就取消这些配置)来实现这一功能:

@ConditionalOnExpression("'${swagger.enable}' == 'true'")

该注解的意思是给定的SpEL表达式计算结果为true时才会创建swaggerbean

swagger.enable这个配置则是配置在application.properties中:

# 是否打开swagger
swagger.enable = true

这样当我们在生产环境时只需要将该配置改为false即可。

ps:更多spring条件化配置:

@ConditionalOnBean                 //配置了某个特定Bean
@ConditionalOnMissingBean          //没有配置特定的Bean
@ConditionalOnClass                //Classpath里有指定的类
@ConditionalOnMissingClass         //Classpath里缺少指定的类
@ConditionalOnExpression           //给定的Spring Expression Language(SpEL)表达式计算结果为true
@ConditionalOnJava                 //Java的版本匹配特定值或者一个范围值
@ConditionalOnJndi                 //参数中给定的JNDI位置必须存在一个,如果没有给参数,则要有JNDI InitialContext
@ConditionalOnProperty             //指定的配置属性要有一个明确的值
@ConditionalOnResource             //Classpath里有指定的资源
@ConditionalOnWebApplication       //这是一个Web应用程序
@ConditionalOnNotWebApplication    //这不是一个Web应用程序
(参考SpringBoot实战)

高可用Eureka

在上一篇中是用Eureka来做了服务注册中心,所有的生产者都往它注册服务,消费者又通过它来获取服务。

但是之前讲到的都是单节点,这在生产环境风险巨大,我们必须做到注册中心的高可用,搭建Eureka集群。

这里简单起见就搭建两个Eureka,思路则是这两个Eureka都把自己当成应用向对方注册,这样就可以构成一个高可用的服务注册中心。

在实际生产环节中会是每个注册中心一台服务器,为了演示起见,我就在本地启动两个注册中心,但是端口不一样。

首先需要在本地配置一个host:

127.0.0.1 node1 node2

这样不论是访问node1还是node2都可以在本机调用的到(当然不配置host也可以,只是需要通过IP来访问,这样看起来不是那么明显)。

并给sbc-service新增了两个配置文件:

application-node1.properties:

spring.application.name=sbc-service
server.port=8888
eureka.instance.hostname=node1

## 不向注册中心注册自己
#eureka.client.register-with-eureka=false
#
## 不需要检索服务
#eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://node2:9999/eureka/

application-node2.properties:

spring.application.name=sbc-service
server.port=9999
eureka.instance.hostname=node2

## 不向注册中心注册自己
#eureka.client.register-with-eureka=false
#
## 不需要检索服务
#eureka.client.fetch-registry=false
eureka.client.serviceUrl.defaultZone=http://node1:8888/eureka/

其中最重要的就是:

eureka.client.serviceUrl.defaultZone=http://node2:9999/eureka/
eureka.client.serviceUrl.defaultZone=http://node1:8888/eureka/

两个应用互相注册。

启动的时候我们按照: java -jar sbc-service-1.0.0-SNAPSHOT.jar --spring.profiles.active=node1启动,就会按照传入的node1或者是node2去读取application-node1.properties,application-node2.properties这两个配置文件(配置文件必须按照application-{name}.properties的方式命名)。

分别启动两个注册中心可以看到以下: 03.jpg


04.jpg

可以看到两个注册中心以及互相注册了。 在服务注册的时候只需要将两个地址都加上即可: eureka.client.serviceUrl.defaultZone=http://node1:8888/eureka/,http://node2:9999/eureka/

在服务调用的时候可以尝试关闭其中一个,正常情况下依然是可以调用到服务的。

Feign声明式调用

接下来谈谈服务调用,上次提到可以用ribbon来进行服务调用,但是明显很不方便,不如像之前rpc调用那样简单直接。

为此这次使用Feign来进行声明式调用,就像调用一个普通方法那样简单。

order-client

片头说到我将应用分成了三个模块order、order-api、order-client,其中的client模块就是关键。

来看看其中的内容,只有一个接口:

@RequestMapping(value="/orderService")
@FeignClient(name="sbc-order")
@RibbonClient
public interface OrderServiceClient extends OrderService{


    @ApiOperation("获取订单号")
    @RequestMapping(value = "/getOrderNo", method = RequestMethod.POST)
    BaseResponse<OrderNoResVO> getOrderNo(@RequestBody OrderNoReqVO orderNoReq) ;
}

@FeignClient这个注解要注意下,其中的name的是自己应用的应用名称,在 application.properties中的spring.application.name配置

其中继承了一个OrderServiceorder-api模块中,来看看order-api中的内容。

order-api

其中也只有一个接口:

@RestController
@Api("订单服务API")
@RequestMapping(value = "/orderService")
@Validated
public interface OrderService {

    @ApiOperation("获取订单号")
    @RequestMapping(value = "/getOrderNo", method = RequestMethod.POST)
    BaseResponse<OrderNoResVO> getOrderNo(@RequestBody OrderNoReqVO orderNoReq) ;
}

这个接口有两个目的。

  1. 给真正的controller来进行实现。
  2. client接口进行继承。

类关系如下:

05.jpg

注解这些都没什么好说的,一看就懂。

order

order则是具体接口实现的模块,就和平时写controller一样。 来看看如何使用client进行声明式调用:

这次看看sbc-user这个项目,在里边调用了sbc-order的服务。 其中的user模块依赖了order-client:

<dependency>
    <groupId>com.crossoverJie</groupId>
    <artifactId>order-client</artifactId>
</dependency>

具体调用:

    @Autowired
    private OrderServiceClient orderServiceClient ;
    
    @Override
    public BaseResponse<UserResVO> getUserByFeign(@RequestBody UserReqVO userReq) {
        //调用远程服务
        OrderNoReqVO vo = new OrderNoReqVO() ;
        vo.setReqNo(userReq.getReqNo());
        BaseResponse<OrderNoResVO> orderNo = orderServiceClient.getOrderNo(vo);

        logger.info("远程返回:"+JSON.toJSONString(orderNo));

        UserRes userRes = new UserRes() ;
        userRes.setUserId(123);
        userRes.setUserName("张三");

        userRes.setReqNo(userReq.getReqNo());
        userRes.setCode(StatusEnum.SUCCESS.getCode());
        userRes.setMessage("成功");

        return userRes ;
    }

可以看到只需要将order-client包中的Order服务注入进来即可。

sbc-clientswagger中进行调用:

06.jpg


07.jpg

由于我并没传appId所以order服务返回的错误。

总结

当一个应用需要对外暴露接口时着需要按照以上方式提供一个client包更消费者使用。

其实应用本身也是需要做高可用的,和Eureka高可用一样,再不同的服务器上再启一个或多个服务并注册到Eureka集群中即可。

后续还会继续谈到zuul网关,容错,断路器等内容,欢迎拍砖讨论。

项目:https://github.com/crossoverJie/springboot-cloud

博客:http://crossoverjie.top

weixin

© 著作权归作者所有

共有 人打赏支持
crossoverJie
粉丝 398
博文 51
码字总数 87769
作品 0
江北
后端工程师
sbc(二)高可用Eureka+声明式服务调用

前言 上一篇简单入门了SpringBoot+SpringCloud 构建微服务。但只能算是一个级别的应用。 这次会按照实际生产要求来搭建这套服务。 Swagger应用 上次提到我们调用自己的接口的时候采用的是来模...

crossoverJie
2017/07/21
0
0
sbc(二)高可用Eureka+声明式服务调用

pexels-photo-516961.jpeg 前言 上一篇简单入门了SpringBoot+SpringCloud 构建微服务。但只能算是一个级别的应用。 这次会按照实际生产要求来搭建这套服务。 Swagger应用 上次提到我们调用自...

crossoverJie
2017/07/21
0
0
sbc(六) Zuul GateWay 网关应用

前言 看过之前SBC系列的小伙伴应该都可以搭建一个高可用、分布式的微服务了。 目前的结构图应该如下所示: 各个微服务之间都不存在单点,并且都注册于 ,基于此进行服务的注册于发现,再通过 ...

crossoverJie
2017/11/28
0
0
sbc(六) Zuul GateWay 网关应用

image 前言 看过之前SBC系列的小伙伴应该都可以搭建一个高可用、分布式的微服务了。 目前的结构图应该如下所示: image 各个微服务之间都不存在单点,并且都注册于 ,基于此进行服务的注册于发...

crossoverJie
2017/11/28
0
0
网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化

网关 Spring-Cloud-Gateway 源码解析 —— 网关初始化 Harries Blog™2017-12-135 阅读 SpringAppclasspathcatbeanAPIbuildbug 本文主要基于 Spring-Cloud-Gateway 2.0.X M4 摘要: 原创出处 ......

Harries Blog™
2017/12/13
0
0
微服务系列-Spring Cloud优质项目推荐

Spring Cloud 微服务架构集大成者,云计算最佳业务实践。 image.png Spring Cloud Spring Cloud Config Spring 配置管理工具包,让你可以把配置放到远程服务器,集中化管理集群配置,目前支持...

高广超
2017/11/06
0
0
springCloud(9):使用Feign实现声明式REST调用-为消费者整合Feign与自定义Feign配置

一、简介 前面我们是使用RestTemplate实现rest api调用的,代码如下: @GetMapping("/user/{id}")public User findById(@PathVariable Long id) throws Exception { return this.restTempla......

我爱大金子
2017/07/17
0
0
Spring Cloud(服务发现Eureka)

服务发现 服务发现机制是为了解决硬网络编码问题,服务消费者使用这种机制获取服务提供者网络信息,当微服务网络地址发生变更(例如IP或端口),会重新注册到服务发现组件,而服务消费者就无...

林塬
2017/12/16
0
0
eureka实战——高可用服务治理框架

本文地址:https://www.jianshu.com/p/9aa452b1def0 代码地址:https://gitee.com/sunnymore/highavailability_eureka grpc实战文章:https://www.jianshu.com/p/87a352ff637b 之前Sunny有聊......

程序员Sunny
06/05
0
0
J360-cloud SpringCloud系列二:服务发现Discovery Service

j360开源博客之 ---------------------------------------------------------- J360-Cloud系列 spring-cloud快速入门工程之j360-cloud-all:(欢迎star、fork) https://github.com/xuminwl......

Hi徐敏
2015/10/10
2K
3

没有更多内容

加载失败,请刷新页面

加载更多

下一页

java集合元素的默认大小

当底层实现涉及到扩容时,容器或重新分配一段更大的连续内存(如果是离散分配则不需要重新分配,离散分配都是插入新元素时动态分配内存),要将容器原来的数据全部复制到新的内存上,这无疑使...

竹叶青出于蓝
3分钟前
0
0
Java快速开发平台,JEECG 3.7.7闪电版本发布,增加多套主流UI代码生成器模板

JEECG 3.7.7 闪电版本发布,提供5套主流UI代码生成器模板 导读 ⊙平台性能优化,速度闪电般提升 ⊙提供5套新的主流UI代码生成器模板(Bootstrap表单+BootstrapTable列表\ ElementUI列表表单)...

Jeecg
6分钟前
0
0
export 和 module.export 的区别

在浏览器端 js 里面,为了解决各模块变量冲突等问题,往往借助于 js 的闭包把左右模块相关的代码都包装在一个匿名函数里。而 Nodejs 编写模块相当的自由,开发者只需要关注 require,exports,...

孟飞阳
9分钟前
0
0
技术教育的兴起

技术教育的兴起 作者: 阮一峰 1、 有一年,我在台湾环岛旅行。 花莲的海边,我遇到一对台湾青年夫妻,带着女儿在海滩上玩。我们聊了起来。 当时,我还在高校当老师。他们问我,是否觉得台湾...

吕伯文
9分钟前
0
0
Linux服务器下的HTTP抓包分析

说到抓包分析,最简单的办法莫过于在客户端直接安装一个Wireshark或者Fiddler了,但是有时候由于客户端开发人员(可能是第三方)知识欠缺或者其它一些原因,无法顺利的在客户端进行抓包分析,...

mylxsw
13分钟前
0
0
mybatis3-javaapi

sqlSessionFactoryBuilder->sqlSessionFactory->sqlSession<-rowbound<-resultHandler myBatis uses a Java enumeration wrapper for transaction isolation levels, called TransactionIsol......

writeademo
17分钟前
0
0
Java NIO:浅析I/O模型

也许很多朋友在学习NIO的时候都会感觉有点吃力,对里面的很多概念都感觉不是那么明朗。在进入Java NIO编程之前,我们今天先来讨论一些比较基础的知识:I/O模型。下面本文先从同步和异步的概念...

yzbty23
17分钟前
0
0
了解iOS消息推送一文就够:史上最全iOS Push技术详解

本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表。 1、引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ、微信等IM界面处于前台时,聊天消息和指令都会...

JackJiang-
19分钟前
0
0
Mysql汉子转拼音

update t_app_city SET CITY_NAME_BEGIN = ELT(INTERVAL(CONV(HEX(LEFT(CONVERT(CITY_NAME USING gbk),1)),16,10), 0xB0A1,0xB0C5,0xB2C1,0xB4EE,0xB6EA,0xB7A2,0xB8C1,0xB9FE,0xBBF7, 0xBFA......

尘叙缘
21分钟前
0
0
大数据构建智慧城市“新引擎”,加速推进新旧动能转换

——“大数据与智慧城市”技术交流分享会——济南站召开 7月13日,“大数据携手智慧城市,助力山东新旧动能转换”技术交流分享会——济南站在山东信息通信技术研究院会议室成功举办,此次会议...

左手的倒影
22分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部