赞
踩
微服务:
1.是系统架构上的一种设计风格,他的主旨是将一个原本独立系统拆分成多个小型服务,这些小型服务都在各自独立的进程中运行,服务之间一般通过HTTP的restfulAPI进行通信协作。
2.被拆分成的每一个小型服务都围绕着系统中的某一项或些耦合度较高的业务功能进行构建,并且每个服务都维护着自身的数据存储、业务开发自动化测试案例以及独立部署机制。
3.由于有了轻量级的通信协作基础,所以这些微服务可以使用不同的语言来编写
1.Spring Cloud 是一系列框架的有序集合。
2. Spring Cloud 并没有重复制造轮子,它只是将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来。
3.通过 Spring Boot 风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包。
4.它利用Spring Boot的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、 断路器、数据监控等,都可以用Spring Boot的开发风格做到一键启动和部署。
5.Spring Cloud项目官方网址:https://spring.io/projects/spring-cloud
6.Spring Cloud 版本命名方式采用了伦敦地铁站的名称,同时根据字母表的顺序来对应版本时间顺序,比如:最早的Release版本:Angel,第二个Release版本:Brixton,然后是Camden、Dalston、Edgware,Finchley,Greenwich,Hoxton
1.微服务就是将项目的各个模块拆分为可独立运行,部署,测试的架构设计风格。
2.Spring 公司将其他公司中微服务架构常用的组件整合起来,并使用Spring Boot简化其开发,配置,成为spring cloud.
3.Spring Cloud 与Dubbo都是实现微服务的有限的工具。Dubbo性能更好,而Spring Cloud 动能更全面。
Nacos(Dynamic Naming and Configuration Service) 是阿里巴巴2018年7月开源的项目。
• 它专注于服务发现和配置管理领域 致力于帮助您发现、配置和管理微服务。Nacos 支持几乎所有主流类型的“服
务”的发现、配置和管理。
• 一句话概括就是Nacos = Spring Cloud注册中心 + Spring Cloud配置中心。
• 官网:https://nacos.io/
• 下载地址: https://github.com/alibaba/nacos/releases
启动
启动成功效果:
控制台登录
账号,密码:nacos
控制台页面
Nacos 快速入门
nacos-provider pom.xml
<dependencies> <!--nacos--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>0.2.2.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>1.1.0</version> </dependency> <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> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
application.yml
server:
port: 8000
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址
config:
server-addr: 127.0.0.1:8848
application:
name: nacos-provider # 服务名称
nacos consumer pom.xml
<dependencies> <!--nacos--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId> <version>0.2.2.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>1.1.0</version> </dependency> <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> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> </dependencies>
application.yml
server:
port: 9000
spring:
cloud:
nacos:
discovery:
server-addr: 127.0.0.1:8848 # 配置nacos 服务端地址
config:
server-addr: 127.0.0.1:8848
application:
name: nacos-consumer # 服务名称
控制台显示
详情页面
• Feign 是一个声明式的 REST 客户端,它用了基于接口的注解方式,很方便实现客户端配置。
• Feign 最初由 Netflix 公司提供,但不支持SpringMVC注解,后由 SpringCloud 对其封装,支持了SpringMVC注
解,让使用者更易于接受
Feign: 对Ribbon进行了封装,内置了负载均衡,并且封 装了RestTemplate的远程调用。
1.在消费端引入 open-feign 依赖
<!--feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置
server: port: 9000 eureka: instance: hostname: localhost # 主机名 client: service-url: defaultZone: http://localhost:8761/eureka spring: application: name: feign-consumer # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径 #设置Ribbon 的超时时间 ribbon: ConnectTomeout: 1000 #连接超时默认1秒 ReadTimeout: 3000 #逻辑处理超时时间 ,,等待服务处理结果时间 #设置当前的日志级别 logging: level: com.test: debug
2.编写Feign调用接口
package com.test.consumer.feign; import com.test.consumer.config.FeignLogConfig; import com.test.consumer.domain.Goods; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; /** * * feign声明式接口。发起远程调用的。 * String url = "http://FEIGN-PROVIDER/goods/findOne/"+id; Goods goods = restTemplate.getForObject(url, Goods.class); * * 1. 定义接口 * 2. 接口上添加注解 @FeignClient,设置value属性为 服务提供者的 应用名称 * 3. 编写调用接口,接口的声明规则 和 提供方接口保持一致。 * 4. 注入该接口对象,调用接口方法完成远程调用 */ @FeignClient(value = "FEIGN-PROVIDER") public interface GoodsFeignClient { @GetMapping("/goods/findOne/{id}") public Goods findGoodsById(@PathVariable("id") int id); }
OrderController
package com.test.consumer.controller; import com.test.consumer.domain.Goods; import com.test.consumer.feign.GoodsFeignClient; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; @RestController @RequestMapping("/order") public class OrderController { @Autowired private RestTemplate restTemplate; @Autowired private GoodsFeignClient goodsFeignClient; @GetMapping("/goods/{id}") public Goods findGoodsById(@PathVariable("id") int id){ /* String url = "http://FEIGN-PROVIDER/goods/findOne/"+id; // 3. 调用方法 Goods goods = restTemplate.getForObject(url, Goods.class); return goods;*/ Goods goods = goodsFeignClient.findGoodsById(id); return goods; } }
服务提供方
配置:
server:
port: 8001
eureka:
instance:
hostname: localhost # 主机名
prefer-ip-address: true # 将当前实例的ip注册到eureka server 中。默认是false 注册主机名
ip-address: 127.0.0.1 # 设置当前实例的ip
instance-id: ${eureka.instance.ip-address}:${spring.application.name}:${server.port} # 设置web控制台显示的 实例id
client:
service-url:
defaultZone: http://localhost:8761/eureka
spring:
application:
name: feign-provider # 设置当前应用的名称。将来会在eureka中Application显示。将来需要使用该名称来获取路径
package com.test.provider.controller; import com.test.provider.domain.Goods; import com.tesr.provider.service.GoodsService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * Goods Controller 服务提供方 */ @RestController @RequestMapping("/goods") public class GoodsController { @Autowired private GoodsService goodsService; @GetMapping("/findOne/{id}") public Goods findOne(@PathVariable("id") int id){ Goods goods = goodsService.findOne(id); return goods; } }
3.在启动类 添加 @EnableFeignClients 注解,开启Feign功能
package com.test.consumer; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.discovery.EnableDiscoveryClient; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableDiscoveryClient // 激活DiscoveryClient @EnableEurekaClient @SpringBootApplication @EnableFeignClients //开启Feign的功能 public class ConsumerApp { public static void main(String[] args) { SpringApplication.run(ConsumerApp.class,args); } }
小结:
1,feign: 定义一个feignClient接口:
@FeignClient: 声明要调用的服务
接口定义的方法:是不需要开发者实现的,而由feign自动产生一个代理实现类:这个实现类将我们手动调用restTemplate来访问远程服务的代码和URL的拼接进行了实现。
2,使用时:注入定义的接口即可
• Feign 底层依赖于 Ribbon 实现负载均衡和远程调用。
• Ribbon默认1秒超时。
• 超时配置:
feign-consumer application.yml
# 设置Ribbon的超时时间
ribbon:
ConnectTimeout: 1000 # 连接超时时间 默认1s 默认单位毫秒
ReadTimeout: 3000 # 逻辑处理的超时时间 默认1s 默认单位毫秒 等待服务处理结果的时间
• Feign 只能记录 debug 级别的日志信息。
feign-consumer application.yml
# 设置当前的日志级别 debug,feign只支持记录debug级别的日志
logging:
level:
com.test: debug
• 定义Feign日志级别Bean
FeignLogConfig
package com.test.consumer.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignLogConfig { /* NONE,不记录 BASIC,记录基本的请求行,响应状态码数据 HEADERS,记录基本的请求行,响应状态码数据,记录响应头信息 FULL;记录完成的请求 响应数据 */ @Bean public Logger.Level level(){ return Logger.Level.FULL; } }
• 启用该Bean:
package com.test.consumer.feign; import com.test.consumer.config.FeignLogConfig; import com.test.consumer.domain.Goods; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; /** * * feign声明式接口。发起远程调用的。 * String url = "http://FEIGN-PROVIDER/goods/findOne/"+id; Goods goods = restTemplate.getForObject(url, Goods.class); * * 1. 定义接口 * 2. 接口上添加注解 @FeignClient,设置value属性为 服务提供者的 应用名称 * 3. 编写调用接口,接口的声明规则 和 提供方接口保持一致。 * 4. 注入该接口对象,调用接口方法完成远程调用 */ @FeignClient(value = "FEIGN-PROVIDER", configuration = FeignLogConfig.class) public interface GoodsFeignClient { @GetMapping("/goods/findOne/{id}") public Goods findGoodsById(@PathVariable("id") int id); }
小结:
1,在调用方(消费方):导入依赖 spring-cloud-starter-openfeign
2, 在引导类上:开启注解@EnableFeignClients
3, 定义一个接口:声明所要调用的方法
加注解:@FeignClient(value=服务名,configuration=配置类)
4, 远程调用时:直接注入声明的接口即可使用。spring-cloud就会将产生的代理实现类自动注入。
• Hystix 是 Netflix 开源的一个延迟和容错库,用于隔离访问远程服务、第三方库,防止出现级联失败(雪崩)。
• 雪崩:一个服务失败,导致整条链路的服务都失败的情形
Hystix 主要功能
• 隔离
线程池隔离
信号量隔离
• 降级:异常,超时
• 熔断
• 限流
Hystix 降级:当服务发生异常或调用超时,返回默认数据
服务提供方降级
1.在服务提供方,引入 hystrix 依赖
<!-- hystrix -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
2.定义降级方法
/**
* 定义降级方法:
* 1. 方法的返回值需要和原方法一样
* 2. 方法的参数需要和原方法一样
*/
public Goods findOne_fallback(int id){
Goods goods = new Goods();
goods.setTitle("降级了~~~");
return goods;
}
3.使用 @HystrixCommand 注解配置降级方法
/** * 降级: * 1. 出现异常 * 2. 服务调用超时 * * 默认1s超时 * * @HystrixCommand(fallbackMethod = "findOne_fallback") * fallbackMethod:指定降级后调用的方法名称 */ @GetMapping("/findOne/{id}") @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = { //设置Hystrix的超时时间,默认1s @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000") }) public Goods findOne(@PathVariable("id") int id){ //1.造个异常 int i = 3/0; try { //2. 休眠2秒 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } Goods goods = goodsService.findOne(id); goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上 return goods; }
4.在启动类上开启Hystrix功能:@EnableCircuitBreaker
package com.test.provider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; /** * 启动类 */ @EnableEurekaClient //该注解 在新版本中可以省略 @SpringBootApplication @EnableCircuitBreaker // 开启Hystrix功能 public class ProviderApp { public static void main(String[] args) { SpringApplication.run(ProviderApp.class,args); } }
package com.test.consumer.feign; import com.test.consumer.domain.Goods; import org.springframework.stereotype.Component; /** * Feign 客户端的降级处理类 * 1. 定义类 实现 Feign 客户端接口 * 2. 使用@Component注解将该类的Bean加入SpringIOC容器 */ @Component public class GoodsFeignClientFallback implements GoodsFeignClient { @Override public Goods findGoodsById(int id) { Goods goods = new Goods(); goods.setTitle("又被降级了~~~"); return goods; } }
3.在 @FeignClient 注解中使用 fallback 属性设置降级处理类。
GoodsFeignClient
package com.test.consumer.feign;
import com.test.consumer.domain.Goods;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
@FeignClient(value = "HYSTRIX-PROVIDER",fallback = GoodsFeignClientFallback.class)
public interface GoodsFeignClient {
@GetMapping("/goods/findOne/{id}")
public Goods findGoodsById(@PathVariable("id") int id);
}
4.配置开启 feign.hystrix.enabled = true
application.yml
# 开启feign对hystrix的支持
feign:
hystrix:
enabled: true
熔断-概念
• Hystrix 熔断机制,用于监控微服务调用情况,当失败的情况达到预定的阈值(5秒失败20次),会打开断路器,拒绝所有请求,直到服务恢复正常为止。
断路器三种状态:打开、半开、关闭、
熔断-代码演示
修改服务提供方的方法,演示熔断机制
熔断配置
• circuitBreaker.sleepWindowInMilliseconds:监控时间
• circuitBreaker.requestVolumeThreshold:失败次数
• circuitBreaker.errorThresholdPercentage:失败率
GoodsController
package com.test.provider.controller; import com.test.provider.domain.Goods; import com.test.provider.service.GoodsService; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Date; /** * Goods Controller 服务提供方 */ @RestController @RequestMapping("/goods") public class GoodsController { @Autowired private GoodsService goodsService; @Value("${server.port}") private int port; /** * 降级: * 1. 出现异常 * 2. 服务调用超时 * * 默认1s超时 * * @HystrixCommand(fallbackMethod = "findOne_fallback") * fallbackMethod:指定降级后调用的方法名称 */ @GetMapping("/findOne/{id}") @HystrixCommand(fallbackMethod = "findOne_fallback",commandProperties = { //设置Hystrix的超时时间,默认1s @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds",value = "3000"), //监控时间 默认5000 毫秒 @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds",value = "5000"), //失败次数。默认20次 @HystrixProperty(name="circuitBreaker.requestVolumeThreshold",value = "20"), //失败率 默认50% @HystrixProperty(name="circuitBreaker.errorThresholdPercentage",value = "50") }) public Goods findOne(@PathVariable("id") int id){ //如果id == 1 ,则出现异常,id != 1 则正常访问 if(id == 1){ //1.造个异常 int i = 3/0; } /*try { //2. 休眠2秒 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }*/ Goods goods = goodsService.findOne(id); goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上 return goods; } /** * 定义降级方法: * 1. 方法的返回值需要和原方法一样 * 2. 方法的参数需要和原方法一样 */ public Goods findOne_fallback(int id){ Goods goods = new Goods(); goods.setTitle("降级了~~~"); return goods; } }
• Hystrix 提供了 Hystrix-dashboard 功能,用于实时监控微服务运行状态。
• 但是Hystrix-dashboard只能监控一个微服务。
• Netflix 还提供了 Turbine ,进行聚合监控。
网关旨在为微服务架构提供一种简单而有效的统一的API路由管理方式。
在微服务架构中,不同的微服务可以有不同的网络地址,各个微服务之间通过互相调用完成用户请求,客户端可能通过调用N个微服务的接口完成一个用户请求。
存在的问题:
1**.客户端多次请求不同的微服务,增加客户端的复杂性**
2.认证复杂,每个服务都要进行认证
3.http请求不同服务次数增加,性能不高
网关就是系统的入口,封装了应用程序的内部结构,为客户端提供统一服务,一些与业务本身功能无关的公共逻辑可以在这里实现,诸如认证、鉴权、监控、缓存、负载均衡、流量管控、路由转发等
在目前的网关解决方案里,有Nginx+ Lua、Netflix Zuul 、Spring Cloud Gateway等等
网关两要功能:
1,路由
2,过滤
1.搭建网关模块
创建api-gateway-server模块
2.引入依赖:starter-gateway
<dependencies>
<!--引入gateway 网关-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<!-- eureka-client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
</dependencies>
package com.test.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApp.class,args);
}
}
4.编写配置文件
application.yml
server: port: 80 spring: application: name: api-gateway-server cloud: # 网关配置 gateway: # 路由配置:转发规则 routes: #集合。 # id: 唯一标识。默认是一个UUID # uri: 转发路径 # predicates: 条件,用于请求网关路径的匹配规则 - id: gateway-provider uri: http://localhost:8001/ predicates: - Path=/goods/**
5.启动测试
application.yml 中的uri是写死的,就是静态路由
server: port: 80 spring: application: name: api-gateway-server cloud: # 网关配置 gateway: # 路由配置:转发规则 routes: #集合。 # id: 唯一标识。默认是一个UUID # uri: 转发路径 # predicates: 条件,用于请求网关路径的匹配规则 # filters:配置局部过滤器的 - id: gateway-provider # 静态路由 uri: http://localhost:8001/ predicates: - Path=/goods/**
启动类添加@EnableEurekaClient(新版本不加也可以)
package com.test.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ApiGatewayApp {
public static void main(String[] args) {
SpringApplication.run(ApiGatewayApp.class,args);
}
}
引入eureka-client配置
application.yml 中修改uri属性:uri: lb://服务名称
server: port: 80 spring: application: name: api-gateway-server cloud: # 网关配置 gateway: # 路由配置:转发规则 routes: #集合。 # id: 唯一标识。默认是一个UUID # uri: 转发路径 # predicates: 条件,用于请求网关路径的匹配规则 # filters:配置局部过滤器的 - id: gateway-provider # 静态路由 # uri: http://localhost:8001/ # 动态路由:lb://对应服务名称(注册中心) uri: lb://GATEWAY-PROVIDER predicates: - Path=/goods/**
# 微服务名称配置
discovery:
locator:
enabled: true # 设置为true 请求路径前可以添加微服务名称
lower-case-service-id: true # 允许为小写
Gateway 支持过滤器功能,对请求或响应进行拦截,完成一些通用操作。
Gateway 提供两种过滤器方式:“pre”和“post”
pre 过滤器,在转发之前执行,可以做参数校验、权限校验、流量监控、日志输出、协议转换等。
post 过滤器,在响应之前执行,可以做响应内容、响应头的修改,日志的输出,流量监控等。
Gateway 还提供了两种类型过滤器
GatewayFilter:局部过滤器,针对单个路由
GlobalFilter :全局过滤器,针对所有路由
server: port: 80 spring: application: name: api-gateway-server cloud: # 网关配置 gateway: # 路由配置:转发规则 routes: #集合。 # id: 唯一标识。默认是一个UUID # uri: 转发路径 # predicates: 条件,用于请求网关路径的匹配规则 # filters:配置局部过滤器的 - id: gateway-provider # 静态路由 # uri: http://localhost:8001/ # 动态路由 uri: lb://GATEWAY-PROVIDER predicates: - Path=/goods/** filters: - AddRequestParameter=username,zhangsan
gateway-provider模块中GoodsController中的findOne添加username参数
public Goods findOne(@PathVariable("id") int id,String username){ System.out.println(username); //如果id == 1 ,则出现异常,id != 1 则正常访问 if(id == 1){ //1.造个异常 int i = 3/0; } /*try { //2. 休眠2秒 Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); }*/ Goods goods = goodsService.findOne(id); goods.setTitle(goods.getTitle() + ":" + port);//将端口号,设置到了 商品标题上 return goods; }
MyFilter
package com.test.gateway.filter; import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.core.Ordered; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; @Component public class MyFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { System.out.println("自定义全局过滤器执行了~~~"); return chain.filter(exchange);//放行 } /** * 过滤器排序 * @return 数值越小 越先执行 */ @Override public int getOrder() { return 0; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。