SpringCloud使用feign和zuul搭建一个简单的微服务
才学习了SpringCloud 微服务的基本组件,做个笔记记录下。
1. 项目环境
IDEA 2019 3.1、jdk1.8、mysql 8.0.16、SpringBoot 2.2.1.RELEASE、SpringCloud Hoxton.SR6
SpringCloud的版本一定要适配SpringBoot的版本,如果不清楚,可以去官网查询。
https://cloud.spring.io/spring-cloud-static/Hoxton.SR5/reference/html/
2. 需求介绍
这个微服务是一个简单的查询,通过id查询用户的信息。系统架构如图:

3. 项目结构

3. 1eureka-server:eureka注册中心,用于服务的注册和发现

3.1.1 导入依赖
创建项目后,导入依赖。只需要在pom文件中导入springcloud和eureka服务端组件即可,由于pom依赖篇幅较大,所以所有的pom依赖都放在了最后第5节。
3.1.2 application配置文件
eureka注册中心,需要配置eureka服务地址,如果有多个注册中心,则${server.port}可以书写为其他注册中心的端口,进行互相注册。
1 2 3 4 5 6 7 8 9 10 11 12
| server: port: 10086 spring: application: name: eureka-server eureka: client: service-url: defaultZone: http://localhost:${server.port}/eureka server: eviction-interval-timer-in-ms: 5000 enable-self-preservation: false
|
3.1.3 启动类
注册中心可以什么都不用书写,只需要开启注册中心服务
1 2 3 4 5 6 7 8 9
| @SpringBootApplication @EnableEurekaServer public class EurekaServerApplication {
public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); }
}
|
3.2 service-consumer:服务的消费方

3.2.1 导入依赖
这个的pom文件和注册中心的类似,也需要进行版本管理。但作为服务,需要导入eureka的客户端。因为这个微服务使用了fegin进行服务的远程调用和熔断,所以需要导入熔断组件
3.2.2 application配置文件
作为eureka服务的注册方,需要进行服务的拉取,并开启feign的熔断机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| server: port: 80 spring: application: name: service-consume eureka: client: service-url: defaultZone: http://localhost:10086/eureka fetch-registry: true registry-fetch-interval-seconds: 5 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 6000 feign: hystrix: enable: true
|
3.2.3 启动类
1 2 3 4 5 6 7 8 9 10 11
| @SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker @EnableFeignClients public class ServiceConsumerApplication {
public static void main(String[] args) { SpringApplication.run(ServiceConsumerApplication.class, args); } }
|
3.2.4 处理代码
controller:
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Controller @RequestMapping("user") public class UserController {
@Autowired UserClient userClient;
@RequestMapping("{uid}") @ResponseBody public String getUserById(@PathVariable("uid") String uid){ return userClient.getUserById(uid); } }
|
UserClient:一个接口,Feign会通过动态代理,帮我们生成实现类,@FeignClient
,声明这是一个Feign客户端。接口中的定义方法,完全采用SpringMVC的注解,Feign会根据注解帮我们生成URL,并访问获取结果改造原来的调用逻辑,调用UserClient接口。所以将Controller中的方法复制过来。
1 2 3 4 5 6 7
| @FeignClient(value = "service-provide",fallback = UserClientCallBack.class) public interface UserClient {
@RequestMapping("/user/{uid}") public String getUserById(@PathVariable("uid") String uid); }
|
UserClientCallBack:当在application配置文件中开启熔断功能时,就可以书写熔断方法了。只需要继承上面的接口即可
1 2 3 4 5 6 7 8
| @Component public class UserClientCallBack implements UserClient{
@Override public String getUserById(String uid) { return new String("请求超时,请稍后再试!"); } }
|
3.3 service-provide:服务的提供方
和传统SSM项目一样的书写方式

