赞
踩
记录一下SpringCloudAlibaba搭建过程,避免经常忘记!因为懒,记录下来以后自己抄自己 为了此结构长期可扩展性这里就集成nacos+gateway的基本结构就算完工,其余组件用的时候再说吧~nacos可以动态配置,负载均衡!gateway可以路由,过滤,拦截,限流,降级,溶断等各种功能,其实也不算半成品了。很多公司就是这么用的,如果集成一大堆组件,反而把人弄得晕呼呼的!
我这里直接使用docker部署了一个nacos-server!当然也可以直接clone项目直接启动nacos,或者直接把代码集成到自己项目,想怎么玩都行
关于nacos在docker下的部署请看:docker安装nacos并配置mysql数据库(docker系列六)
创建一个maven项目作为父工程
大概就是下图的样子,删除src目录(因为父工程不需要启动,只是作为maven全局版本控制器使用)

父工程pom文件配置如下
注释都写在pom文件里面了,自己看吧
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- 描述此pom打包方式为父类型,如果不配置默认jar(所以其他子工程不需要设置,默认即可),如果需要外部部署子工程可设置war--> <packaging>pom</packaging> <!-- 全局Springboot版本(包括test,web,starter等)与SpringCloud Greenwich兼容(SpringCloud版本在2020.0.X之前使用姓名作为版本,从A,B,C这样的顺序排列),Greenwich版本以上集成gateway有问题,目前没解决,所有退回来了哈哈 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> <relativePath/> </parent> <!-- maven坐标配置及此项目版本号 --> <groupId>com.zbdemo</groupId> <artifactId>spring-cloud-alibaba-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <!-- 项目名称(使用坐标id或者自定义),描述,地址 --> <name>${project.artifactId}</name> <description>这是一个简单的项目描述</description> <url>http://www.zbdemo.com</url> <!-- 引入jar包版本控制 --> <properties> <java.version>1.8</java.version> <!-- 与Springboot2.1.x兼容(这个版本以上集成gateway有问题,目前没解决,所有退回来了哈哈) --> <spring-cloud.version>Greenwich.SR6</spring-cloud.version> <lombok.version>1.18.22</lombok.version> </properties> <dependencyManagement> <dependencies> <!--SpringCloud版本全局控制(即使使用SpringCloudAlibaba也要加这个)--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> <!--SpringCloudAlibaba版本全局控制--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-alibaba-dependencies</artifactId> <version>0.9.0.RELEASE</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <!-- 受管理的子依赖(下面三个是后续要增加的子项目) --> <modules> <module>commons</module> <module>user</module> <module>gateway</module> </modules> <!-- 描述打包方式 必须加在父工程而不是commons,否则其他工程引用不到,当然你也可以每个需要打包的项目都引一次--> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
创建一个maven新的
在父工程右键->new->modul创建一个子maven工程,命名为commons(意为公共工程)

**
**

commons工程pom配置如下
注释都写在pom文件里面了,自己看吧?
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring-cloud-alibaba-demo</artifactId> <groupId>com.zbdemo</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>commons</artifactId> <name>${project.artifactId}</name> <url>http://www.zbdemo.com</url> <!-- 在公用项目引入依赖,在父工程全局控制版本 --> <dependencies> <!-- springboot版本父工程已控制不用写版本号 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- SpringCloudAlibaba版本父工程已控制不用写版本号 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- lombook 插件(为了演示父工程与公共子工程之间的版本控制关系,引入一个lombok作为示例)--> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>${lombok.version}</version> </dependency> <!-- swagger2依赖(为了演示公共工程如何做公共配置引入swagger2做演示) --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <!-- 使用bootstrap-ui --> <!-- <dependency>--> <!-- <groupId>io.springfox</groupId>--> <!-- <artifactId>springfox-swagger-ui</artifactId>--> <!-- <version>2.9.2</version>--> <!-- </dependency>--> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.5</version> </dependency> </dependencies> </project>
修改commons工程的pom文件后继续配置公共的swagger2

