版本:
spring-boot:1.5.3.RELEASE;
spring cloud:Dalston.RELEASE(1.3.0.RELEASE)
路由定位器
- 配置所在jar包:spring-cloud-netflix-core-1.3.0.RELEASE.jar
- 顶层接口:RouteLocator
- 可刷新的路由:RefreshableRouteLocator extends RouteLocator
- 路由处理器:CompositeRouteLocator implements RefreshableRouteLocator,所有的路由定位器都交由给它处理
- 默认加载的路由定位器:SimpleRouteLocator implements RouteLocator, Ordered,实现Ordered接口达到排序的效果
- 配置类:ZuulProxyConfiguration extends ZuulConfiguration,ZuulConfiguration中包含默认的一些公共的filter,ZuulProxyConfiguration包含spring cloud的需要的一些filter,如:host解析、ribbon负载均衡等
- zuul初始化配置不是通过spring.factories配置文件,而是通过@EnableZuulProxy注解引入配置的,源码如下:
@EnableCircuitBreaker
@EnableDiscoveryClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulProxyConfiguration.class)
public @interface EnableZuulProxy {
}
- zuul路由的请求是通过filter发出去的
- 可刷新的路由定位器(RefreshableRouteLocator)是基于监听spring容器事件实现的,并且都是在配置类中(内部静态类),有两个地方:
ZuulConfiguration中的监听:
//加载bean
@Bean
public ApplicationListener<ApplicationEvent> zuulRefreshRoutesListener() {
return new ZuulRefreshListener();
}
//内部静态类
private static class ZuulRefreshListener implements ApplicationListener<ApplicationEvent> {
@Autowired
private ZuulHandlerMapping zuulHandlerMapping;
private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor();
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent
|| event instanceof RefreshScopeRefreshedEvent
|| event instanceof RoutesRefreshedEvent) {
this.zuulHandlerMapping.setDirty(true);
}
else if (event instanceof HeartbeatEvent) {
if (this.heartbeatMonitor.update(((HeartbeatEvent) event).getValue())) {
this.zuulHandlerMapping.setDirty(true);
}
}
}
}
ZuulProxyConfiguration中的监听:
//加载bean
@Bean
public ApplicationListener<ApplicationEvent> zuulDiscoveryRefreshRoutesListener() {
return new ZuulDiscoveryRefreshListener();
}
//内部静态类
private static class ZuulDiscoveryRefreshListener implements ApplicationListener<ApplicationEvent> {
private HeartbeatMonitor monitor = new HeartbeatMonitor();
@Autowired
private ZuulHandlerMapping zuulHandlerMapping;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof InstanceRegisteredEvent) {
reset();
}
else if (event instanceof ParentHeartbeatEvent) {
ParentHeartbeatEvent e = (ParentHeartbeatEvent) event;
resetIfNeeded(e.getValue());
}
else if (event instanceof HeartbeatEvent) {
HeartbeatEvent e = (HeartbeatEvent) event;
resetIfNeeded(e.getValue());
}
}
private void resetIfNeeded(Object value) {
if (this.monitor.update(value)) {
reset();
}
}
private void reset() {
this.zuulHandlerMapping.setDirty(true);
}
}
以上可以看出有个问题,两个地方都监听了HeartbeatEvent,并且做了相同的处理,会导致重复刷新
- 触发心跳事件:SimpleApplicationEventMulticaster-->167行
- 心跳是个线程池专门处理,初始化是在:com.netflix.discovery.DiscoveryClient-->1247行
- 心跳的间隔时间配置有bug(配置没生效,配置的名称是间隔,但是线程池调度的时候传给超时时间的),默认是30分钟,配置是:
#org.springframework.cloud.netflix.eureka.EurekaInstanceConfigBean.leaseRenewalIntervalInSeconds
eureka.instance.leaseRenewalIntervalInSeconds=30