@EnableZuulProxy和@EnableZuulServer通过实例化不同的Marker,走不同的AutoConfiguration。
@EnableZuulProxy所走的ZuulProxyAutoConfiguration基础于@EnableZuulServer的ZuulServerAutoConfiguration。
所以两者的区别在于ZuulProxyAutoConfiguration在ZuulServerAutoConfiguration的基础上增加eureka、ribbon、hystrix等功能。
Zuul配置文件读取是通过在@Configuration注解的类上加@EnableConfigurationProperties注解引入ZuulProperties,而去自动读取的。
ZuulProperties通过routes存放每个路由信息。
ZuulServlet的实例化位于ZuulServerAutoConfiguration中,其通过ServletRegistrationBean注册了监听/zuul路径的ZuulServlet。
@Bean
@ConditionalOnMissingBean(name = "zuulServlet")
@ConditionalOnProperty(name = "zuul.use-filter", havingValue = "false", matchIfMissing = true)
public ServletRegistrationBean zuulServlet() {
ServletRegistrationBean<ZuulServlet> servlet = new ServletRegistrationBean<>(
new ZuulServlet(), this.zuulProperties.getServletPattern());
servlet.addInitParameter("buffer-requests", "false");
return servlet;
}
但我们使用过程中访问的路径是不带/zuul的,其实现是通过ZuulServerAutoConfiguration实例化的ZuulController和ZuulHandlerMapping来实现的。
ZuulController继承了ServletWrappingController,将请求委托给ZuulServlet处理。
public class ZuulController extends ServletWrappingController {
public ZuulController() {
setServletClass(ZuulServlet.class);
setServletName("zuul");
setSupportedMethods((String[]) null); // Allow all
}
@Override
public ModelAndView handleRequest(HttpServletRequest request,
HttpServletResponse response) throws Exception {
try {
return super.handleRequestInternal(request, response);
}
finally {
RequestContext.getCurrentContext().unset();
}
}
}
而ZuulHandlerMapping继承了AbstractUrlHandlerMapping,通过重写lookupHandler,将配置文件所配置的路径交给ZuulController处理。
public class ZuulHandlerMapping extends AbstractUrlHandlerMapping {
private final RouteLocator routeLocator;
private final ZuulController zuul;
private volatile boolean dirty = true;
@Override
protected Object lookupHandler(String urlPath, HttpServletRequest request)
throws Exception {
RequestContext ctx = RequestContext.getCurrentContext();
if (ctx.containsKey("forward.to")) {
return null;
}
//刷新新Route配置
if (this.dirty) {
synchronized (this) {
if (this.dirty) {
registerHandlers();
this.dirty = false;
}
}
}
return super.lookupHandler(urlPath, request);
}
//Route配置的路径,注册处理器为ZuulController
private void registerHandlers() {
Collection<Route> routes = this.routeLocator.getRoutes();
if (routes.isEmpty()) {
this.logger.warn("No routes found from RouteLocator");
}
else {
for (Route route : routes) {
registerHandler(route.getFullPath(), this.zuul);
}
}
}
}
于是当我们配置一个route,hello->localhost:8080,我们可以通过/zuul/hello去访问,也可以通过/hello去访问。
下面我们看下ZuulServlet的逻辑,可以发现ZuulServlet的逻辑很简单,都是交给ZuulFilter去实现。
public class ZuulServlet extends HttpServlet {
private static final long serialVersionUID = -3374242278843351500L;
private ZuulRunner zuulRunner;
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
String bufferReqsStr = config.getInitParameter("buffer-requests");
boolean bufferReqs = bufferReqsStr != null && bufferReqsStr.equals("true") ? true : false;
zuulRunner = new ZuulRunner(bufferReqs);
}
@Override
public void service(javax.servlet.ServletRequest servletRequest, javax.servlet.ServletResponse servletResponse) throws ServletException, IOException {
try {
init((HttpServletRequest) servletRequest, (HttpServletResponse) servletResponse);
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();
}
}
}
原文:https://www.cnblogs.com/wuweishuo/p/13346453.html