You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/08/29 14:17:19 UTC
(camel) 05/06: CAMEL-21140: camel-core - Add init/destroy method support for registry bind
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch init-destroy
in repository https://gitbox.apache.org/repos/asf/camel.git
commit d31aba86fb3ce66e8366018b29f4649ef3ee8d83
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Thu Aug 29 15:46:25 2024 +0200
CAMEL-21140: camel-core - Add init/destroy method support for registry bind
---
.../main/java/org/apache/camel/BindToRegistry.java | 10 ++++++++
.../CamelDependencyInjectionAnnotationFactory.java | 5 +++-
.../impl/engine/DefaultCamelBeanPostProcessor.java | 29 ++++++++++++++--------
...efaultDependencyInjectionAnnotationFactory.java | 6 +++--
.../org/apache/camel/support/DefaultRegistry.java | 12 ++++-----
.../camel/support/scan/PackageScanHelper.java | 20 +++++++++++++--
6 files changed, 60 insertions(+), 22 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 7cf2bd2d43f..15ea5a3cf65 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
@@ -52,4 +52,14 @@ public @interface BindToRegistry {
* only need to create beans if they are explicit in-use.
*/
boolean lazy() default false;
+
+ /**
+ * The optional name of a method to call on the bean instance during initialization.
+ */
+ String initMethod() default "";
+
+ /**
+ * The optional name of a method to call on the bean instance during destruction.
+ */
+ String destroyMethod() default "";
}
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 1eb23532078..5ea4d40770a 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
@@ -30,10 +30,13 @@ public interface CamelDependencyInjectionAnnotationFactory {
* @param beanName the bean name
* @param beanType the bean type (optional)
* @param beanPostProcess whether bean post processor should be performed
+ * @param initMethod optional init method (invoked at bind)
+ * @param destroyMethod optional destroy method (invoked at unbind or stopping Camel)
* @return the created task to use for binding the bean
*/
Runnable createBindToRegistryFactory(
String id, Object bean, Class<?> beanType,
- String beanName, boolean beanPostProcess);
+ String beanName, boolean beanPostProcess,
+ String initMethod, String destroyMethod);
}
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 e56ba6a462a..12c14e21507 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
@@ -300,7 +300,8 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
BindToRegistry bind = field.getAnnotation(BindToRegistry.class);
if (bind != null) {
- bindToRegistry(field, bind.value(), bean, beanName, bind.beanPostProcess(), false);
+ bindToRegistry(field, bind.value(), bean, beanName, bind.beanPostProcess(), false, bind.initMethod(),
+ bind.destroyMethod());
}
});
}
@@ -405,7 +406,8 @@ 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(), bind.lazy());
+ bindToRegistry(method, bind.value(), bean, beanName, bind.beanPostProcess(), bind.lazy(), bind.initMethod(),
+ bind.destroyMethod());
});
}
@@ -413,7 +415,8 @@ 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(), ann.lazy());
+ bindToRegistry(clazz, ann.value(), bean, beanName, ann.beanPostProcess(), ann.lazy(), ann.initMethod(),
+ ann.destroyMethod());
}
}
@@ -422,7 +425,8 @@ 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(), ann.lazy());
+ bindToRegistry(clazz, ann.value(), null, null, ann.beanPostProcess(), ann.lazy(), ann.initMethod(),
+ ann.destroyMethod());
}
});
}
@@ -505,7 +509,8 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
private void bindToRegistry(
Class<?> clazz, String name, Object bean, String beanName,
- boolean beanPostProcess, boolean lazy) {
+ boolean beanPostProcess, boolean lazy,
+ String initMethod, String destroyMethod) {
if (isEmpty(name)) {
name = clazz.getSimpleName();
}
@@ -536,13 +541,14 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
}
// use dependency injection factory to perform the task of binding the bean to registry
Runnable task = PluginHelper.getDependencyInjectionAnnotationFactory(getOrLookupCamelContext())
- .createBindToRegistryFactory(name, bean, clazz, beanName, postProcess);
+ .createBindToRegistryFactory(name, bean, clazz, beanName, postProcess, initMethod, destroyMethod);
task.run();
}
private void bindToRegistry(
Field field, String name, Object bean, String beanName,
- boolean beanPostProcess, boolean lazy) {
+ boolean beanPostProcess, boolean lazy,
+ String initMethod, String destroyMethod) {
if (isEmpty(name)) {
name = field.getName();
}
@@ -572,14 +578,16 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
}
// use dependency injection factory to perform the task of binding the bean to registry
Runnable task = PluginHelper.getDependencyInjectionAnnotationFactory(getOrLookupCamelContext())
- .createBindToRegistryFactory(name, value, field.getType(), beanName, postProcess);
+ .createBindToRegistryFactory(name, value, field.getType(), beanName, postProcess, initMethod,
+ destroyMethod);
task.run();
}
}
private void bindToRegistry(
Method method, String name, Object bean, String beanName,
- boolean beanPostProcess, boolean lazy) {
+ boolean beanPostProcess, boolean lazy,
+ String initMethod, String destroyMethod) {
if (isEmpty(name)) {
name = method.getName();
}
@@ -611,7 +619,8 @@ public class DefaultCamelBeanPostProcessor implements CamelBeanPostProcessor, Ca
}
// use dependency injection factory to perform the task of binding the bean to registry
Runnable task = PluginHelper.getDependencyInjectionAnnotationFactory(getOrLookupCamelContext())
- .createBindToRegistryFactory(name, value, method.getReturnType(), beanName, postProcess);
+ .createBindToRegistryFactory(name, value, method.getReturnType(), beanName, postProcess,
+ initMethod, destroyMethod);
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 1e1dcf70d11..fe6899f5b48 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
@@ -50,7 +50,8 @@ public class DefaultDependencyInjectionAnnotationFactory
@Override
@SuppressWarnings("unchecked")
public Runnable createBindToRegistryFactory(
- String id, Object bean, Class<?> beanType, String beanName, boolean beanPostProcess) {
+ String id, Object bean, Class<?> beanType, String beanName, boolean beanPostProcess,
+ String initMethod, String destroyMethod) {
return () -> {
if (beanPostProcess) {
try {
@@ -63,11 +64,12 @@ public class DefaultDependencyInjectionAnnotationFactory
}
CamelContextAware.trySetCamelContext(bean, camelContext);
if (bean instanceof Supplier) {
+ // TODO: supplier/lazy does not support init/destroy
// 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);
+ camelContext.getRegistry().bind(id, bean, initMethod, destroyMethod);
}
};
}
diff --git a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
index 521762ea480..b9036124e6e 100644
--- a/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
+++ b/core/camel-support/src/main/java/org/apache/camel/support/DefaultRegistry.java
@@ -42,6 +42,8 @@ import org.apache.camel.util.function.Suppliers;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import static org.apache.camel.util.ObjectHelper.isNotEmpty;
+
/**
* The default {@link Registry} which supports using a given first-choice repository to lookup the beans, such as
* Spring, JNDI, OSGi etc. And to use a secondary {@link SimpleRegistry} as the fallback repository to lookup and bind
@@ -180,11 +182,7 @@ public class DefaultRegistry extends ServiceSupport implements Registry, LocalBe
@Override
public void bind(String id, Class<?> type, Object bean) throws RuntimeCamelException {
- if (bean != null) {
- // automatic inject camel context in bean if its aware
- CamelContextAware.trySetCamelContext(bean, camelContext);
- fallbackRegistry.bind(id, type, bean);
- }
+ bind(id, type, bean, null, null);
}
@Override
@@ -193,7 +191,7 @@ public class DefaultRegistry extends ServiceSupport implements Registry, LocalBe
if (bean != null) {
// automatic inject camel context in bean if its aware
CamelContextAware.trySetCamelContext(bean, camelContext);
- if (initMethod != null) {
+ if (isNotEmpty(initMethod)) {
try {
org.apache.camel.support.ObjectHelper.invokeMethodSafe(initMethod, bean);
} catch (Exception e) {
@@ -201,7 +199,7 @@ public class DefaultRegistry extends ServiceSupport implements Registry, LocalBe
}
}
fallbackRegistry.bind(id, type, bean);
- if (destroyMethod != null) {
+ if (isNotEmpty(destroyMethod)) {
beansToDestroy.put(id, new KeyValueHolder<>(bean, destroyMethod));
}
}
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 4e927d221d8..e405e4550cd 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
@@ -33,6 +33,7 @@ import org.apache.camel.spi.Registry;
import org.apache.camel.support.PluginHelper;
import static org.apache.camel.util.ObjectHelper.isEmpty;
+import static org.apache.camel.util.ObjectHelper.isNotEmpty;
/**
* Helper for Camel package scanning.
@@ -58,6 +59,7 @@ public class PackageScanHelper {
Injector injector = camelContext.getInjector();
if (scanner != null && injector != null) {
Map<Class<?>, Object> created = new HashMap<>();
+ Map<Object, String> initMethods = new HashMap<>();
Set<Class<?>> lazy = new HashSet<>();
for (String pkg : packages) {
Set<Class<?>> classes = scanner.findAnnotated(BindToRegistry.class, pkg);
@@ -100,7 +102,7 @@ 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, c, beanName, false);
+ .createBindToRegistryFactory(name, bean, c, beanName, false, null, null);
task.run();
}
}
@@ -118,7 +120,11 @@ 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, c, beanName, false);
+ .createBindToRegistryFactory(name, bean, c, beanName, false, null, ann.destroyMethod());
+ // defer calling init methods until dependency injection in phase-4 is complete
+ if (isNotEmpty(ann.initMethod())) {
+ initMethods.put(bean, ann.initMethod());
+ }
task.run();
}
}
@@ -138,6 +144,16 @@ public class PackageScanHelper {
throw new RuntimeCamelException("Error post-processing bean: " + beanName, e);
}
}
+ for (Entry<Object, String> entry : initMethods.entrySet()) {
+ Object bean = entry.getKey();
+ String method = entry.getValue();
+ // phase-5: now call init method on created beans
+ try {
+ org.apache.camel.support.ObjectHelper.invokeMethodSafe(method, bean);
+ } catch (Exception e) {
+ throw RuntimeCamelException.wrapRuntimeCamelException(e);
+ }
+ }
}
}
}