CamelContext的启动过程

camel version:2.20.1

1. Start Camel

org.apache.camel.impl.DefaultCamelContext#doStartCamel

private void doStartCamel() throws Exception {
	// start components
    startServices(components.values());
    // start the route definitions before the routes is started
    startRouteDefinitions(routeDefinitions);
    // invoke this logic to warmup the routes and if possible also start the routes
    // check clash = true; start consumer = true; resume consume = false; addingRoutes = true
    doStartOrResumeRoutes(routeServices, true, !doNotStartRoutesOnFirstStart, false, true);
    // starting will continue in the start method
}

1.1 Start Route Definitions

遍历所有的RouteDefinition,执行startRoute。

一个RouteDefinition可以包含多个消费者(from()),每个消费者对应一个Route,每个Route对应一个RouteContext。

org.apache.camel.impl.DefaultCamelContext#startRoute(org.apache.camel.model.RouteDefinition)

public void startRoute(RouteDefinition route) throws Exception {
    isStartingRoutes.set(true);
    try {
        // must ensure route is prepared, before we can start it
        route.prepare(this);

        List<Route> routes = new ArrayList<Route>();
        List<RouteContext> routeContexts = route.addRoutes(this, routes);
        RouteService routeService = new RouteService(this, route, routeContexts, routes);
        startRouteService(routeService, true);
    } finally {
        // we are done staring routes
        isStartingRoutes.remove();
    }
}

1.1.1 Create RouteContext Using From Definitions

遍历所有的FromDefinition生成对应数量的RouteContext

org.apache.camel.model.RouteDefinition#addRoutes(org.apache.camel.model.ModelCamelContext, java.util.Collection<org.apache.camel.Route>)

public List<RouteContext> addRoutes(ModelCamelContext camelContext, Collection<Route> routes) throws Exception {
    List<RouteContext> answer = new ArrayList<RouteContext>();
    for (FromDefinition fromType : inputs) {
        RouteContext routeContext;
        try {
            routeContext = addRoutes(camelContext, routes, fromType);
        } catch (FailedToCreateRouteException e) {
        } catch (Exception e) {
        }
        answer.add(routeContext);
    }
    return answer;
}

创建RouteContext的逻辑:

1. 解析endpoint;
2. 添加processor;
3. 提交routeContext;

org.apache.camel.model.RouteDefinition#addRoutes(org.apache.camel.CamelContext, java.util.Collection<org.apache.camel.Route>, org.apache.camel.model.FromDefinition)

protected RouteContext addRoutes(CamelContext camelContext, Collection<Route> routes, FromDefinition fromType) throws Exception {
   RouteContext routeContext = new DefaultRouteContext(camelContext, this, fromType, routes); 
   routeContext.getEndpoint();

   List<ProcessorDefinition<?>> list = new ArrayList<ProcessorDefinition<?>>(outputs);
   for (ProcessorDefinition<?> output : list) {
       try {
           output.addRoutes(routeContext, routes);
       } catch (Exception e) {
           RouteDefinition route = routeContext.getRoute();
           throw new FailedToCreateRouteException(route.getId(), route.toString(), output.toString(), e);
       }
   }

   routeContext.commit();
   return routeContext;
}
1.1.1.1 Resolve Endpoint

解析Endpoint。

org.apache.camel.impl.DefaultRouteContext#getEndpoint

public Endpoint getEndpoint() {
    if (endpoint == null) {
        endpoint = from.resolveEndpoint(this);
    }
    return endpoint;
}

org.apache.camel.impl.DefaultRouteContext#resolveEndpoint(java.lang.String, java.lang.String)

public Endpoint resolveEndpoint(String uri, String ref) {
    Endpoint endpoint = null;
    if (uri != null) {
        endpoint = resolveEndpoint(uri);
    }
    if (ref != null) {
        endpoint = lookup(ref, Endpoint.class);
        try {
            // need add the endpoint into service
            getCamelContext().addService(endpoint);
        } catch (Exception ex) {
            throw new RuntimeCamelException(ex);
        }
    }
}

通过URI获取Endpoint的最终逻辑在 org.apache.camel.CamelContext#getEndpoint(java.lang.String) 方法中实现。

1.1.1.2 Add Event Driven Processor

1. 根据processor类型构建Processor;
2. 将processor包装成channel;
3. 将包装后的channel添加到eventDrivenProcessors列表;

org.apache.camel.model.ProcessorDefinition#addRoutes

public void addRoutes(RouteContext routeContext, Collection<Route> routes) throws Exception {
    Processor processor = makeProcessor(routeContext);
    if (!routeContext.isRouteAdded()) {
        boolean endpointInterceptor = false;
        if (endpointInterceptor) {
        } else {
            routeContext.addEventDrivenProcessor(processor);
        }
    }
}

org.apache.camel.model.ProcessorDefinition#makeProcessorImpl

