Search code examples
springapache-camelspring-camel

How to write a custom Apache Camel component/endpoint with Spring Boot Java Config


I'm looking for an example/documentation of how to implement a custom Apache Camel component and endpoint with Spring Boot in Java Config. I don't know how I have to annotate the classes, that Could you please provide an example. Without using Spring my (working) code looks like this:

public class MyCustomComponent extends DefaultComponent {
    @Override
    protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
        Endpoint endpoint = new MyCustomEndpoint(uri, this);
        setProperties(endpoint, parameters);
        return endpoint;
    }
}

Registered is the component in resources/META-INF/services/org/apache/camel/component/myscheme with the FQN of the MyCustomComponent class.

public class MyCustomEndpoint extends DefaultEndpoint {

    public MyCustomEndpoint(String uri, MyCustomComponent component) {
        super(uri, component);
    }

    @Override
    public Producer createProducer() throws Exception {
        return new MyCustomProducer(this);
    }

    @Override
    public Consumer createConsumer(Processor processor) throws Exception {
        throw new UnsupportedOperationException("Not implemented yet: MyCustomEndpoint#createConsumer");
    }

    @Override
    public boolean isSingleton() {
        return false;
    }
}
public class MyCustomProducer extends DefaultProducer {

    public MyCustomProducer(Endpoint endpoint) {
        super(endpoint);
    }

    @Override
    public void process(Exchange exchange) throws Exception {
    }
}

Solution

  • After a lot of search I have found a solution on the base of Spring's BeanFactory. The major obstacle are the circular dependencies (Component -> Endpoint -> Component | Endpoint -> Producer -> Endpoint). At first I have introduced a Spring Configuration class:

    @Configuration
    public class ComponentConfiguration {
    
        @Bean("myCustomEndpoint")
        @Scope("prototype")
        public MyCustomEndpoint myCustomEndpoint(String uri, MyCustomComponent component) {
            MyCustomEndpoint endpoint = new MyCustomEndpoint(uri, component);
            return endpoint;
        }
    
        @Bean("myCustomProducer")
        @Scope("prototype")
        public MyCustomProducer myCustomProducer(MyCustomEndpoint endpoint) {
            return new MyCustomProducer(endpoint);
        }
    }
    

    Make the custom Camel component a Spring component with @Componentannotation, so I'm able to inject the BeanFactory to create an instance of the MyCustomEndpoint class on demand (prototype scope).

    @org.springframework.stereotype.Component
    public class MyCustomComponent extends DefaultComponent {
    
        @Autowired
        private BeanFactory beanFactory;
    
        @Override
        protected Endpoint createEndpoint(String uri, String remaining, Map<String, Object> parameters) throws Exception {
            MyCustomEndpoint endpoint = (MyCustomEndpoint) beanFactory.getBean("myCustomEndpoint", uri, this);
            setProperties(endpoint, parameters);
            return endpoint;
        }
    }
    
    public class MyCustomEndpoint extends DefaultEndpoint {
    
        @Autowired
        private BeanFactory beanFactory;
    
        public MyCustomEndpoint(String uri, MyCustomComponent component) {
            super(uri, component);
        }
    
        @Override
        public Producer createProducer() throws Exception {
            MyCustomProducer producer = (MyCustomProducer) beanFactory.getBean("myCustomProducer",  this);
            return producer;
        }
    
        @Override
        public Consumer createConsumer(Processor processor) throws Exception {
            throw new UnsupportedOperationException("Not implemented yet: MyCustomEndpoint#createConsumer");
        }
    
        @Override
        public boolean isSingleton() {
            return true;
        }
    }
    
    public class MyCustomProducer extends DefaultProducer {
    
        // Now, I am able to inject some other Spring beans
        @Autowired
        private AnotherSpringBean bean;
    
        public MyCustomProducer(Endpoint endpoint) {
            super(endpoint);
        }
    
        @Override
        public void process(Exchange exchange) throws Exception {
        }
    }
    

    Note that the Camel component MyCustomComponent is already registered in resources/META-INF/services/org/apache/camel/component/myscheme:

    class=<fqn-of-MyCustomComponent>