在上一篇服务注册中心的搭建中,为了提升项目的友好性,可以另加一个eureka监听器用于感知哪些服务注册了或是挂掉了,对于挂掉了的服务可选择由程序自动进行通知等等。在实际的环境中,这样处理是大有裨益的,具体的做法会在补充篇中涉及到,而对于学习而言并不必须。中心建立了,各个服务就能直接注册到中心,但是如何去访问这些服务呢?直接去单独访问各微服务的端口以获取其内容自然是可以的,但若是这样,那么微服务框架将毫无意义,而且也无法保障安全性。所以,我们需要一个门,通过门的验证后才能访问相应的服务,对于有问题的访问门便会把它阻挡在外,即网关。
如何去搭建一个网关服务呢,与任何一个springboot项目一样,“三步走”,添加项目所用到的依赖包,配置文件的配置,类文件的编码。与注册中心微服务一样,在父(顶级)项目名上右键新建一个Module,然后新建一个空的Maven项目,命名zuul-service,得到的便是一个空有结构的maven子项目。随后便进行“三步走”操作:
1、pom.xml文件配置
打开zuul-service项目的pom.xml文件,添加依赖项如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-eurekaartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-zuulartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
dependencies>
第一个依赖包声明其为一个微服务,与所有的非注册中心的依赖包一致,注册中心的多一段 -server ,很容易辨识。第二个带有zuul所代表的依赖包声明该微服务为网关微服务,第三个依赖包声明该服务可被发现。这三个是基本的依赖项,当然加入test依赖,web依赖都是不影响的。
2、配置文件的配置
由于建立的空maven项目只有结构,没有相应的内容,因此我们需要在resources下自己新建配置文件application.yml,并在该文件中写入内容如下:
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8000/eureka/
server:
port: 8001
spring:
application:
name: zuul-service
zuul:
prefix: /api
routes:
# api-a:
# path: /a/**
# serviceId: service-ribbon-1
api-b:
path: /b/**
serviceId: feign-service
# stripPrefix: false #不移除前缀api-b,访问路径为/api/b/test --> user-center /b/test(需要在对应函数RequestMapping前加/b)
# 默认时 /api/b/test --> user-center /test
除了常见的feign,ribbon等专用的负载均衡服务,网关服务其实也是自带负载均衡功能的,只需要将上述的serviceId改成对应的消费服务的注册名,网关便会根据该服务名顺序循环的调用该注册名下的服务。
3、后台代码
首先,由于我们建立的是一个空的maven项目,因此启动类也需要我们自己去编写。在java文件夹下新建一个包com.springcloud.zuul,在该包名下,建一个类命名ZuulBootstrap作为启动类,改造成如下内容:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class ZuulBootstrap{
public static void main(String[] args) {
SpringApplication.run(ZuulBootstrap.class, args);
}
}
三个注解的含义如字面意,分别为声明为网关,声明为服务而非注册中心,声明该类为一个springboot类的启动类。
作为一个网关服务,网关拥有的功能一般为路由功能与过滤功能,在示例中,我们只看到了在配置文件中设置的路由功能,并没有看到过滤功能。所以,为了增加其过滤功能,我们需要在包com.springcloud.zuul下新建一个包filter,一般过滤功能分为前置过滤与后置过滤,因此,在filter包下新建两个类,命名Prefilter与PostFilter以完善过滤功能。
(1) 前置过滤PreFilter
@Component
public class PreFilter extends ZuulFilter{
private Logger logger = LoggerFactory.getLogger(PreFilter.class);
public PreFilter() {
super();
}
@Override
public String filterType() {
return "pre";
}
@Override
public int filterOrder() {
return 1;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
logger.info("pre--模拟身份认证");
// TODO: 2017/12/24 身份不通过,跟oauth,jwt
RequestContext ctx = RequestContext.getCurrentContext();
ctx.put("start",System.currentTimeMillis());
return null;
}
}
前置过滤需要继承Zuulfilter过滤器,需要覆写的方法的含义如字面意,过滤类型,过滤顺序,是否过滤,过滤规则则是在run()方法在覆写,禁止非法访问,进行身份认证等都可以在这个方法在实现。@Component声明该类为一个自动加载的组件。
(2) 后置过滤PostFilter
@Component
public class PostFilter extends ZuulFilter {
Logger log = LoggerFactory.getLogger(PostFilter.class);
public PostFilter() {
super();
}
@Override
public String filterType() {
return "post";
}
@Override
public int filterOrder() {
return 0;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
log.info("post....");
RequestContext ctx = RequestContext.getCurrentContext();
long total = System.currentTimeMillis() - (long) ctx.get("start");
log.info("the request use:total=" + total + "ms");
// ctx.addZuulResponseHeader(); 增加反应的头
return null;
}
}
前置过滤是过滤进入的访问,后置过滤则是过滤返回的响应。
至此,网关服务的基本结构便搭建起来了,但是网关的内容远不止这些,随着内容的增加,笔者也会慢慢扩充网关的内容。需要看源码的东西可以移步这个系列的总览页springcloud学习之路总览查看源码。