private Processor makeProcessorImpl(RouteContext routeContext) throws Exception {
    Processor processor = null;
	// at first use custom factory
    if (routeContext.getCamelContext().getProcessorFactory() != null) {
        processor = routeContext.getCamelContext().getProcessorFactory().createProcessor(routeContext, this);
    }
    // fallback to default implementation if factory did not create the processor
    if (processor == null) {
        processor = createProcessor(routeContext);
    }
    return wrapProcessor(routeContext, processor);
}
1.1.1.3 Commit Route Context

1. 组装Route:
Event Driven Processor -> Pipeline -> CamelInternalProcessor -> EventDrivenConsumerRoute。
2. 添加到Route列表;

org.apache.camel.impl.DefaultRouteContext#commit

public void commit() {
    // now lets turn all of the event driven consumer processors into a single route
    if (!eventDrivenProcessors.isEmpty()) {
        Processor target = Pipeline.newInstance(getCamelContext(), eventDrivenProcessors);
        CamelInternalProcessor internal = new CamelInternalProcessor(target);
        // and create the route that wraps the UoW
        Route edcr = new EventDrivenConsumerRoute(this, getEndpoint(), internal);
        routes.add(edcr);
    }
}

1.1.2 Start RouteService

创建并启用RouteService。

CamelContext既包含启动RouteService的方法也包含恢复RouteService的方法。

在CamelContext启动过程中,shouldStartRoutes()的值为false,所以这里并不启动路由,而是在org.apache.camel.impl.DefaultCamelContext#doStartOrResumeRoutes方法执行时才启动。

org.apache.camel.impl.DefaultCamelContext#startRouteService

protected synchronized void startRouteService(RouteService routeService, boolean addingRoutes) throws Exception {
    // we may already be starting routes so remember this, so we can unset accordingly in finally block
    boolean alreadyStartingRoutes = isStartingRoutes();
    if (!alreadyStartingRoutes) {
        isStartingRoutes.set(true);
    }

    try {
        // 如果routeService处于挂起状态,需要恢复routeService
        if (routeService.getStatus().isSuspended()) {
            resumeRouteService(routeService);
        } else {
            // 将routeService添加到 routeService Map
            routeServices.put(routeService.getId(), routeService);
            // CamelContext启动后才能添加route
            if (shouldStartRoutes()) {
                // 以安全的方式启动routeService
                // route将按正确的顺序启动、进行冲突检查、并且以正确的顺序关闭
                // forceAutoStart = true; check clash = true; start consumer = true; resume consume = false
                safelyStartRouteServices(true, true, true, false, addingRoutes, routeService);
                // start route services if it was configured to auto startup and we are not adding routes
                boolean autoStartup = routeService.getRouteDefinition().isAutoStartup(this) && this.isAutoStartup();
                if (!addingRoutes || autoStartup) {
                    // start the route since auto start is enabled or we are starting a route (not adding new routes)
                    routeService.start();
                }
            }
        }
    } finally {
        if (!alreadyStartingRoutes) {
            isStartingRoutes.remove();
        }
    }
}

1.2 Start Or Resume Route

org.apache.camel.impl.DefaultCamelContext#doStartOrResumeRoutes

protected void doStartOrResumeRoutes(Map<String, RouteService> routeServices, boolean checkClash,
                                         boolean startConsumer, boolean resumeConsumer, boolean addingRoutes) throws Exception {
    isStartingRoutes.set(true);
    try {
        // filter out already started routes
        Map<String, RouteService> filtered = new LinkedHashMap<String, RouteService>();
        for (Map.Entry<String, RouteService> entry : routeServices.entrySet()) {
            boolean startable = false;
			// judgement
            if (startable) {
                filtered.put(entry.getKey(), entry.getValue());
            }
        }

        // the context is in last phase of staring, so lets start the routes
        safelyStartRouteServices(checkClash, startConsumer, resumeConsumer, addingRoutes, filtered.values());
    } finally {
        isStartingRoutes.remove();
    }
}

1.2.1 Safely Start Route Services

1. 为每个路由设置启动顺序
2. 优先启动processor及其子服务
3. 然后启动consumer
4. 清空consumer列表

参数介绍
checkClash 是否检查启动顺序冲突
startConsumer 是否启动路由consumer, 可以在不启动consumer的情况下对路由进行预热
resumeConsumer 是否恢复路由consumer
addingRoutes 是否新添加路由
routeServices 路由列表

org.apache.camel.impl.DefaultCamelContext#safelyStartRouteServices(boolean, boolean, boolean, boolean, java.util.Collection<org.apache.camel.impl.RouteService>)

