记录一下SpringCloudAlibaba搭建过程,避免经常忘记!因为懒,记录下来以后自己抄自己 为了此结构长期可扩展性这里就集成nacos+gateway的基本结构就算完工,其余组件用的时候再说吧~nacos可以动态配置,负载均衡!gateway可以路由,过滤,拦截,限流,降级,溶断等各种功能,其实也不算半成品了。很多公司就是这么用的,如果集成一大堆组件,反而把人弄得晕呼呼的!
我这里直接使用docker部署了一个nacos-server!当然也可以直接clone项目直接启动nacos,或者直接把代码集成到自己项目,想怎么玩都行
关于nacos在docker下的部署请看:docker安装nacos并配置mysql数据库(docker系列六)
创建一个maven项目作为父工程
大概就是下图的样子,删除src目录(因为父工程不需要启动,只是作为maven全局版本控制器使用)
父工程pom文件配置如下
注释都写在pom文件里面了,自己看吧
<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.0modelVersion>
<packaging>pompackaging>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.9.RELEASEversion>
<relativePath/>
parent>
<groupId>com.zbdemogroupId>
<artifactId>spring-cloud-alibaba-demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>${project.artifactId}name>
<description>这是一个简单的项目描述description>
<url>http://www.zbdemo.comurl>
<properties>
<java.version>1.8java.version>
<spring-cloud.version>Greenwich.SR6spring-cloud.version>
<lombok.version>1.18.22lombok.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-dependenciesartifactId>
<version>${spring-cloud.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-alibaba-dependenciesartifactId>
<version>0.9.0.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
<modules>
<module>commonsmodule>
<module>usermodule>
<module>gatewaymodule>
modules>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
plugin>
plugins>
build>
project>
创建一个maven新的
在父工程右键->new->modul创建一个子maven工程,命名为commons(意为公共工程)
**
**
commons工程pom配置如下
注释都写在pom文件里面了,自己看吧?
<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-demoartifactId>
<groupId>com.zbdemogroupId>
<version>0.0.1-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>commonsartifactId>
<name>${project.artifactId}name>
<url>http://www.zbdemo.comurl>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>${lombok.version}version>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>swagger-bootstrap-uiartifactId>
<version>1.9.5version>
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等依赖
<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-demoartifactId>
<groupId>com.zbdemogroupId>
<version>0.0.1-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>userartifactId>
<name>${project.artifactId}name>
<url>http://www.zbdemo.comurl>
<dependencies>
<dependency>
<groupId>com.zbdemogroupId>
<artifactId>commonsartifactId>
<version>0.0.1-SNAPSHOTversion>
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文件
<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-demoartifactId>
<groupId>com.zbdemogroupId>
<version>0.0.1-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>gatewayartifactId>
<name>gatewayname>
<url>http://www.zbdemo.comurl>
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
<dependency>
<groupId>io.springfoxgroupId>
<artifactId>springfox-swagger2artifactId>
<version>2.9.2version>
dependency>
<dependency>
<groupId>com.github.xiaoymingroupId>
<artifactId>swagger-bootstrap-uiartifactId>
<version>1.9.5version>
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)));
}
}
重启gateway测试接口聚合效果
访问:http://localhost:8000/doc.html
可以看到已经成功检索到user服务接口内容,后续添加其他服务也会检索进gateway的swagger文档
其他内容后续可能会另起一篇作为增量,目前这篇就到此为止,太多太杂容易让人迷失
演示代码拉取地址:我知道你想要