Search code examples
springspring-bootapache-camelspring-camel

CamelContextStartedEvent called twice


The CamelContextStartedEvent is called twice for the same camel context (camel-1). The issue might be the way I register the EventNotifier. You can reproduce the issue with Spring Initializr with Spring Boot 1.5.14, Spring Boot Camel Starter 2.21.1 and Spring Boot Web Starter.

See the logs:

2018-07-06 11:04:41.104  INFO 19092 --- [           main] o.a.camel.spring.SpringCamelContext      : Apache Camel 2.21.1 (CamelContext: camel-1) is starting
2018-07-06 11:04:41.106  INFO 19092 --- [           main] o.a.c.m.ManagedManagementStrategy        : JMX is enabled
2018-07-06 11:04:41.191  INFO 19092 --- [           main] o.a.camel.spring.SpringCamelContext      : StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
2018-07-06 11:04:41.193  INFO 19092 --- [           main] o.a.camel.spring.boot.RoutesCollector    : Starting CamelMainRunController to ensure the main thread keeps running
2018-07-06 11:04:41.193  INFO 19092 --- [           main] o.a.camel.spring.SpringCamelContext      : Total 0 routes, of which 0 are started
2018-07-06 11:04:41.194  INFO 19092 --- [           main] o.a.camel.spring.SpringCamelContext      : Apache Camel 2.21.1 (CamelContext: camel-1) started in 0.090 seconds
2018-07-06 11:04:41.195  INFO 19092 --- [           main] c.e.bug.service.StartupEventNotifier     : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.195  INFO 19092 --- [           main] c.e.bug.service.StartupEventNotifier     : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.216  INFO 19092 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 11223 (http)
2018-07-06 11:04:41.221  INFO 19092 --- [           main] com.example.bug.BugApplication           : Started BugApplication in 4.684 seconds (JVM running for 6.773)

The service that initializes the EventNotifier:

@Service
public class SchedulerService {

    private final CamelContext camelContext;

    private final StartupEventNotifier startupEventNotifier;

    public SchedulerService(CamelContext camelContext, StartupEventNotifier startupEventNotifier) {
        this.camelContext = camelContext;
        this.startupEventNotifier = startupEventNotifier;
    }

    @PostConstruct
    public void init() {
        camelContext.getManagementStrategy().addEventNotifier(startupEventNotifier);
    }

}

The EventNotifier:

@Component
public class StartupEventNotifier extends EventNotifierSupport {

    private static final Logger logger = LoggerFactory.getLogger(StartupEventNotifier.class);

    @Override
    public void notify(EventObject event) throws Exception {
        if (event instanceof CamelContextStartedEvent) {
            logger.info("CamelContextStartedEvent for {}", event.getSource());
        }
    }

    @Override
    public boolean isEnabled(EventObject event) {
        if (event instanceof CamelContextStartedEvent) {
            return true;
        }
        return false;
    }
}

application.yml:

camel:
  springboot:
    main-run-controller: true
server:
  port: 11223

Solution

  • It is called twice, because it is registered twice. Once by you and once by Apache Camel. EventNotifier is registered automatically, if is found in Registry. Since your StartupEventNotifier is annotated as Component, it is part of Registry and Apache Camel registered it during CamelContext startup (You can see it in CamelAutoConfiguration line 424).

    You have four options:

    • Remove your custom registration from SchedulerService.
    • Remove @Component annotation from StartupEventNotifier and register it with with camelContext.getManagementStrategy().addEventNotifier(new StartupEventNotifier())
    • Add duplicity check to your SchedulerService. Something like:

      if (!context.getManagementStrategy().getEventNotifiers().contains(startupEventNotifier)){
          context.getManagementStrategy().addEventNotifier(startupEventNotifier);
      }
      
    • Register EventNotifier in @PostConstruct of RouteBuilder. It will be registered before automatic discovery is started and then it will be skipped in CamelAutoConfiguration (See line 422)