protected synchronized void safelyStartRouteServices(boolean checkClash, boolean startConsumer, boolean resumeConsumer,
                                                         boolean addingRoutes, Collection<RouteService> routeServices) throws Exception {
    Map<Integer, DefaultRouteStartupOrder> inputs = new TreeMap<Integer, DefaultRouteStartupOrder>();

    // 为每个路由设置启动顺序
    for (RouteService routeService : routeServices) {
        DefaultRouteStartupOrder order = doPrepareRouteToBeStarted(routeService);
        inputs.put(order.getStartupOrder(), order);
    }

    // 优先启动processor及其子服务
    doWarmUpRoutes(inputs, startConsumer);

    // 然后启动consumer
    if (startConsumer) {
        if (resumeConsumer) {
            // 恢复consumer
            doResumeRouteConsumers(inputs, addingRoutes);
        } else {
            // 启动consumer
            // 检查是否存在多个consumer消费一个endpoint的情形,这是不允许的。
            doStartRouteConsumers(inputs, addingRoutes);
        }
    }

    // 清空consumer列表
    inputs.clear();
}
1.2.1.1 Warm Up Route Service

warm up的主要作用是启动RouteService对应路由的endpoint和子服务。

优先启动所有的processor和子服务,然后再启用consumer,增强了Camel的健壮性。当consumer启动后便可以及时的消费消息。

org.apache.camel.impl.RouteService#doWarmUp

protected synchronized void doWarmUp() throws Exception {
	// 启动endpoint
    if (endpointDone.compareAndSet(false, true)) {
        // endpoint只能启动一次,可以被其他路由重用,endpoint启用后只有在Camel停止时才被关闭
        for (Route route : routes) {
            // 确保endpoint在route services(比如consumer)之前启动
            ServiceHelper.startService(route.getEndpoint());
        }
    }

    if (warmUpDone.compareAndSet(false, true)) {
        for (Route route : routes) {
            try (MDCHelper mdcHelper = new MDCHelper(route.getId())) {
                // 清空服务列表
                route.warmUp();
				// 获取服务列表
                List<Service> services = route.getServices();
                // 构建服务列表
                route.onStartingServices(services);

                // 获取需要启动的所有服务(包含所有子服务、递归获取)
                Set<Service> list = new LinkedHashSet<Service>();
                for (Service service : services) {
                    list.addAll(ServiceHelper.getChildServices(service));
                }

                // 将Consumer和子服务分离,优先启动子服务
                List<Service> childServices = new ArrayList<Service>();
                for (Service service : list) {
                    // inject the route
                    if (service instanceof RouteAware) {
                        ((RouteAware) service).setRoute(route);
                    }

                    if (service instanceof Consumer) {
                        inputs.put(route, (Consumer) service);
                    } else {
                        childServices.add(service);
                    }
                }
                startChildService(route, childServices);

                // 触发route添加事件
                EventHelper.notifyRouteAdded(camelContext, route);
            }
        }

        // ensure lifecycle strategy is invoked which among others enlist the route in JMX
        for (LifecycleStrategy strategy : camelContext.getLifecycleStrategies()) {
            strategy.onRoutesAdd(routes);
        }

        // add routes to camel context
        camelContext.addRouteCollection(routes);

        // add the routes to the inflight registry so they are pre-installed
        for (Route route : routes) {
            camelContext.getInflightRepository().addRoute(route.getId());
        }
    }
}

org.apache.camel.impl.EventDrivenConsumerRoute#addServices

protected void addServices(List<Service> services) throws Exception {
   	// 创建并添加consumer
    Endpoint endpoint = getEndpoint();
    consumer = endpoint.createConsumer(processor);
    if (consumer != null) {
        services.add(consumer);
        if (consumer instanceof RouteAware) {
            ((RouteAware) consumer).setRoute(this);
        }
    }
    // 如果processor是Service的实例,添加processor
    Processor processor = getProcessor();
    if (processor instanceof Service) {
        services.add((Service)processor);
    }
}
1.2.1.2 Start Or Resume Route Consumers

org.apache.camel.impl.DefaultCamelContext#doStartOrResumeRouteConsumers

private void doStartOrResumeRouteConsumers(Map<Integer, DefaultRouteStartupOrder> inputs, boolean resumeOnly, boolean addingRoute) throws Exception {
    List<Endpoint> routeInputs = new ArrayList<Endpoint>();

    for (Map.Entry<Integer, DefaultRouteStartupOrder> entry : inputs.entrySet()) {
        Integer order = entry.getKey();
        Route route = entry.getValue().getRoute();
        RouteService routeService = entry.getValue().getRouteService();
        // start the service
        for (Consumer consumer : routeService.getInputs().values()) {
            Endpoint endpoint = consumer.getEndpoint();
            if (resumeOnly && route.supportsSuspension()) {
                // if we are resuming and the route can be resumed
                ServiceHelper.resumeService(consumer);
            } else {
                // when starting we should invoke the lifecycle strategies
                for (LifecycleStrategy strategy : lifecycleStrategies) {
                    strategy.onServiceAdd(this, consumer, route);
                }
                
                startService(consumer);
                }
            }

            routeInputs.add(endpoint);
        }

        if (resumeOnly) {
            routeService.resume();
        } else {
            routeService.start(false);
        }
    }
}

参考

Camel路由启动过程

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值