This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 951d29d0451 Add lazy option to @BindToRegistry (#15361)
951d29d0451 is described below
commit 951d29d0451f5a3c28ef862a6f6dd6f28caced95
Author: Claus Ibsen <[email protected]>
AuthorDate: Thu Aug 29 10:32:44 2024 +0200
Add lazy option to @BindToRegistry (#15361)
* CAMEL-21137: camel-core - Add lazy option to @BindToRegistry
---
.../main/java/org/apache/camel/BindToRegistry.java | 10 ++-
.../CamelDependencyInjectionAnnotationFactory.java | 5 +-
.../impl/engine/DefaultCamelBeanPostProcessor.java | 98 ++++++++++++++++++----
...efaultDependencyInjectionAnnotationFactory.java | 15 +++-
.../impl/BindToRegistryBeanLazyMethodTest.java | 73 ++++++++++++++++
.../camel/impl/BindToRegistryBeanLazyTest.java | 70 ++++++++++++++++
.../camel/support/scan/PackageScanHelper.java | 54 ++++++++++--
.../dsl/java/joor/JavaRoutesBuilderLoader.java | 4 +-
.../injection/AnnotationDependencyInjection.java | 69 +++++++++------
9 files changed, 342 insertions(+), 56 deletions(-)
diff --git a/core/camel-api/src/main/java/org/apache/camel/BindToRegistry.java
b/core/camel-api/src/main/java/org/apache/camel/BindToRegistry.java
index f60ccbe05d8..7cf2bd2d43f 100644
--- a/core/camel-api/src/main/java/org/apache/camel/BindToRegistry.java
+++ b/core/camel-api/src/main/java/org/apache/camel/BindToRegistry.java
@@ -26,7 +26,7 @@ import java.lang.annotation.Target;
* Used for binding a bean to the registry.
*
* This annotation is not supported with camel-spring or camel-spring-boot as
they have their own set of annotations for
- * registering beans in spring bean registry. Instead this annotation is
intended for Camel standalone such as
+ * registering beans in spring bean registry. Instead, this annotation is
intended for Camel standalone such as
* camel-main or camel-quarkus or similar runtimes.
*
* If no name is specified then the bean will have its name auto computed
based on the class name, field name, or method
@@ -43,7 +43,13 @@ public @interface BindToRegistry {
String value() default "";
/**
- * Whether to perform bean post processing (dependency injection) on the
bean
+ * Whether to perform bean post-processing (dependency injection) on the
bean
*/
boolean beanPostProcess() default false;
+
+ /**
+ * Whether to create the bean instance lazy (on-demand) instead of
creating eager. Using lazy can be useful when you
+ * only need to create beans if they are explicit in-use.
+ */
+ boolean lazy() default false;
}
diff --git
a/core/camel-api/src/main/java/org/apache/camel/spi/CamelDependencyInjectionAnnotationFactory.java
b/core/camel-api/src/main/java/org/apache/camel/spi/CamelDependencyInjectionAnnotationFactory.java
index 47d2e204248..1eb23532078 100644
---
a/core/camel-api/src/main/java/org/apache/camel/spi/CamelDependencyInjectionAnnotationFactory.java
+++
b/core/camel-api/src/main/java/org/apache/camel/spi/CamelDependencyInjectionAnnotationFactory.java
@@ -28,9 +28,12 @@ public interface CamelDependencyInjectionAnnotationFactory {
* @param id the bean id
* @param bean the bean instance
* @param beanName the bean name
+ * @param beanType the bean type (optional)
* @param beanPostProcess whether bean post processor should be performed
* @return the created task to use for binding the bean
*/
- Runnable createBindToRegistryFactory(String id, Object bean, String
beanName, boolean beanPostProcess);
+ Runnable createBindToRegistryFactory(
+ String id, Object bean, Class<?> beanType,
+ String beanName, boolean beanPostProcess);
}
diff --git
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
index 6d05404ddbf..c9b146dc40b 100644
---
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
+++
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultCamelBeanPostProcessor.java
@@ -23,6 +23,7 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Function;
+import java.util.function.Supplier;
import org.apache.camel.BeanConfigInject;
import org.apache.camel.BeanInject;
@@ -33,6 +34,7 @@ import org.apache.camel.DeferredContextBinding;
import org.apache.camel.EndpointInject;
import org.apache.camel.Produce;
import org.apache.camel.PropertyInject;
+import org.apache.camel.RuntimeCamelException;
import org.apache.camel.spi.CamelBeanPostProcessor;
import org.apache.camel.spi.CamelBeanPostProcessorInjector;
import org.apache.camel.support.DefaultEndpoint;
@@ -298,7 +300,7 @@ public class DefaultCamelBeanPostProcessor implements
CamelBeanPostProcessor, Ca
BindToRegistry bind = field.getAnnotation(BindToRegistry.class);
if (bind != null) {
- bindToRegistry(field, bind.value(), bean, beanName,
bind.beanPostProcess());
+ bindToRegistry(field, bind.value(), bean, beanName,
bind.beanPostProcess(), false);
}
});
}
@@ -403,7 +405,7 @@ public class DefaultCamelBeanPostProcessor implements
CamelBeanPostProcessor, Ca
// bind each method
methods.forEach(method -> {
BindToRegistry bind = method.getAnnotation(BindToRegistry.class);
- bindToRegistry(method, bind.value(), bean, beanName,
bind.beanPostProcess());
+ bindToRegistry(method, bind.value(), bean, beanName,
bind.beanPostProcess(), bind.lazy());
});
}
@@ -411,7 +413,7 @@ public class DefaultCamelBeanPostProcessor implements
CamelBeanPostProcessor, Ca
Class<?> clazz = bean.getClass();
BindToRegistry ann = clazz.getAnnotation(BindToRegistry.class);
if (ann != null) {
- bindToRegistry(clazz, ann.value(), bean, beanName,
ann.beanPostProcess());
+ bindToRegistry(clazz, ann.value(), bean, beanName,
ann.beanPostProcess(), ann.lazy());
}
}
@@ -420,7 +422,7 @@ public class DefaultCamelBeanPostProcessor implements
CamelBeanPostProcessor, Ca
BindToRegistry ann = clazz.getAnnotation(BindToRegistry.class);
if (ann != null) {
// it is a nested class so we don't have a bean instance for it
- bindToRegistry(clazz, ann.value(), null, null,
ann.beanPostProcess());
+ bindToRegistry(clazz, ann.value(), null, null,
ann.beanPostProcess(), ann.lazy());
}
});
}
@@ -501,55 +503,115 @@ public class DefaultCamelBeanPostProcessor implements
CamelBeanPostProcessor, Ca
}
}
- private void bindToRegistry(Class<?> clazz, String name, Object bean,
String beanName, boolean beanPostProcess) {
+ private void bindToRegistry(
+ Class<?> clazz, String name, Object bean, String beanName,
+ boolean beanPostProcess, boolean lazy) {
if (isEmpty(name)) {
name = clazz.getSimpleName();
}
+ boolean postProcess = beanPostProcess;
if (bean == null) {
- // no bean so then create an instance from its type
- bean = getOrLookupCamelContext().getInjector().newInstance(clazz);
+ if (lazy) {
+ postProcess = false; // we do post-processing lazy
+ bean = (Supplier<Object>) () -> {
+ Object answer =
getOrLookupCamelContext().getInjector().newInstance(clazz);
+ if (answer != null && beanPostProcess) {
+ try {
+ final CamelBeanPostProcessor beanPostProcessor =
PluginHelper.getBeanPostProcessor(camelContext);
+
beanPostProcessor.postProcessBeforeInitialization(answer, beanName);
+
beanPostProcessor.postProcessAfterInitialization(answer, beanName);
+ } catch (Exception e) {
+ throw
RuntimeCamelException.wrapRuntimeException(e);
+ }
+ }
+ return answer;
+ };
+ } else {
+ // no bean so then create an instance from its type
+ bean =
getOrLookupCamelContext().getInjector().newInstance(clazz);
+ }
}
-
if (unbindEnabled) {
getOrLookupCamelContext().getRegistry().unbind(name);
}
// use dependency injection factory to perform the task of binding the
bean to registry
Runnable task =
PluginHelper.getDependencyInjectionAnnotationFactory(getOrLookupCamelContext())
- .createBindToRegistryFactory(name, bean, beanName,
beanPostProcess);
+ .createBindToRegistryFactory(name, bean, clazz, beanName,
postProcess);
task.run();
}
- private void bindToRegistry(Field field, String name, Object bean, String
beanName, boolean beanPostProcess) {
+ private void bindToRegistry(
+ Field field, String name, Object bean, String beanName,
+ boolean beanPostProcess, boolean lazy) {
if (isEmpty(name)) {
name = field.getName();
}
- Object value = ReflectionHelper.getField(field, bean);
-
+ boolean postProcess = beanPostProcess;
+ Object value;
+ if (lazy) {
+ postProcess = false; // we do post-processing lazy
+ value = (Supplier<Object>) () -> {
+ Object answer = ReflectionHelper.getField(field, bean);
+ if (answer != null && beanPostProcess) {
+ try {
+ final CamelBeanPostProcessor beanPostProcessor =
PluginHelper.getBeanPostProcessor(camelContext);
+
beanPostProcessor.postProcessBeforeInitialization(answer, beanName);
+
beanPostProcessor.postProcessAfterInitialization(answer, beanName);
+ } catch (Exception e) {
+ throw RuntimeCamelException.wrapRuntimeException(e);
+ }
+ }
+ return answer;
+ };
+ } else {
+ value = ReflectionHelper.getField(field, bean);
+ }
if (value != null) {
if (unbindEnabled) {
getOrLookupCamelContext().getRegistry().unbind(name);
}
// use dependency injection factory to perform the task of binding
the bean to registry
Runnable task =
PluginHelper.getDependencyInjectionAnnotationFactory(getOrLookupCamelContext())
- .createBindToRegistryFactory(name, value, beanName,
beanPostProcess);
+ .createBindToRegistryFactory(name, value, field.getType(),
beanName, postProcess);
task.run();
}
}
- private void bindToRegistry(Method method, String name, Object bean,
String beanName, boolean beanPostProcess) {
+ private void bindToRegistry(
+ Method method, String name, Object bean, String beanName,
+ boolean beanPostProcess, boolean lazy) {
if (isEmpty(name)) {
name = method.getName();
}
- Object value = getPostProcessorHelper()
- .getInjectionBeanMethodValue(getOrLookupCamelContext(),
method, bean, beanName);
-
+ boolean postProcess = beanPostProcess;
+ Object value;
+ if (lazy) {
+ postProcess = false; // we do post-processing lazy
+ value = (Supplier<Object>) () -> {
+ Object answer = getPostProcessorHelper()
+
.getInjectionBeanMethodValue(getOrLookupCamelContext(), method, bean, beanName);
+ if (answer != null && beanPostProcess) {
+ try {
+ final CamelBeanPostProcessor beanPostProcessor =
PluginHelper.getBeanPostProcessor(camelContext);
+
beanPostProcessor.postProcessBeforeInitialization(answer, beanName);
+
beanPostProcessor.postProcessAfterInitialization(answer, beanName);
+ } catch (Exception e) {
+ throw RuntimeCamelException.wrapRuntimeException(e);
+ }
+ }
+ return answer;
+ };
+ } else {
+ value = getPostProcessorHelper()
+ .getInjectionBeanMethodValue(getOrLookupCamelContext(),
method, bean, beanName);
+ }
if (value != null) {
if (unbindEnabled) {
getOrLookupCamelContext().getRegistry().unbind(name);
}
// use dependency injection factory to perform the task of binding
the bean to registry
Runnable task =
PluginHelper.getDependencyInjectionAnnotationFactory(getOrLookupCamelContext())
- .createBindToRegistryFactory(name, value, beanName,
beanPostProcess);
+ .createBindToRegistryFactory(name, value,
method.getReturnType(), beanName, postProcess);
task.run();
}
}
diff --git
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultDependencyInjectionAnnotationFactory.java
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultDependencyInjectionAnnotationFactory.java
index a2b6fced400..1e1dcf70d11 100644
---
a/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultDependencyInjectionAnnotationFactory.java
+++
b/core/camel-base-engine/src/main/java/org/apache/camel/impl/engine/DefaultDependencyInjectionAnnotationFactory.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.impl.engine;
+import java.util.function.Supplier;
+
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.RuntimeCamelException;
@@ -46,12 +48,13 @@ public class DefaultDependencyInjectionAnnotationFactory
}
@Override
- public Runnable createBindToRegistryFactory(String id, Object bean, String
beanName, boolean beanPostProcess) {
+ @SuppressWarnings("unchecked")
+ public Runnable createBindToRegistryFactory(
+ String id, Object bean, Class<?> beanType, String beanName,
boolean beanPostProcess) {
return () -> {
if (beanPostProcess) {
try {
final CamelBeanPostProcessor beanPostProcessor =
PluginHelper.getBeanPostProcessor(camelContext);
-
beanPostProcessor.postProcessBeforeInitialization(bean,
beanName);
beanPostProcessor.postProcessAfterInitialization(bean,
beanName);
} catch (Exception e) {
@@ -59,7 +62,13 @@ public class DefaultDependencyInjectionAnnotationFactory
}
}
CamelContextAware.trySetCamelContext(bean, camelContext);
- camelContext.getRegistry().bind(id, bean);
+ if (bean instanceof Supplier) {
+ // must be Supplier<Object> to ensure correct binding
+ Supplier<Object> sup = (Supplier<Object>) bean;
+ camelContext.getRegistry().bind(id, beanType, sup);
+ } else {
+ camelContext.getRegistry().bind(id, bean);
+ }
};
}
}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/impl/BindToRegistryBeanLazyMethodTest.java
b/core/camel-core/src/test/java/org/apache/camel/impl/BindToRegistryBeanLazyMethodTest.java
new file mode 100644
index 00000000000..c38e21be9d0
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/impl/BindToRegistryBeanLazyMethodTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.impl;
+
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.support.PluginHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+public class BindToRegistryBeanLazyMethodTest extends ContextTestSupport {
+
+ private String hello = "Hello World";
+
+ @BindToRegistry(lazy = false)
+ public FooService myEager() {
+ return new FooService(hello);
+ }
+
+ @BindToRegistry(lazy = true)
+ public FooService myLazy() {
+ return new FooService(hello);
+ }
+
+ @Test
+ public void testLazy() throws Exception {
+ // bean post processing dont run on ContextTestSupport
+ CamelBeanPostProcessor cbpp =
PluginHelper.getBeanPostProcessor(context);
+ cbpp.postProcessBeforeInitialization(this, "this");
+ cbpp.postProcessAfterInitialization(this, "this");
+
+ // change message which should only affect lazy
+ hello = "Bye World";
+
+ FooService eager =
context.getRegistry().lookupByNameAndType("myEager", FooService.class);
+ assertNotNull(eager);
+ assertEquals("Hello World", eager.getMessage());
+
+ FooService lazy = context.getRegistry().lookupByNameAndType("myLazy",
FooService.class);
+ assertNotNull(lazy);
+ assertEquals("Bye World", lazy.getMessage());
+ }
+
+ public static class FooService {
+
+ private final String message;
+
+ public FooService(String message) {
+ this.message = message;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+ }
+}
diff --git
a/core/camel-core/src/test/java/org/apache/camel/impl/BindToRegistryBeanLazyTest.java
b/core/camel-core/src/test/java/org/apache/camel/impl/BindToRegistryBeanLazyTest.java
new file mode 100644
index 00000000000..b36d643e16d
--- /dev/null
+++
b/core/camel-core/src/test/java/org/apache/camel/impl/BindToRegistryBeanLazyTest.java
@@ -0,0 +1,70 @@
+/*
+ * 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.impl;
+
+import org.apache.camel.BeanInject;
+import org.apache.camel.BindToRegistry;
+import org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.spi.CamelBeanPostProcessor;
+import org.apache.camel.support.PluginHelper;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertSame;
+
+public class BindToRegistryBeanLazyTest extends ContextTestSupport {
+
+ // field
+ @BindToRegistry(lazy = true, beanPostProcess = true)
+ private final FooService foo = new FooService();
+
+ // method
+ @BindToRegistry(lazy = true, beanPostProcess = true)
+ public FooService myOtherFoo() {
+ return new FooService();
+ }
+
+ @Test
+ public void testPostProcessor() throws Exception {
+ // bean post processing dont run on ContextTestSupport
+ CamelBeanPostProcessor cbpp =
PluginHelper.getBeanPostProcessor(context);
+ cbpp.postProcessBeforeInitialization(this, "this");
+ cbpp.postProcessAfterInitialization(this, "this");
+
+ assertNotNull(foo);
+ assertSame(context, foo.getCamelContext());
+
+ FooService other = (FooService)
context.getRegistry().lookupByName("myOtherFoo");
+ assertNotNull(other);
+ assertSame(context, other.getCamelContext());
+ }
+
+ public static class FooService {
+
+ @BeanInject
+ private CamelContext camelContext;
+
+ public CamelContext getCamelContext() {
+ return camelContext;
+ }
+
+ public void setCamelContext(CamelContext camelContext) {
+ this.camelContext = camelContext;
+ }
+ }
+}
diff --git
a/core/camel-support/src/main/java/org/apache/camel/support/scan/PackageScanHelper.java
b/core/camel-support/src/main/java/org/apache/camel/support/scan/PackageScanHelper.java
index ffc8c9fb394..4e927d221d8 100644
---
a/core/camel-support/src/main/java/org/apache/camel/support/scan/PackageScanHelper.java
+++
b/core/camel-support/src/main/java/org/apache/camel/support/scan/PackageScanHelper.java
@@ -17,13 +17,16 @@
package org.apache.camel.support.scan;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.function.Supplier;
import org.apache.camel.BindToRegistry;
import org.apache.camel.CamelContext;
import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.spi.CamelBeanPostProcessor;
import org.apache.camel.spi.Injector;
import org.apache.camel.spi.PackageScanClassResolver;
import org.apache.camel.spi.Registry;
@@ -55,18 +58,55 @@ public class PackageScanHelper {
Injector injector = camelContext.getInjector();
if (scanner != null && injector != null) {
Map<Class<?>, Object> created = new HashMap<>();
+ Set<Class<?>> lazy = new HashSet<>();
for (String pkg : packages) {
Set<Class<?>> classes =
scanner.findAnnotated(BindToRegistry.class, pkg);
for (Class<?> c : classes) {
- // phase-1: create empty bean instance without any
bean post-processing
- Object b = injector.newInstance(c, false);
- if (b != null) {
- created.put(c, b);
+ BindToRegistry ann =
c.getAnnotation(BindToRegistry.class);
+ if (ann != null && ann.lazy()) {
+ // phase-1: remember lazy creating beans
+ lazy.add(c);
+ } else {
+ // phase-1: create empty bean instance without
any bean post-processing
+ Object b = injector.newInstance(c, false);
+ if (b != null) {
+ created.put(c, b);
+ }
+ }
+ }
+ for (Class<?> c : lazy) {
+ // phase-2: special for lazy beans that must be
registered and created on-demand
+ BindToRegistry ann =
c.getAnnotation(BindToRegistry.class);
+ if (ann != null) {
+ String name = ann.value();
+ if (isEmpty(name)) {
+ name = c.getSimpleName();
+ }
+ String beanName = c.getName();
+ Object bean = (Supplier<Object>) () -> {
+ Object answer = injector.newInstance(c);
+ if (answer != null &&
ann.beanPostProcess()) {
+ try {
+ final CamelBeanPostProcessor
beanPostProcessor
+ =
PluginHelper.getBeanPostProcessor(camelContext);
+
beanPostProcessor.postProcessBeforeInitialization(answer, beanName);
+
beanPostProcessor.postProcessAfterInitialization(answer, beanName);
+ } catch (Exception e) {
+ throw
RuntimeCamelException.wrapRuntimeException(e);
+ }
+ }
+ return answer;
+ };
+ // - bind to registry if
@org.apache.camel.BindToRegistry is present
+ // use dependency injection factory to perform
the task of binding the bean to registry
+ Runnable task =
PluginHelper.getDependencyInjectionAnnotationFactory(camelContext)
+ .createBindToRegistryFactory(name,
bean, c, beanName, false);
+ task.run();
}
}
for (Entry<Class<?>, Object> entry :
created.entrySet()) {
Class<?> c = entry.getKey();
- // phase-2: discover any created beans has
@BindToRegistry to register them eager
+ // phase-3: discover any created beans has
@BindToRegistry to register them eager
BindToRegistry ann =
c.getAnnotation(BindToRegistry.class);
if (ann != null) {
String name = ann.value();
@@ -78,13 +118,13 @@ public class PackageScanHelper {
// - bind to registry if
@org.apache.camel.BindToRegistry is present
// use dependency injection factory to perform
the task of binding the bean to registry
Runnable task =
PluginHelper.getDependencyInjectionAnnotationFactory(camelContext)
- .createBindToRegistryFactory(name,
bean, beanName, false);
+ .createBindToRegistryFactory(name,
bean, c, beanName, false);
task.run();
}
}
for (Entry<Class<?>, Object> entry :
created.entrySet()) {
Class<?> c = entry.getKey();
- // phase-3: now we can do bean post-processing on
the created beans
+ // phase-4: now we can do bean post-processing on
the created beans
Object bean = entry.getValue();
String beanName = c.getName();
try {
diff --git
a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
index 317693f93bd..d805e559cd7 100644
---
a/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
+++
b/dsl/camel-java-joor-dsl/src/main/java/org/apache/camel/dsl/java/joor/JavaRoutesBuilderLoader.java
@@ -29,6 +29,7 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+import org.apache.camel.BindToRegistry;
import org.apache.camel.CamelContext;
import org.apache.camel.CamelContextAware;
import org.apache.camel.RoutesBuilder;
@@ -138,8 +139,9 @@ public class JavaRoutesBuilderLoader extends
ExtendedRouteBuilderLoaderSupport {
Class<?> clazz = result.getClass(className);
if (clazz != null) {
+ BindToRegistry bir = clazz.getAnnotation(BindToRegistry.class);
boolean skip = clazz.isInterface() ||
Modifier.isAbstract(clazz.getModifiers())
- || Modifier.isPrivate(clazz.getModifiers());
+ || Modifier.isPrivate(clazz.getModifiers()) || (bir !=
null && bir.lazy());
// must have a default no-arg constructor to be able to create
an instance
boolean ctr = ObjectHelper.hasDefaultNoArgConstructor(clazz);
if (ctr && !skip) {
diff --git
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/AnnotationDependencyInjection.java
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/AnnotationDependencyInjection.java
index 1d9ef7ace70..e042e6ecaa3 100644
---
a/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/AnnotationDependencyInjection.java
+++
b/dsl/camel-kamelet-main/src/main/java/org/apache/camel/main/injection/AnnotationDependencyInjection.java
@@ -20,6 +20,7 @@ import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
+import java.util.function.Supplier;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Produces;
@@ -136,31 +137,51 @@ public final class AnnotationDependencyInjection {
@Override
public void postCompile(CamelContext camelContext, String name,
Class<?> clazz, byte[] byteCode, Object instance)
throws Exception {
- if (instance == null) {
- return;
- }
- BindToRegistry bir =
instance.getClass().getAnnotation(BindToRegistry.class);
- Configuration cfg =
instance.getClass().getAnnotation(Configuration.class);
- if (bir != null || cfg != null || instance instanceof
CamelConfiguration) {
- CamelBeanPostProcessor bpp =
PluginHelper.getBeanPostProcessor(camelContext);
- if (bir != null && ObjectHelper.isNotEmpty(bir.value())) {
- name = bir.value();
- } else if (cfg != null &&
ObjectHelper.isNotEmpty(cfg.value())) {
- name = cfg.value();
- }
- // to support hot reloading of beans then we need to enable
unbind mode in bean post processor
- bpp.setUnbindEnabled(true);
- try {
- // this class uses camels own annotations so the bind to
registry happens
- // automatic by the bean post processor
- bpp.postProcessBeforeInitialization(instance, name);
- bpp.postProcessAfterInitialization(instance, name);
- } finally {
- bpp.setUnbindEnabled(false);
- }
- if (instance instanceof CamelConfiguration) {
- ((CamelConfiguration) instance).configure(camelContext);
+ BindToRegistry bir = clazz.getAnnotation(BindToRegistry.class);
+ Configuration cfg = clazz.getAnnotation(Configuration.class);
+
+ // special for lazy beans which we must create on-demand
+ if (instance == null && bir != null && bir.lazy()) {
+ final String beanName = bir.value();
+ instance = (Supplier<Object>) () -> {
+ Object answer =
camelContext.getInjector().newInstance(clazz);
+ CamelBeanPostProcessor bpp =
PluginHelper.getBeanPostProcessor(camelContext);
+ try {
+ bpp.postProcessBeforeInitialization(answer, beanName);
+ bpp.postProcessAfterInitialization(answer, beanName);
+ } catch (Exception e) {
+ throw RuntimeCamelException.wrapRuntimeException(e);
+ }
+ return answer;
+ };
+ // unbind old bean and register lazy bean
+ camelContext.getRegistry().unbind(beanName);
+ // use dependency injection factory to perform the task of
binding the bean to registry
+ Runnable task =
PluginHelper.getDependencyInjectionAnnotationFactory(camelContext)
+ .createBindToRegistryFactory(name, instance, clazz,
beanName, false);
+ task.run();
+ } else {
+ if (bir != null || cfg != null || instance instanceof
CamelConfiguration) {
+ CamelBeanPostProcessor bpp =
PluginHelper.getBeanPostProcessor(camelContext);
+ if (bir != null && ObjectHelper.isNotEmpty(bir.value())) {
+ name = bir.value();
+ } else if (cfg != null &&
ObjectHelper.isNotEmpty(cfg.value())) {
+ name = cfg.value();
+ }
+ // to support hot reloading of beans then we need to
enable unbind mode in bean post processor
+ bpp.setUnbindEnabled(true);
+ try {
+ // this class uses camels own annotations so the bind
to registry happens
+ // automatic by the bean post processor
+ bpp.postProcessBeforeInitialization(instance, name);
+ bpp.postProcessAfterInitialization(instance, name);
+ } finally {
+ bpp.setUnbindEnabled(false);
+ }
+ if (instance instanceof CamelConfiguration) {
+ ((CamelConfiguration)
instance).configure(camelContext);
+ }
}
}
}