组件介绍
- Hystix 熔断器,主要作用有失败回滚和弹性容错
- 失败回滚,当访问服务失败时(访问服务时间超时,访问的服务关闭等),返回一个比较友好的提示页面
- 弹性容错:在服务运行状况转为良好后,自动重连
- zuul 网关:主要作用有路由转发和过滤
- 路由转发:以往有几个微服务我们就需要几个端口号,这样既麻烦又不安全,使用zuul可以统一访问zuul端口号来访问这些微服务(可看下面的例子)
- 过滤功能:可以实现一系列的权限检验,限流等功能
Hystix
导入依赖
修改配置文件
此配置文件和之前的没有区别,只是修改了端口号和应用名字
server.port=8087
spring.main.allow-bean-definition-overriding=true
spring.application.name=book-consumer3
eureka.client.service-url.defaultZone=http://127.0.0.1:10086/eureka
eureka.instance.prefer-ip-address=true
eureka.instance.ip-address=127.0.0.1
USER-PRODUCER.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.RandomRule
spring.cloud.loadbalancer.retry.enabled=true
修改启动类
和之前相比,只需要添加@EnableHystrix注解即可
@SpringBootApplication
@EnableDiscoveryClient
@EnableEurekaClient
@EnableHystrix
public class Consumer3Application {
public static void main(String[] args) {
SpringApplication.run(Consumer3Application.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
service层
定义**@HystrixCommand(fallbackMethod = “queryUserByIdFallback”)**,同时实现与其同名的方法即可,注意回滚的方法的参数需要与正常的方法完全相同(返回值类型是否影响也可以尝试)
@Component
public class BookService {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "queryFallback")
public String queryUserById(int id){
return restTemplate.getForObject("http://BOOK-PRODUCER/book/"+id,String.class);
}
public String queryFallback(int id){
return "用户查询失败,执行回滚";
}
}
controller层
调用该方法就好
@RestController
public class BookController {
@Autowired
BookService bookService;
@RequestMapping("booktest/{id}")
public String booktest(@PathVariable("id") int id){
return bookService.queryUserById(id);
}
}
测试
最简单的方法,将producer服务关掉,然后访问url,我们可以得到一下的结果:
自动重连
自己还待研究,这里贴一段别人的方法
Ribbon的超时时间一定要小于Hystix的超时时间。Hystix默认是1000ms,而我们之前ribbon的重试时间也是1000ms
我们可以通过hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
来设置Hystrix超时时间。
hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=6000 # 设置hystrix的超时时间为6000ms
Zuul篇
zuul-demo1
导入依赖
修改配置文件
最重要的就是path:填写映射路径
url: 填写映射的实际路径
至于前面的"book-service"我们可以随意填写,只要保持两个一致就好
server.port=10087
spring.application.name=book-zuul
zuul.routes.book-service.path=/book-service/**
zuul.routes.book-service.url=http://127.0.0.1:8081
启动类
加上一个@EnableZuulProxy的注解即可
@EnableZuulProxy
@SpringBootApplication
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
启动
访问10087端口即可
zuul-demo2
demo1中url已经被写死,现在我们和eureka注册中心结合,让zuul去注册中心自己寻找映射
导入依赖
配置文件
我们一般会将服务名称当作默认映射名称,因此zuul默认为我们配置好了,如果你想使用其他映射名称的话,可以根据之前的自己配置
zuul.routes.user-service.path=/user-service/**
zuul.routes.user-service.service-id=user-service #服务名称
#未实验
我们可以省略上面的,zuul默认帮我们配置好
server.port=10088
spring.application.name=book-zuul
eureka.client.service-url.defaultZone=http://127.0.0.1:10086/eureka
eureka.instance.ip-address=127.0.0.1
eureka.client.registry-fetch-interval-seconds=5
zuul.prefix=/api #前缀
写启动类
@SpringBootApplication
@EnableDiscoveryClient
@EnableZuulProxy
public class ZuulTestApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulTestApplication.class, args);
}
}
启动,访问
http://localhost:10088(zuul端口号)/api(前缀)/book-producer(提供的服务名字)/book/2
权限管理
创建一个LogiFilter类,非带token不可获取资源,做拦截功能
@Component
public class LoginFilter extends ZuulFilter {
@Override
public String filterType() {
// 登录校验,肯定是在前置拦截
return "pre";
}
@Override
public int filterOrder() {
// 顺序设置为1
return 1;
}
@Override
public boolean shouldFilter() {
// 返回true,代表过滤器生效。
return true;
}
@Override
public Object run() throws ZuulException {
// 登录校验逻辑。
// 1)获取Zuul提供的请求上下文对象
RequestContext ctx = RequestContext.getCurrentContext();
// 2) 从上下文中获取request对象
HttpServletRequest req = ctx.getRequest();
// 3) 从请求中获取token
String token = req.getParameter("token");
// 4) 判断
if(token == null || "".equals(token.trim())){
// 没有token,登录校验失败,拦截
ctx.setSendZuulResponse(false);
// 返回401状态码。也可以考虑重定向到登录页。
ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
}
// 校验通过,可以考虑把用户信息放入上下文,继续向后执行
return null;
}
}
试验
不带token和带token