Spring Cloud Zuul 路由自动刷新原理

现象

发布新服务,然后在数据库配置了路由,使用服务路径访问404。然后重新发布新的服务,就可以继续访问得到

(1)配置了路由第一次访问

动态路由-应用重启前

(2)重新发布后访问

动态路由-应用重启后

分析

(1)查找RefreshableRouteLocator.refresh方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
@Component
public class NacosRouteLocator extends SimpleRouteLocator implements RefreshableRouteLocator {

public NacosRouteLocator(ServerProperties serverProperties, ZuulProperties properties) {
super(serverProperties.getServlet().getContextPath(), properties);
}

@Override
public void refresh() {
doRefresh();
}

@Override
protected Map<String, ZuulProperties.ZuulRoute> locateRoutes() {

//默认从配置文件中加载路由信息
//return super.locateRoutes());

//定制路由, 可以使用db的配置管理进行路由
Map<String, ZuulProperties.ZuulRoute> routesMap = DbUtils.loadRoutes();

return routesMap;
}
}

(2)ZuulHandlerMapping.setDirty方法

1
2
3
4
5
6
7
8
9
public class ZuulHandlerMapping extends AbstractUrlHandlerMapping {

public void setDirty(boolean dirty) {
this.dirty = dirty;
if (this.routeLocator instanceof RefreshableRouteLocator) {
((RefreshableRouteLocator) this.routeLocator).refresh();
}
}
}

(3)ZuulRefreshListener.reset方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
|| 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.heartbeatMonitor.update(value)) {
reset();
}
}

private void reset() {
this.zuulHandlerMapping.setDirty(true);
}
}

(4)发现ApplicationEvent

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent
|| event instanceof RefreshScopeRefreshedEvent
|| event instanceof RoutesRefreshedEvent
|| 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());
}
}

可以看到,其中的实例注册事件RoutesRefreshedEventInstanceRegisteredEvent均会触发刷新路由。

(5)Eureka触发路由更新

1
2
3
4
5
6
7
8
9
10
11
12
// org.springframework.cloud.netflix.eureka.CloudEurekaClient#onCacheRefreshed
@Override
protected void onCacheRefreshed() {
super.onCacheRefreshed();

if (this.cacheRefreshedCount != null) { // might be called during construction and
// will be null
long newCount = this.cacheRefreshedCount.incrementAndGet();
log.trace("onCacheRefreshed called with count: " + newCount);
this.publisher.publishEvent(new HeartbeatEvent(this, newCount));
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Override
// org.springframework.cloud.netflix.eureka.serviceregistry.EurekaAutoServiceRegistration#start
public void start() {
// only set the port if the nonSecurePort or securePort is 0 and this.port != 0
if (this.port.get() != 0) {
if (this.registration.getNonSecurePort() == 0) {
this.registration.setNonSecurePort(this.port.get());
}

if (this.registration.getSecurePort() == 0 && this.registration.isSecure()) {
this.registration.setSecurePort(this.port.get());
}
}

// only initialize if nonSecurePort is greater than 0 and it isn't already running
// because of containerPortInitializer below
if (!this.running.get() && this.registration.getNonSecurePort() > 0) {

this.serviceRegistry.register(this.registration);

this.context.publishEvent(new InstanceRegisteredEvent<>(this,
this.registration.getInstanceConfig()));
this.running.set(true);
}
}

Powered by AppBlog.CN     浙ICP备14037229号

Copyright © 2012 - 2021 APP开发技术博客 All Rights Reserved.

访客数 : | 访问量 :