前面部分是在网上抄的,后面写了我自己的使用
Zuul功能:
认证
压力测试
金丝雀测试
动态路由
负载削减
安全
静态响应处理
主动/主动交换管理
我这里只实现了简单的代理功能
pom.xml
<?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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.2.RELEASE</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.lesaas</groupId>
<artifactId>rhea</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<repositories>
<repository>
<id>central</id>
<name>Central Repository</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<layout>default</layout>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.main>com.lesaas.rhea.RheaStart</project.main>
<spring-cloud-netflix.version>1.2.5.RELEASE</spring-cloud-netflix.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-velocity</artifactId>
</dependency> -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- log related -->
<dependency> <!-- exclude掉spring-boot的默认log配置 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency> <!-- 引入log4j2依赖 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency> <!-- 加上这个才能辨认到log4j2.yml文件 -->
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<!-- end of log related -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
<version>${spring-cloud-netflix.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
<version>${spring-cloud-netflix.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>${spring-cloud-netflix.version}</version>
</dependency>
<dependency>
<groupId>com.netflix.zuul</groupId>
<artifactId>zuul-core</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
<version>${spring-cloud-netflix.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>${spring-cloud-netflix.version}</version>
</dependency>
</dependencies>
<build>
<finalName>rhea</finalName> <!-- 指定package生成的文件名为rhea.jar -->
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions> <!--执行器 mvn assembly:assembly-->
<execution>
<id>make-tar</id><!--名字任意 -->
<phase>package</phase><!-- 绑定到package生命周期阶段上 -->
<goals>
<goal>single</goal><!-- 只运行一次 -->
</goals>
<configuration>
<descriptors> <!--描述文件路径-->
<descriptor>src/assembly/zip.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
配置文件application.yml
server:
port: 9090
spring:
application:
name: rhea
eureka:
instance:
preferIpAddress: true
client:
registerWithEureka: false
fetchRegistry: false
serviceUrl:
defaultZone: http://172.16.2.140:17070/eureka/
#ribbon:
# eureka:
# enabled: true
# ReadTimeout: 60000
# ConnectTimeout: 60000
# MaxAutoRetries: 1
# MaxAutoRetriesNextServer: 1
zuul:
host:
maxTotalConnections: 200 # (总连接数)默认200
maxPerRouteConnections: 50 # 路由连接数 默认 20
ignoredServices: '*'
routes:
customer-by-address:
path: /customer-by-address/**
url: http://www.baidu.com
index:
path: /index/**
url: http://www.baidu.com
index1:
path: /index1/**
url: http://www.baidu.com
review:
path: /review/**
url: http://www.baidu.com
sample-client:
ribbon:
EnablePrimeConnections: true
启动类
/**
* 启动程序
*
* @author
* @date 2016年11月27日 14:36
*/
@SpringCloudApplication
@EnableFeignClients
//@EnableHystrixDashboard
@EnableZuulProxy
@EnableEurekaClient
//@ComponentScan(basePackages="com.lesaas.paygateway", lazyInit = true)
public class RheaStart {
public static void main(String[] args) {
MonitoringHelper.initMocks();
new SpringApplicationBuilder(RheaStart.class).web(true).run(args);
}
@Bean
@ConfigurationProperties(prefix = "filter.logger")
public LoggerFilter loggerFilter() {
LoggerFilter loggerFilter = new LoggerFilter();
loggerFilter.setFilterType("pre");
return loggerFilter;
}
@Bean
@ConfigurationProperties(prefix = "filter.review")
public TestPostFilter testPostFilter(){
TestPostFilter testPostFilter = new TestPostFilter();
testPostFilter.setFilterType("error");
return testPostFilter;
}
@Bean
@ConfigurationProperties(prefix = "filter.index1")
public TestPostFilter1 testPostFilterindex1(){
TestPostFilter1 testPostFilter = new TestPostFilter1();
testPostFilter.setFilterType("post");
return testPostFilter;
}
// @Bean
// public TestPostFilter1 testPostFilter1(){
// TestPostFilter1 testPostFilter = new TestPostFilter1();
// return testPostFilter;
// }
// @Bean
// public FilterRegistrationBean contextLifecycleFilter() {
// FilterRegistrationBean filter = new FilterRegistrationBean(new ContextLifecycleFilter());
// filter.addUrlPatterns("/ccc");
// return filter;
// }
}
测试类TestPostFilter
import com.netflix.zuul.context.RequestContext;
/**
* 测试用
*
* @author
* @date 2016年11月27日 16:15
*/
public class TestPostFilter extends BaseFilter {
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
logger.info("请求成功,serviceId:{},uri:{}", ctx.get("serviceId"), ctx.get("url"));
return null;
}
}
基本类BaseFilter
package com.lesaas.rhea.base.filter;
/**
* BaseFilter.java 2016年11月27日 17:09
* <p>
* Copyright (c) 2016-2021 qilong All rights reserved.
*
* @Description
* @version 1.0
*/
import com.netflix.zuul.ZuulFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* BaseFilter
*
* @author
* @date 2016年11月27日 17:09
*/
public abstract class BaseFilter extends ZuulFilter {
Logger logger = LoggerFactory.getLogger(getClass());
private String filterType ;
private Integer filterOrder=0;
/**
* filterType:返回一个字符串代表过滤器的类型,在zuul中定义了四种不同生命周期的过滤器类型,具体如下:
* pre:可以在请求被路由之前调用
* routing:在路由请求时候被调用
* post:在routing和error过滤器之后被调用
* error:处理请求时发生错误时被调用
*
* @return
*/
@Override
public String filterType() {
return filterType;
}
/**
* 通过int值来定义过滤器的执行顺序
*
* @return
*/
@Override
public int filterOrder() {
return filterOrder != null ? filterOrder : 0;
}
/**
* shouldFilter:返回一个boolean类型来判断该过滤器是否要执行,所以通过此函数可实现过滤器的开关。
*
* @return
*/
@Override
public boolean shouldFilter() {
return true;
}
public String getFilterType() {
return filterType;
}
public void setFilterType(String filterType) {
this.filterType = filterType;
}
public Integer getFilterOrder() {
return filterOrder;
}
public void setFilterOrder(Integer filterOrder) {
this.filterOrder = filterOrder;
}
}
到此为止,springCloud zuul的基本架子是搭建完成了,然而我们在现实中,会有各种需求,比如 配置刷新,更改http请求等,在下面我介绍修改http请求
- 重新实现http接口
package com.answern.zuul.filter.base;
import com.netflix.zuul.http.ServletInputStreamWrapper;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 需求名称:
* @author:[wem] <br/>
* 创建时间:[2018/1/9 19:37] <br/>
* 版本:[v1.0] <br/>
*/
public class ParameterRequestWrapper extends HttpServletRequestWrapper {
private Map<String , String[]> params = new HashMap<String, String[]>();
private byte[] reader;
@SuppressWarnings("unchecked")
public ParameterRequestWrapper(HttpServletRequest request) {
// 将request交给父类,以便于调用对应方法的时候,将其输出,其实父亲类的实现方式和第一种new的方式类似
super(request);
//将参数表,赋予给当前的Map以便于持有request中的参数
this.params.putAll(request.getParameterMap());
}
//重载一个构造方法
public ParameterRequestWrapper(HttpServletRequest request , Map<String , Object> extendParams) {
this(request);
//这里将扩展参数写入参数表
// addAllParameters(extendObject);
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new ServletInputStreamWrapper(reader);
}
@Override
public int getContentLength() {
return reader.length;
}
@Override
public long getContentLengthLong() {
return reader.length;
}
@Override
public String getParameter(String name) {//重写getParameter,代表参数从当前类中的map获取
String[]values = params.get(name);
if(values == null || values.length == 0) {
return null;
}
return values[0];
}
@Override
public String[] getParameterValues(String name) {//同上
return params.get(name);
}
public void addAllParameters(Map<String , Object>otherParams) {//增加多个参数
for(Map.Entry<String , Object>entry : otherParams.entrySet()) {
addParameter(entry.getKey() , entry.getValue());
}
}
public void addParameter(String name , Object value) {//增加参数
if(value != null) {
if(value instanceof String[]) {
params.put(name , (String[])value);
}else if(value instanceof String) {
params.put(name , new String[] {(String)value});
}else {
params.put(name , new String[] {String.valueOf(value)});
}
}
}
public void setReader(byte[] reader){
this.reader = reader;
}
}
在上面的代码中暴露了一个setReader 方法,所以http请求的时候就可以重新set一个reader了,
ParameterRequestWrapper requestWrapper = new ParameterRequestWrapper((HttpServletRequest)request);
requestWrapper.setReader(String.getBytes());
- 修改http头的请求类型
/**
* 修改request的content-type
* @param ctx
* @param contentType 值只能是text/plain application/xml、application/json、application/x-www-form-urlencoded
*/
public void setRequestContentType(RequestContext ctx,String contentType){
ctx.getZuulRequestHeaders().put(content-type, contentType);
}