Repository: camel Updated Branches: refs/heads/master 1611a1930 -> 300c1277f
CAMEL-11841: cluster service : make a simple FileLock based service Project: http://git-wip-us.apache.org/repos/asf/camel/repo Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/300c1277 Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/300c1277 Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/300c1277 Branch: refs/heads/master Commit: 300c1277f8418ee57ec7d894b93077968ef69add Parents: 1611a19 Author: lburgazzoli <lburgazz...@gmail.com> Authored: Tue Sep 26 12:43:55 2017 +0200 Committer: lburgazzoli <lburgazz...@gmail.com> Committed: Tue Sep 26 14:06:16 2017 +0200 ---------------------------------------------------------------------- .../file/ha/FileLockClusterService.java | 138 ++++++++++++++ .../component/file/ha/FileLockClusterView.java | 181 +++++++++++++++++++ .../ha/FileLockClusteredRoutePolicyTest.java | 108 +++++++++++ camel-core/src/test/resources/log4j2.properties | 5 +- ...FileLockClusterServiceAutoConfiguration.java | 65 +++++++ .../ha/FileLockClusterServiceConfiguration.java | 87 +++++++++ .../main/resources/META-INF/spring.factories | 1 + 7 files changed, 584 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/camel/blob/300c1277/camel-core/src/main/java/org/apache/camel/component/file/ha/FileLockClusterService.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/file/ha/FileLockClusterService.java b/camel-core/src/main/java/org/apache/camel/component/file/ha/FileLockClusterService.java new file mode 100644 index 0000000..2d207de --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/component/file/ha/FileLockClusterService.java @@ -0,0 +1,138 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.file.ha; + +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.CamelContext; +import org.apache.camel.impl.ha.AbstractCamelClusterService; +import org.apache.camel.util.ObjectHelper; + +public class FileLockClusterService extends AbstractCamelClusterService<FileLockClusterView> { + private String root; + private long acquireLockDelay; + private TimeUnit acquireLockDelayUnit; + private long acquireLockInterval; + private TimeUnit acquireLockIntervalUnit; + private ScheduledExecutorService executor; + + public FileLockClusterService() { + this.acquireLockDelay = 1; + this.acquireLockDelayUnit = TimeUnit.SECONDS; + this.acquireLockInterval = 10; + this.acquireLockIntervalUnit = TimeUnit.SECONDS; + } + + @Override + protected FileLockClusterView createView(String namespace) throws Exception { + return new FileLockClusterView(this, namespace); + } + + public String getRoot() { + return root; + } + + /** + * Sets the root path. + */ + public void setRoot(String root) { + this.root = root; + } + + public long getAcquireLockDelay() { + return acquireLockDelay; + } + + /** + * The time to wait before starting to try to acquire lock, default 1. + */ + public void setAcquireLockDelay(long acquireLockDelay) { + this.acquireLockDelay = acquireLockDelay; + } + + public void setAcquireLockDelay(long pollDelay, TimeUnit pollDelayUnit) { + setAcquireLockDelay(pollDelay); + setAcquireLockDelayUnit(pollDelayUnit); + } + + public TimeUnit getAcquireLockDelayUnit() { + return acquireLockDelayUnit; + } + + /** + * The time unit fo the acquireLockDelay, default to TimeUnit.SECONDS. + */ + public void setAcquireLockDelayUnit(TimeUnit acquireLockDelayUnit) { + this.acquireLockDelayUnit = acquireLockDelayUnit; + } + + public long getAcquireLockInterval() { + return acquireLockInterval; + } + + /** + * The time to wait between attempts to try to acquire lock, default 10. + */ + public void setAcquireLockInterval(long acquireLockInterval) { + this.acquireLockInterval = acquireLockInterval; + } + + public void setAcquireLockInterval(long pollInterval, TimeUnit pollIntervalUnit) { + setAcquireLockInterval(pollInterval); + setAcquireLockIntervalUnit(pollIntervalUnit); + } + + public TimeUnit getAcquireLockIntervalUnit() { + return acquireLockIntervalUnit; + } + + /** + * The time unit fo the acquireLockInterva, default to TimeUnit.SECONDS. + */ + public void setAcquireLockIntervalUnit(TimeUnit acquireLockIntervalUnit) { + this.acquireLockIntervalUnit = acquireLockIntervalUnit; + } + + @Override + protected void doStop() throws Exception { + super.doStop(); + + CamelContext context = getCamelContext(); + + if (executor != null) { + if (context != null) { + context.getExecutorServiceManager().shutdown(executor); + } else { + executor.shutdown(); + } + + executor = null; + } + } + + synchronized ScheduledExecutorService getExecutor() { + if (executor == null) { + // Camel context should be set at this stage. + final CamelContext context = ObjectHelper.notNull(getCamelContext(), "CamelContext"); + + executor = context.getExecutorServiceManager().newSingleThreadScheduledExecutor(this, "FileLockClusterService-" + getId()); + } + + return executor; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/300c1277/camel-core/src/main/java/org/apache/camel/component/file/ha/FileLockClusterView.java ---------------------------------------------------------------------- diff --git a/camel-core/src/main/java/org/apache/camel/component/file/ha/FileLockClusterView.java b/camel-core/src/main/java/org/apache/camel/component/file/ha/FileLockClusterView.java new file mode 100644 index 0000000..6fcf703 --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/component/file/ha/FileLockClusterView.java @@ -0,0 +1,181 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.file.ha; + +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.nio.channels.OverlappingFileLockException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.ha.CamelClusterMember; +import org.apache.camel.impl.ha.AbstractCamelClusterView; +import org.apache.camel.util.IOHelper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class FileLockClusterView extends AbstractCamelClusterView { + private static final Logger LOGGER = LoggerFactory.getLogger(FileLockClusterView.class); + + private final ClusterMember localMember; + private final Path path; + private RandomAccessFile file; + private FileChannel channel; + private FileLock lock; + private ScheduledFuture<?> task; + + FileLockClusterView(FileLockClusterService cluster, String namespace) { + super(cluster, namespace); + + this.localMember = new ClusterMember(); + this.path = Paths.get(cluster.getRoot(), namespace); + + } + + @Override + public Optional<CamelClusterMember> getMaster() { + return Optional.of(this.localMember); + } + + @Override + public CamelClusterMember getLocalMember() { + return this.localMember; + } + + @Override + public List<CamelClusterMember> getMembers() { + // It may be useful to lock only a region of the file an then have views + // appending their id to the file on different regions so we can + // have a list of members. Root/Header region that is used for locking + // purpose may also contains the lock holder. + return Collections.emptyList(); + } + + @Override + protected void doStart() throws Exception { + if (file != null) { + close(); + + fireLeadershipChangedEvent(Optional.empty()); + } + + if (!Files.exists(path.getParent())) { + Files.createDirectories(path.getParent()); + } + + file = new RandomAccessFile(path.toFile(), "rw"); + channel = file.getChannel(); + + FileLockClusterService service = getClusterService().unwrap(FileLockClusterService.class); + ScheduledExecutorService executor = service.getExecutor(); + + task = executor.scheduleAtFixedRate( + this::tryLock, + TimeUnit.MILLISECONDS.convert(service.getAcquireLockDelay(), service.getAcquireLockDelayUnit()), + TimeUnit.MILLISECONDS.convert(service.getAcquireLockInterval(), service.getAcquireLockIntervalUnit()), + TimeUnit.MILLISECONDS + ); + } + + @Override + protected void doStop() throws Exception { + close(); + } + + // ********************************* + // + // ********************************* + + private void close() throws Exception { + if (task != null) { + task.cancel(true); + } + + if (lock != null) { + lock.release(); + } + + if (file != null) { + IOHelper.close(channel); + IOHelper.close(file); + + channel = null; + file = null; + } + } + + private void tryLock() { + if (isStarting() || isStarted()) { + try { + if (localMember.isLeader()) { + LOGGER.trace("Holding the lock on file {} (lock={})", path, lock); + return; + } + + synchronized (FileLockClusterView.this) { + if (lock != null) { + LOGGER.info("Lock on file {} lost (lock={})", path, lock); + fireLeadershipChangedEvent(Optional.empty()); + } + + LOGGER.debug("Try to acquire a lock on {}", path); + + lock = null; + lock = channel.tryLock(); + + if (lock != null) { + LOGGER.info("Lock on file {} acquired (lock={})", path, lock); + fireLeadershipChangedEvent(Optional.of(localMember)); + } else { + LOGGER.debug("Lock on file {} not acquired ", path); + } + } + } catch (OverlappingFileLockException e) { + LOGGER.debug("Lock on file {} not acquired ", path); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + } + + private final class ClusterMember implements CamelClusterMember { + @Override + public boolean isLeader() { + synchronized (FileLockClusterView.this) { + return lock != null && lock.isValid(); + } + } + + @Override + public boolean isLocal() { + return true; + } + + @Override + public String getId() { + return getClusterService().getId(); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/300c1277/camel-core/src/test/java/org/apache/camel/component/file/ha/FileLockClusteredRoutePolicyTest.java ---------------------------------------------------------------------- diff --git a/camel-core/src/test/java/org/apache/camel/component/file/ha/FileLockClusteredRoutePolicyTest.java b/camel-core/src/test/java/org/apache/camel/component/file/ha/FileLockClusteredRoutePolicyTest.java new file mode 100644 index 0000000..3e19566 --- /dev/null +++ b/camel-core/src/test/java/org/apache/camel/component/file/ha/FileLockClusteredRoutePolicyTest.java @@ -0,0 +1,108 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.file.ha; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ThreadLocalRandom; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.DefaultCamelContext; +import org.apache.camel.impl.ha.ClusteredRoutePolicyFactory; +import org.junit.Assert; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class FileLockClusteredRoutePolicyTest { + private static final Logger LOGGER = LoggerFactory.getLogger(FileLockClusteredRoutePolicyTest.class); + private static final List<String> CLIENTS = IntStream.range(0, 3).mapToObj(Integer::toString).collect(Collectors.toList()); + private static final List<String> RESULTS = new ArrayList<>(); + private static final ScheduledExecutorService SCHEDULER = Executors.newScheduledThreadPool(CLIENTS.size()); + private static final CountDownLatch LATCH = new CountDownLatch(CLIENTS.size()); + + // ************************************ + // Test + // ************************************ + + @Test + public void test() throws Exception { + for (String id : CLIENTS) { + SCHEDULER.submit(() -> run(id)); + } + + LATCH.await(1, TimeUnit.MINUTES); + SCHEDULER.shutdownNow(); + + Assert.assertEquals(CLIENTS.size(), RESULTS.size()); + Assert.assertTrue(RESULTS.containsAll(CLIENTS)); + } + + // ************************************ + // Run a Camel node + // ************************************ + + private static void run(String id) { + try { + int events = ThreadLocalRandom.current().nextInt(2, 6); + CountDownLatch contextLatch = new CountDownLatch(events); + + FileLockClusterService service = new FileLockClusterService(); + service.setId("node-" + id); + service.setRoot("target/ha"); + service.setAcquireLockDelay(1, TimeUnit.SECONDS); + service.setAcquireLockInterval(1, TimeUnit.SECONDS); + + DefaultCamelContext context = new DefaultCamelContext(); + context.disableJMX(); + context.setName("context-" + id); + context.addService(service); + context.addRoutePolicyFactory(ClusteredRoutePolicyFactory.forNamespace("my-ns")); + context.addRoutes(new RouteBuilder() { + @Override + public void configure() throws Exception { + from("timer:file-lock?delay=1s&period=1s") + .routeId("route-" + id) + .log("From ${routeId}") + .process(e -> contextLatch.countDown()); + } + }); + + // Start the context after some random time so the startup order + // changes for each test. + Thread.sleep(ThreadLocalRandom.current().nextInt(500)); + context.start(); + + contextLatch.await(); + + LOGGER.debug("Shutting down node {}", id); + RESULTS.add(id); + + context.stop(); + + LATCH.countDown(); + } catch (Exception e) { + LOGGER.warn("", e); + } + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/300c1277/camel-core/src/test/resources/log4j2.properties ---------------------------------------------------------------------- diff --git a/camel-core/src/test/resources/log4j2.properties b/camel-core/src/test/resources/log4j2.properties index 98bc5d1..85f3188 100644 --- a/camel-core/src/test/resources/log4j2.properties +++ b/camel-core/src/test/resources/log4j2.properties @@ -37,10 +37,13 @@ logger.customlogger.name = org.apache.camel.customlogger logger.customlogger.level = TRACE logger.customlogger.appenderRef.file2.ref = file2 +logger.file-ha.name = org.apache.camel.component.file.ha +logger.file-ha.level = DEBUG + rootLogger.level = INFO rootLogger.appenderRef.file.ref = file -#rootLogger.appenderRef.file.ref = console +#rootLogger.appenderRef.console.ref = console #logger.camel-core.name = org.apache.camel.impl #logger.camel-core.level = DEBUG http://git-wip-us.apache.org/repos/asf/camel/blob/300c1277/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/file/springboot/ha/FileLockClusterServiceAutoConfiguration.java ---------------------------------------------------------------------- diff --git a/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/file/springboot/ha/FileLockClusterServiceAutoConfiguration.java b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/file/springboot/ha/FileLockClusterServiceAutoConfiguration.java new file mode 100644 index 0000000..689127e --- /dev/null +++ b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/file/springboot/ha/FileLockClusterServiceAutoConfiguration.java @@ -0,0 +1,65 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.file.springboot.ha; + + +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +import org.apache.camel.component.file.ha.FileLockClusterService; +import org.apache.camel.converter.TimePatternConverter; +import org.apache.camel.ha.CamelClusterService; +import org.apache.camel.spring.boot.CamelAutoConfiguration; +import org.apache.camel.spring.boot.ha.ClusteredRouteControllerAutoConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.config.ConfigurableBeanFactory; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; + +@Configuration +@AutoConfigureBefore({ ClusteredRouteControllerAutoConfiguration.class, CamelAutoConfiguration.class }) +@ConditionalOnProperty(prefix = "camel.component.file.cluster.service", name = "enabled") +@EnableConfigurationProperties(FileLockClusterServiceConfiguration.class) +public class FileLockClusterServiceAutoConfiguration { + @Autowired + private FileLockClusterServiceConfiguration configuration; + + @Bean(initMethod = "start", destroyMethod = "stop") + @Scope(ConfigurableBeanFactory.SCOPE_SINGLETON) + @ConditionalOnMissingBean + public CamelClusterService consulClusterService() throws Exception { + FileLockClusterService service = new FileLockClusterService(); + + Optional.ofNullable(configuration.getId()) + .ifPresent(service::setId); + Optional.ofNullable(configuration.getRoot()) + .ifPresent(service::setRoot); + Optional.ofNullable(configuration.getAcquireLockDelay()) + .map(TimePatternConverter::toMilliSeconds) + .ifPresent(v -> service.setAcquireLockDelay(v, TimeUnit.MILLISECONDS)); + Optional.ofNullable(configuration.getAcquireLockInterval()) + .map(TimePatternConverter::toMilliSeconds) + .ifPresent(v -> service.setAcquireLockInterval(v, TimeUnit.MILLISECONDS)); + + return service; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/300c1277/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/file/springboot/ha/FileLockClusterServiceConfiguration.java ---------------------------------------------------------------------- diff --git a/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/file/springboot/ha/FileLockClusterServiceConfiguration.java b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/file/springboot/ha/FileLockClusterServiceConfiguration.java new file mode 100644 index 0000000..3ef175e --- /dev/null +++ b/platforms/spring-boot/components-starter/camel-core-starter/src/main/java/org/apache/camel/component/file/springboot/ha/FileLockClusterServiceConfiguration.java @@ -0,0 +1,87 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.camel.component.file.springboot.ha; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +@ConfigurationProperties(prefix = "camel.component.file.cluster.service") +public class FileLockClusterServiceConfiguration { + /** + * Sets if the zookeeper cluster service should be enabled or not, default is false. + */ + private boolean enabled; + + /** + * Cluster Service ID + */ + private String id; + + /** + * The root path. + */ + private String root; + + /** + * The time to wait before starting to try to acquire lock. + */ + private String acquireLockDelay; + + /** + * The time to wait between attempts to try to acquire lock. + */ + private String acquireLockInterval; + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getRoot() { + return root; + } + + public void setRoot(String root) { + this.root = root; + } + + public String getAcquireLockDelay() { + return acquireLockDelay; + } + + public void setAcquireLockDelay(String acquireLockDelay) { + this.acquireLockDelay = acquireLockDelay; + } + + public String getAcquireLockInterval() { + return acquireLockInterval; + } + + public void setAcquireLockInterval(String acquireLockInterval) { + this.acquireLockInterval = acquireLockInterval; + } +} http://git-wip-us.apache.org/repos/asf/camel/blob/300c1277/platforms/spring-boot/components-starter/camel-core-starter/src/main/resources/META-INF/spring.factories ---------------------------------------------------------------------- diff --git a/platforms/spring-boot/components-starter/camel-core-starter/src/main/resources/META-INF/spring.factories b/platforms/spring-boot/components-starter/camel-core-starter/src/main/resources/META-INF/spring.factories index 253b608..800582d 100644 --- a/platforms/spring-boot/components-starter/camel-core-starter/src/main/resources/META-INF/spring.factories +++ b/platforms/spring-boot/components-starter/camel-core-starter/src/main/resources/META-INF/spring.factories @@ -46,6 +46,7 @@ org.apache.camel.component.mock.springboot.MockComponentAutoConfiguration,\ org.apache.camel.component.browse.springboot.BrowseComponentAutoConfiguration,\ org.apache.camel.component.language.springboot.LanguageComponentAutoConfiguration,\ org.apache.camel.component.file.springboot.FileComponentAutoConfiguration,\ +org.apache.camel.component.file.springboot.ha.FileLockClusterServiceAutoConfiguration,\ org.apache.camel.component.timer.springboot.TimerComponentAutoConfiguration,\ org.apache.camel.component.test.springboot.TestComponentAutoConfiguration,\ org.apache.camel.component.beanclass.springboot.ClassComponentAutoConfiguration,\