Swagger2Config文件内容如下:
import io.swagger.annotations.Api; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 public class Swagger2Config { /** * 通过 createRestApi函数来构建一个DocketBean * 函数名,可以随意命名,喜欢什么命名就什么命名 */ @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo())//调用apiInfo方法,创建一个ApiInfo实例,里面是展示在文档页面信息内容 .select() //控制暴露出去的路径下的实例 //如果某个接口不想暴露,可以使用以下注解 //@ApiIgnore 这样,该接口就不会暴露在 swagger2 的页面下 // .apis(RequestHandlerSelectors.basePackage("com.zbdemo")) // 这里不配置具体路径,扫描所有带有swagger注解的controller .apis(RequestHandlerSelectors.withClassAnnotation(Api.class)) .paths(PathSelectors.any()) .build(); } //构建 api文档的详细信息函数 private ApiInfo apiInfo() { return new ApiInfoBuilder() //页面标题 .title(" Swagger2 构建RESTful API") //条款地址 .termsOfServiceUrl("http://www.zbdemo.com") .version("1.0") //描述 .description("spring-cloud-alibaba-demo") .build(); } }
按照commons工程创建的方式再创建一个user子工程作为普通的client服务测试一下效果
创建完成后结构修改成如下:

user工程pom配置如下
注释都写在pom文件里面了,自己看吧?
user工程依赖commons之后就会继承commons的依赖:如lombook,swagger2,springboot,springcloud等依赖
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring-cloud-alibaba-demo</artifactId> <groupId>com.zbdemo</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>user</artifactId> <name>${project.artifactId}</name> <url>http://www.zbdemo.com</url> <dependencies> <!--依赖commons--> <dependency> <groupId>com.zbdemo</groupId> <artifactId>commons</artifactId> <version>0.0.1-SNAPSHOT</version> </dependency> </dependencies> </project>
接下来创建一个resources文件夹,在里面创建yml配置文件

application.yml配置文件内容如下:
# 指定user工程端口号
server:
port: 8001
# 配置挂载的子配置文件,比如我这里创建两,一个是dev开发使用,一个是pro生产环境使用
spring:
profiles:
active: dev
application-dev.yml配置文件内容如下:
Spring:
cloud:
nacos:
discovery:
# 指定你的nacos服务注册中心地址和端口,更多配置自行查询文档
server-addr: 192.168.101.1:8848
# 指定服务名称
application:
name: user
关于配置文件可以把其他配置内容放在nacos,然后通过这里引入配置,为了演示方便我就不做了
UserApplication启动类如下:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import springfox.documentation.swagger2.annotations.EnableSwagger2; // SpringBoot启动类注解 @SpringBootApplication // SpringCloud客户端注解 @EnableDiscoveryClient // 这个注解开启swagger2,swagger2配置已在commons工程做好,这里直接开启就行 @EnableSwagger2 public class UserApplication { public static void main(String[] args) { SpringApplication.run(UserApplication.class, args); } }
接下来在user工程写个controller测试一下效果:

UserController内容如下:
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/hello")
public class UserController {
@GetMapping(value = "/hello")
public String hello() {
return "hello word";
}
}
最后启动user工程,测试效果
启动成功效果图:

查看注册中心,user已经成功注册到nacos:

调用我们刚刚写的接口测试效果:localhost:8001/hello/hello 调用成功

然后调用swagger-ui测试集成效果:localhost:8001/doc.html 效果完美

创建过程与前面相似,这里不重复了,创建完成后结构修改如下:

修改gateway工程pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>spring-cloud-alibaba-demo</artifactId> <groupId>com.zbdemo</groupId> <version>0.0.1-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>gateway</artifactId> <name>gateway</name> <url>http://www.zbdemo.com</url> <!--这里不要引用commons模块,否则spring-boot-starter-web包和gateway中引用的spring-boot-starter-web会冲突报错--> <dependencies> <!--gateway--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-gateway</artifactId> </dependency> <!-- SpringCloudAlibaba版本父工程已控制不用写版本号 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> </dependency> <!-- swagger2依赖 (网关不写业务,但是需要聚合所有服务的接口方便查看)--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.5</version> </dependency> </dependencies> </project>
老规矩,创建resources文件夹,配置yml
application.yml配置文件内容如下:
server:
port: 8000
spring:
profiles:
active: dev
端口定为8000
application-dev.yml配置文件内容如下:
Spring: application: name: gateway cloud: nacos: discovery: server-addr: 192.168.101.1:8848 gateway: discovery: locator: enabled: true #表明gateway开启服务注册和发现的功能,并且spring cloud gateway自动根据服务发现为每一个服务创建了一个router,这个router将以服务名开头的请求路径转发到对应的服务 lower-case-service-id: true #是将请求路径上的服务名配置为小写(因为服务注册的时候,向注册中心注册时将服务名转成大写的了 routes: -id: user #自定义id,无意义但不能重复,最好跟服务名保持一致 uri: lb://user # 注册中心中的服务吗 predicates: - Path=/user/** # 转发该路径 filters: - StripPrefix=1 #必须加上StripPrefix=1,否则访问服务时会带上user # 经过gateWay网关时,需要在网关统一配置跨域请求,全部通过 globalcors: cors-configurations: '[/**]': allowed-origins: "*" allowed-headers: "*" allow-credentials: true allowed-methods: - GET - POST - DELETE - PUT - OPTION
GatewayApplication启动类如下:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
启动Gateway服务测试路由效果
成功注册到nacos

