1.在今后的实验中,都采用单节点的 eureka 进行开发,所以把 bootstrap 的配置全部注释掉,重新启用 application 的配置。
2.创建 homepage-zuul 模块,完成 pom 文件配置,比较注意的一点是,上一节我们做的是 erueka server 的开发,那么接下来的所有模块都应该属于 erueka client,因此需要在 pom 文件中加入 eureka client 的依赖
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <artifactId>imooc-homepage</artifactId> <groupId>cn.chenforcode.homepage</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>homepage-zuul</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <!-- 模块信息描述 --> <name>homepage-zuul</name> <description>Spring Cloud Gateway</description> <dependencies> <!-- Eureka客户端,客户端向Eureka server注册的时候会提供一系列的元数据信息,如主机,端口,健康检查url等 Eureka Server接收每个客户端的心跳信息,如果在某个配置的超时时间内未收到心跳信息,实例会被从注册列表中移除 --> <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-zuul</artifactId> </dependency> <!-- apache工具类 --> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>1.3.2</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
3.在 src 目录下建立与 server 相类似的结构,建立包和相应的启动类 ZuulGatewayApplication
package cn.chenforcode.homepage; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.netflix.zuul.EnableZuulProxy; /** * @author <a href="http://www.chenforcode.cn">PKUCoder</a> * @date 2019/11/10 6:00 下午 * @description 服务网关的启动类 * EnableZuulProxy用来标示这个类为zuul server * SpringCloudApplication 是一个组合注解,用来简化配置,里边有额外的一些注解 */ @EnableZuulProxy @SpringCloudApplication public class ZuulGatewayApplication { public static void main(String[] args) { SpringApplication.run(ZuulGatewayApplication.class, args); } }
4.实现自定义过滤器,建立 filter 包,建立 PreRequestFliter
package cn.chenforcode.homepage.fliter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.stereotype.Component; /** * @author <a href="http://www.chenforcode.cn">PKUCoder</a> * @date 2019/11/10 6:12 下午 * @description 自定义过滤器,记录客户端发起请求的时间戳 */ @Component public class PreRequestFliter extends ZuulFilter { //定义过滤器的类型,代表过滤器在请求的什么时候进行调用,由于记录请求时间,所以在请求带来前记录时间 @Override public String filterType() { return FilterConstants.PRE_TYPE; } //定义过滤器的执行顺序,数值越小代表优先级越高 @Override public int filterOrder() { return 0; } //定义是否启用该过滤器,true代表启用,false代表不启用 @Override public boolean shouldFilter() { return false; } @Override public Object run() throws ZuulException { //获取请求上下文,用与在过滤器之间传递消息,它的本质是一个concurrentHashmap,所以存储的时候以key-value的形式存储 RequestContext ctx = RequestContext.getCurrentContext(); ctx.set("startTime", System.currentTimeMillis()); return null; } }
5.建立 AccessLogFliter
package cn.chenforcode.homepage.fliter; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import lombok.extern.slf4j.Slf4j; import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; /** * @author <a href="http://www.chenforcode.cn">PKUCoder</a> * @date 2019/11/10 6:22 下午 * @description 记录请求执行时间 */ @Component @Slf4j public class AccessLogFliter extends ZuulFilter { //在请求之后执行 @Override public String filterType() { return FilterConstants.POST_TYPE; } //这个常量是最低的,但是order设置成这个值的时候过滤器失效,所以在他之前执行,比最后一个order的优先级略高 @Override public int filterOrder() { return FilterConstants.SEND_RESPONSE_FILTER_ORDER - 1; } @Override public boolean shouldFilter() { return true; } //打印日志,记录每个请求的时间 @Override public Object run() throws ZuulException { RequestContext ctx = RequestContext.getCurrentContext(); Long startTime = (Long) ctx.get("startTime"); HttpServletRequest request = ctx.getRequest(); String uri = request.getRequestURI(); long duration = System.currentTimeMillis() - startTime; log.info("uri: {}, duration: {}", uri, duration / 100); return null; } }
在这里简述一下自己的疑问:
如果在第一个请求过来的时候,设置了一下 startTime,然后在这个请求没有执行到第二个过滤器的时候,又来了一个请求,那不就会又设置了一下 startTime 了吗?这个时候第一个请求最后算出来的时间就不准了。
所以我觉得不应该使用同一个名字记录这个 startTime。应该在记录开始时间的时候也拿到相应的 uri,然后用一个 uriStartTime 来存储他的时间,也就是把自己的时间 key 能够标识出来。
6.完成配置文件 application.yml 文件
server: port: 9000 spring: application: name: homepage-zuul eureka: client: service-url: defaultZone: http://server1:8000/eureka/
注意这里的 eureka 配置要写成 client,不再是 server 了
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于