您的位置:首页 > 编程语言 > Java开发

API网关服务:Spring Cloud Zuul

2017-09-21 16:05 1051 查看

1.Zuul简介

1.1 zuul的位置

    zuul就像是整个微服务架构系统的门面,所有的外部客户端请求都需要经过它进行路由。
     


1.2 zuul执行流程



     简单来说zuul将请求转发,并提供pre,post,error类型过滤器,这些过滤器执行的时间不同,对应不同的阶段。

2.使用

2.1.添加依赖

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>

2.2请求路由

传统路由方式

zuul.routes.api-server.path=/test/**
zuul.routes.api-server.url=http://localhost:8011/

面向服务的路由方式

zuul.routes.api-favorite.path=/Favorite/**
zuul.routes.api-favorite.serviceId=mem-favorite


本地跳转
zuul.routes.api-b.path=/api-b/**
zuul.routes.api-b.url=forward:/api/b

zull默认会将通过服务名(从服务中心拉取的信息)作为ContextPath的方式来创建路由映射。

2.3请求过滤

class PreFilter extends ZuulFilter {

@Override
String filterType() {
return "pre"
}

@Override
int filterOrder() {
return -4
}

@Override
boolean shouldFilter() {
return true
}

@Override
Object run() {
HttpServletRequest context = RequestContext.getCurrentContext().getRequest()
System.out.println("this is a pre filter")

return null
}
}


通过继承ZuulFilter抽象类并覆盖下面4个方法来实现自定义过滤器。
filterType:过滤器类型,它决定了过滤器执行的时机。
filterOrder:过滤器的属性。相同类型过滤器有多个的时候,通过这个决定执行的顺序。
shouldFilter:判断该过滤器是否需要执行。
run:过滤器的具体逻辑。

2.4自定义路由映射规则

public class PatternServiceRouteMapper implements ServiceRouteMapper {

/**
* A RegExp Pattern that extract needed information from a service ID. Ex :
* "(?<name>.*)-(?<version>v.*$)"
*/
private Pattern servicePattern;
/**
* A RegExp that refer to named groups define in servicePattern. Ex :
* "${version}/${name}"
*/
private String routePattern;

public PatternServiceRouteMapper(String servicePattern, String routePattern) {
this.servicePattern = Pattern.compile(servicePattern);
this.routePattern = routePattern;
}


只要创建PatternServiceRouteMapper Bean就可以了。参数是两个正则表达式。

2.5路径匹配

?  匹配任意单个字符
 *   匹配任意数量的字符
 **  匹配任意的字符,支持多级目录

3.zuul原理

3.1 ZuulServlet整体执行流程

@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
try {
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);

// Marks this request as having passed through the "Zuul engine", as opposed to servlets
// explicitly bound in web.xml, for which requests will not have the same data attached
RequestContext context = RequestContext.getCurrentContext();
context.setZuulEngineRan();

try {
preRoute();
} catch (ZuulException e) {
error(e);
postRoute();
return;
}
try {
route();
} catch (ZuulException e) {
error(e);
postRoute();
return;
}
try {
postRoute();
} catch (ZuulException e) {
error(e);
return;
}

} catch (Throwable e) {
error(new ZuulException(e, 500, "UNHANDLED_EXCEPTION_" + e.getClass().getName()));
} finally {
RequestContext.getCurrentContext().unset();
}
}


继续往下看,看到FilterProcessor类几个方法

public void postRoute() throws ZuulException {
try {
runFilters("post");
} catch (ZuulException e) {
throw e;
} catch (Throwable e) {
throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_POST_FILTER_" + e.getClass().getName());
}
}

public void error() {
try {
runFilters("error");
} catch (Throwable e) {
logger.error(e.getMessage(), e);
}
}

public void route() throws ZuulException {
try {
runFilters("route");
} catch (ZuulException e) {
throw e;
} catch (Throwable e) {
throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_ROUTE_FILTER_" + e.getClass().getName());
}
}

public void preRoute() throws ZuulException {
try {
runFilters("pre");
} catch (ZuulException e) {
throw e;
} catch (Throwable e) {
throw new ZuulException(e, 500, "UNCAUGHT_EXCEPTION_IN_PRE_FILTER_" + e.getClass().getName());
}
}

继续看最终我们找到通过getFiltersByType获得相应的ZuulFilter

public List<ZuulFilter> getFiltersByType(String filterType) {

List<ZuulFilter> list = hashFiltersByType.get(filterType);
if (list != null) return list;

list = new ArrayList<ZuulFilter>();

Collection<ZuulFilter> filters = filterRegistry.getAllFilters();
for (Iterator<ZuulFilter> iterator = filters.iterator(); iterator.hasNext(); ) {
ZuulFilter filter = iterator.next();
if (filter.filterType().equals(filterType)) {
list.add(filter);
}
}
Collections.sort(list); // sort by priority

hashFiltersByType.putIfAbsent(filterType, list);
return list;
}

我们看filterRegistry,查看谁调用了put方法我们找到了ZuulFilterInitializer

@Override
public void contextInitialized(ServletContextEvent sce) {

log.info("Starting filter initializer context listener");

TracerFactory.initialize(tracerFactory);
CounterFactory.initialize(counterFactory);

for (Map.Entry<String, ZuulFilter> entry : this.filters.entrySet()) {
filterRegistry.put(entry.getKey(), entry.getValue());
}
}


我们看到是通过filters获得的,继续查看是谁实例化了ZuulFilterInitializer对象,我们找到了ZuulConfiguration类。代码如下

@Configuration
protected static class ZuulFilterConfiguration {

@Autowired
private Map<String, ZuulFilter> filters;

@Bean
public ZuulFilterInitializer zuulFilterInitializer(
CounterFactory counterFactory, TracerFactory tracerFactory) {
FilterLoader filterLoader = FilterLoader.getInstance();
FilterRegistry filterRegistry = FilterRegistry.instance();
return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry);
}

}

最终我们看到了是通过自动注入获得了所有的ZuulFilter

@Autowired
private Map<String, ZuulFilter> filters;


3.2  Zuul默认提供的ZuulFilter



3.3动态路由

 和配置中心结合加入如下代码即可

@Bean
@RefreshScope
@ConfigurationProperties("zuul")
public ZuulProperties zullProperties() {
return new ZuulProperties();
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: