一、@EnableZuulProxy
@Import(ZuulProxyMarkerConfiguration.class) public @interface EnableZuulProxy { } @Configuration(proxyBeanMethods = false) public class ZuulProxyMarkerConfiguration { //标记类 @Bean public Marker zuulProxyMarkerBean() { return new Marker(); } class Marker { } }
控制自动装配开启的标记类,还有一个类似的@EnableZuulServer注解,作用类似,起到zuul开启的控制作用,但是如果使用@EnableZuulServer注解,会少初始化三个过滤器PreDecorationFilter,RibbonRoutingFilter,SimpleHostRoutingFilter。当Zuul与Eureka、Ribbon等组件配合使用时,我们使用@EnableZuulProxy,如果非必要使用@EnableZuulServer即可。
二、自动装配
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.netflix.zuul.ZuulServerAutoConfiguration,\
org.springframework.cloud.netflix.zuul.ZuulProxyAutoConfiguration
ZuulProxyAutoConfiguration
@Configuration(proxyBeanMethods = false)
//导入了三种发送请求的客户端 @Import({ RibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class, RibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class, RibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class, HttpClientConfiguration.class }) @ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class) public class ZuulProxyAutoConfiguration extends ZuulServerAutoConfiguration { }
继承自ZuulServerAutoConfiguration,所以ZuulProxyAutoConfiguration相当于扩展了ZuulServerAutoConfiguration,重写了一部分逻辑,多初始化了一些过滤器。
zuul的本质还是一个servlet,遵从着mvc架构,因此我们来看看一些组件的初始化。
//两个参数,路由、控制器 @Bean public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes, ZuulController zuulController) { //初始化handlerMapping ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController); //错误请求控制器 mapping.setErrorController(this.errorController); //跨域配置 mapping.setCorsConfigurations(getCorsConfigurations()); return mapping; } //控制器初始化 @Bean public ZuulController zuulController() { return new ZuulController(); } //servlet初始化 @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()); // buffer缓冲 false servlet.addInitParameter("buffer-requests", "false"); return servlet; } //zuul 前置过滤器 @Bean public PreDecorationFilter preDecorationFilter(RouteLocator routeLocator, ProxyRequestHelper proxyRequestHelper) { return new PreDecorationFilter(routeLocator, this.server.getServletPrefix(), this.zuulProperties, proxyRequestHelper); } // ribbon 路由过滤器,如果是使用serviceId请求服务,执行该过滤器 @Bean public RibbonRoutingFilter ribbonRoutingFilter(ProxyRequestHelper helper, RibbonCommandFactory<?> ribbonCommandFactory) { RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, ribbonCommandFactory, this.requestCustomizers); return filter; } // 主机地址路由器,如果发现是主要地址请求,执行该路由器 @Bean @ConditionalOnMissingBean(SimpleHostRoutingFilter.class) public SimpleHostRoutingFilter simpleHostRoutingFilter(ProxyRequestHelper helper, ZuulProperties zuulProperties) { return new SimpleHostRoutingFilter(helper, zuulProperties); }
初始化过滤器
@Configuration(proxyBeanMethods = false) protected static class ZuulFilterConfiguration { //从spring容器中获取所有的filters @Autowired private Map<String, ZuulFilter> filters; @Bean public ZuulFilterInitializer zuulFilterInitializer(CounterFactory counterFactory, TracerFactory tracerFactory) { FilterLoader filterLoader = FilterLoader.getInstance(); FilterRegistry filterRegistry = FilterRegistry.instance(); //过滤器放入ZuulFilterInitializer return new ZuulFilterInitializer(this.filters, counterFactory, tracerFactory, filterLoader, filterRegistry); } }
三、执行过程
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(); } }
源码较为简单,就不看了。
四、替换okhttp
跟之前讲过的feign替换类似
添加jar包
<dependency> <groupId>com.squareup.okhttp3</groupId> <artifactId>okhttp</artifactId> </ dependency>
修改配置
ribbon.httpclient.enabled = false ribbon.okhttp.enabled = true