3.3.1 导入依赖
由于提供方需要连接数据库,所以需要mysql的驱动;还要有注册到eureka中,所以需要eureka的客户端
3.3.2 application配置文件
服务提供者与服务消费者此配置类似。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| server: port: 8081 spring: datasource: url: jdbc:mysql:///store?serverTimezone=UTC username: root password: 12345 application: name: service-provide eureka: client: service-url: defaultZone: http://localhost:10086/eureka instance: lease-renewal-interval-in-seconds: 5 lease-expiration-duration-in-seconds: 15
|
3.3.3 启动类
需要扫描pojo和mapper类,并开启服务发现
1 2 3 4 5 6 7 8 9 10
| @SpringBootApplication @MapperScan("com.hay.serviceprovide.mapper") @EnableDiscoveryClient public class ServiceProvideApplication {
public static void main(String[] args) { SpringApplication.run(ServiceProvideApplication.class, args); }
}
|
3.3.4处理代码
处理代码比较简单,就是一个查询根据id查询用户的请求。service和mapper代码和平时书写的没有区别所以省略掉。
1 2 3 4 5 6 7 8 9 10 11 12 13
| @Controller @RequestMapping("/user") public class UserController {
@Autowired UserService userService;
@RequestMapping("{uid}") @ResponseBody public User getUserById(@PathVariable("uid") String uid) { return userService.getUserById(uid); } }
|
3.4 zuul-server:zuul网关,用于请求的路由和过滤

3.4.1 依赖文件
需要注册到eureka中,并导入zuul组件依赖
3.4.2 application配置文件
需要将服务路径注册到zuul网关,以便zuul进行路由和过滤。
其中配置服务请求路径方法有3种。分别是:
3.4.3 启动类
以为zuul也是一个服务,所以需要注册到eureka中
1 2 3 4 5 6 7 8 9 10
| @SpringBootApplication @EnableZuulProxy @EnableDiscoveryClient public class ZuulApplication {
public static void main(String[] args) { SpringApplication.run(ZuulApplication.class, args); }
}
|
3.4.4 处理代码
Zuul作为网关的其中一个重要功能,就是实现请求的鉴权。而这个动作我们往往是通过Zuul提供的过滤器来实现的。
ZuulFilter:是过滤器的顶级父类。在这里我们看一下其中定义的4个最重要的方法:
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
| @Component public class UserFilter extends ZuulFilter {
@Override public String filterType() { return "pre"; }
@Override public int filterOrder() { return 10; } @Override public boolean shouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContext context = RequestContext.getCurrentContext(); HttpServletRequest request = context.getRequest(); String token = request.getParameter("token"); if (StringUtils.isBlank(token)){ context.setSendZuulResponse(false); context.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); context.setResponseBody("request error 401!"); } return null; } }
|
shouldFilter
:返回一个Boolean
值,判断该过滤器是否需要执行。返回true执行,返回false不执行。
run
:过滤器的具体业务逻辑。
filterType
:返回字符串,代表过滤器的类型。包含以下4种:
pre
:请求在被路由之前执行
route
:在路由请求时调用
post
:在route和errror过滤器之后调用
error
:处理请求时发生错误调用
filterOrder
:通过返回的int值来定义过滤器的执行顺序,数字越小优先级越高。
4. 测试
运行4个项目

启动成功后,在浏览器中输入:http://localhost:10001/api/consume/user/1
解释:(localhost:zuul端口/zuul设置的前缀/zuul中配置的服务名映射的路径/请求的路径/参数)
访问会失败,因为zuul的过滤器将此请求过滤了,请求参数种没有token参数,所以打印了zuul中ZuulFilter类里面run方法返回的字符串。

所以,加上token参数

查询成功了!!!!
同时也不仅仅可以通过服务消费者进行访问,也可以直接访问服务提供者,如输入http://localhost:10001/api/provide/user/1?token=1

也访问成功了!
我们以访问10086端口,查看eureka注册中心注册了哪些微服务

完成!!!!!
5. 各项目的pom依赖
5.1 eureka-server
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 57 58 59 60 61
| <?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> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.2.1.RELEASE</version> <relativePath/> </parent> <groupId>com.hay.eureka</groupId> <artifactId>eureka-server</artifactId> <version>0.0.1-SNAPSHOT</version> <name>eureka-server</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
|
5.2 service-consume
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
| <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
|
5.3 service-provide
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
| <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency>
<dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
<dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
|
5.4 zuul-server
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
| <properties> <java.version>1.8</java.version> <spring-cloud.version>Hoxton.SR6</spring-cloud.version> </properties>
<dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> <exclusions> <exclusion> <groupId>org.junit.vintage</groupId> <artifactId>junit-vintage-engine</artifactId> </exclusion> </exclusions> </dependency> </dependencies>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
|