访问:localhost:8000/user/hello/hello 测试路由转发效果

在gateway项目中创建文件如下:

SwaggerProvider内容:
import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.springframework.cloud.gateway.discovery.DiscoveryClientRouteDefinitionLocator; import org.springframework.context.annotation.Primary; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import springfox.documentation.swagger.web.SwaggerResource; import springfox.documentation.swagger.web.SwaggerResourcesProvider; import java.net.HttpURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.List; @Component @Primary public class SwaggerProvider implements SwaggerResourcesProvider { /** * swagger的api json文档路径 */ public static final String API_URI = "/v2/api-docs"; /** * Eureka发现功能的方法的名字,注册的服务会加入这个前缀 */ public static final String EUREKA_SUB_PFIX = "CompositeDiscoveryClient_"; /** * 服务发现的路由处理器 */ private final DiscoveryClientRouteDefinitionLocator routeLocator; public SwaggerProvider(DiscoveryClientRouteDefinitionLocator routeLocator) { this.routeLocator = routeLocator; } @Override public List<SwaggerResource> get() { List<SwaggerResource> resources = new ArrayList<>(); List<String> routes = new ArrayList<>(); //从DiscoveryClientRouteDefinitionLocator 中取出routes,构造成swaggerResource routeLocator.getRouteDefinitions().subscribe(routeDefinition -> { resources.add(swaggerResource( //获取id(服务注册的id) routeDefinition.getId() //去除CompositeDiscoveryClient_前缀 .substring(EUREKA_SUB_PFIX.length()), //获取路由定义信息列表 routeDefinition.getPredicates() //获取路径信息PredicateDefinition{name='Path', args={pattern=/byb-provider2/**}} .get(0) .getArgs() //将pattern中的/**替换为服务swagger文档路径 .get("pattern") .replace("/**", API_URI))); }); return resources; } private SwaggerResource swaggerResource(String name, String location) { SwaggerResource swaggerResource = new SwaggerResource(); swaggerResource.setName(name); swaggerResource.setLocation(location); swaggerResource.setSwaggerVersion("2.0"); return swaggerResource; } }
SwaggerHandler内容:
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; import springfox.documentation.swagger.web.*; import java.util.Optional; @RestController @RequestMapping("/swagger-resources") public class SwaggerHandler { @Autowired(required = false) private SecurityConfiguration securityConfiguration; @Autowired(required = false) private UiConfiguration uiConfiguration; private final SwaggerResourcesProvider swaggerResources; @Autowired public SwaggerHandler(SwaggerResourcesProvider swaggerResources) { this.swaggerResources = swaggerResources; } @GetMapping("/configuration/security") public Mono<ResponseEntity<SecurityConfiguration>> securityConfiguration() { return Mono.just(new ResponseEntity<>( Optional.ofNullable(securityConfiguration).orElse(SecurityConfigurationBuilder.builder().build()), HttpStatus.OK)); } @GetMapping("/configuration/ui") public Mono<ResponseEntity<UiConfiguration>> uiConfiguration() { return Mono.just(new ResponseEntity<>( Optional.ofNullable(uiConfiguration).orElse(UiConfigurationBuilder.builder().build()), HttpStatus.OK)); } // 请使用更新后的的方法 @GetMapping("") public Mono<ResponseEntity> swaggerResources() { return Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK))); } }
2023-10-22更新:原来的的方式在刷新页面后第二次无法正常获取接口资源目录,所以这里人工保存一下资源目录
private Mono<ResponseEntity> mono;
@GetMapping("")
public Mono<ResponseEntity> swaggerResources() {
// 存储返回的资源目录,因为下一次进入资源目录获取不到
if (mono == null){
mono = Mono.just((new ResponseEntity<>(swaggerResources.get(), HttpStatus.OK)));
}
return mono;
}
重启gateway测试接口聚合效果
访问:http://localhost:8000/doc.html

可以看到已经成功检索到user服务接口内容,后续添加其他服务也会检索进gateway的swagger文档
其他内容后续可能会另起一篇作为增量,目前这篇就到此为止,太多太杂容易让人迷失
演示代码拉取地址:我知道你想要
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。