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 52e3a5fb73d9 CAMEL-25767: camel-main - a properties file that changed 
in dev mode applies its beans and components (#28123)
52e3a5fb73d9 is described below

commit 52e3a5fb73d929c8dfa54328caff1f12404dfcb4
Author: Claus Ibsen <[email protected]>
AuthorDate: Mon Oct 19 20:27:39 2026 +0200

    CAMEL-25767: camel-main - a properties file that changed in dev mode 
applies its beans and components (#28123)
    
    Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
---
 .../org/apache/camel/spi/PropertiesReload.java     |  16 +++
 .../RouteWatcherReloadPropertiesLocationTest.java  | 111 +++++++++++++++
 .../org/apache/camel/main/BaseMainSupport.java     |  58 ++++++++
 .../apache/camel/main/MainPropertiesReload.java    |  12 +-
 .../camel/main/MainPropertiesReloadBeansTest.java  | 158 +++++++++++++++++++++
 .../camel/support/RouteWatcherReloadStrategy.java  |  49 ++++++-
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  19 +++
 7 files changed, 418 insertions(+), 5 deletions(-)

diff --git 
a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesReload.java 
b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesReload.java
index 457319c014ad..88fdef1f0143 100644
--- a/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesReload.java
+++ b/core/camel-api/src/main/java/org/apache/camel/spi/PropertiesReload.java
@@ -44,4 +44,20 @@ public interface PropertiesReload {
      */
     void onReload(String name, Properties properties) throws Exception;
 
+    /**
+     * Callback when a resource with properties changed and is re-loaded, such 
as a properties file that was saved while
+     * live reloading is enabled. Unlike {@link #onReload(String, 
Properties)}, the properties are only those that
+     * changed, as the user edited them, so a listener can tell which changes 
it cannot apply without a restart.
+     * <p/>
+     * The default calls {@link #onReload(String, Properties)}.
+     *
+     * @param  name       name of the resource such as the file name (absolute)
+     * @param  properties the properties that changed
+     * @throws Exception  error reloading properties
+     * @since             4.24
+     */
+    default void onChanged(String name, Properties properties) throws 
Exception {
+        onReload(name, properties);
+    }
+
 }
diff --git 
a/core/camel-core/src/test/java/org/apache/camel/support/RouteWatcherReloadPropertiesLocationTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/support/RouteWatcherReloadPropertiesLocationTest.java
new file mode 100644
index 000000000000..11bf60448572
--- /dev/null
+++ 
b/core/camel-core/src/test/java/org/apache/camel/support/RouteWatcherReloadPropertiesLocationTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.support;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.ContextTestSupport;
+import org.apache.camel.spi.PropertiesReload;
+import org.apache.camel.support.service.ServiceSupport;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * CAMEL-25767: a properties file that changed in dev mode is configured from. 
camel run --source-dir=. knows
+ * application.properties as file:./application.properties, and the file 
watcher reports file:application.properties:
+ * the two were compared as text, so the configuration in the file was never 
applied (only its placeholders, as the file
+ * was added once more).
+ */
+public class RouteWatcherReloadPropertiesLocationTest extends 
ContextTestSupport {
+
+    @TempDir
+    Path dir;
+
+    private final List<String> changes = new ArrayList<>();
+    private String known;
+    private Path file;
+
+    @Override
+    protected CamelContext createCamelContext() throws Exception {
+        CamelContext context = super.createCamelContext();
+        file = Files.writeString(dir.resolve("app.properties"), "greeting = 
hello\n");
+        known = "file:" + dir + "/./app.properties";
+        context.getPropertiesComponent().setLocation(known);
+        context.addService(new RecordingPropertiesReload(changes));
+        return context;
+    }
+
+    @Test
+    public void theFileThatChangedIsTheFileThePropertiesComponentKnows() 
throws Exception {
+        Files.writeString(file, "greeting = 
hello\ncamel.component.log.exchange-formatter = #bean:myFormatter\n");
+
+        boolean reloaded = 
strategy().onPropertiesReload(ResourceHelper.resolveResource(context, "file:" + 
file), false);
+
+        assertTrue(reloaded);
+        assertEquals(List.of("changed " + known + ": 
camel.component.log.exchange-formatter"), changes);
+        // the file is not added a second time
+        assertEquals(1, 
context.getPropertiesComponent().getLocations().size());
+    }
+
+    @Test
+    public void theConfigurationOfANewPropertiesFileIsAppliedToo() throws 
Exception {
+        Path other = Files.writeString(dir.resolve("other.properties"),
+                "camel.component.log.exchange-formatter = 
#bean:myFormatter\n");
+
+        boolean reloaded = 
strategy().onPropertiesReload(ResourceHelper.resolveResource(context, "file:" + 
other), false);
+
+        assertTrue(reloaded);
+        assertEquals(List.of("changed file:" + other + ": 
camel.component.log.exchange-formatter"), changes);
+        // and its properties resolve
+        assertEquals("#bean:myFormatter",
+                
context.getPropertiesComponent().resolveProperty("camel.component.log.exchange-formatter").orElse(null));
+    }
+
+    private RouteWatcherReloadStrategy strategy() {
+        RouteWatcherReloadStrategy strategy = new RouteWatcherReloadStrategy();
+        strategy.setCamelContext(context);
+        return strategy;
+    }
+
+    // records what the reload hands to the listener, which camel-main 
configures from
+    private static class RecordingPropertiesReload extends ServiceSupport 
implements PropertiesReload {
+
+        private final List<String> changes;
+
+        RecordingPropertiesReload(List<String> changes) {
+            this.changes = changes;
+        }
+
+        @Override
+        public void onReload(String name, Properties properties) {
+            changes.add("reloaded " + name + ": " + String.join(", ", 
properties.stringPropertyNames()));
+        }
+
+        @Override
+        public void onChanged(String name, Properties properties) {
+            changes.add("changed " + name + ": " + String.join(", ", 
properties.stringPropertyNames()));
+        }
+    }
+}
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java 
b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
index 3199ff2b0acd..87f87a8d12cb 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/BaseMainSupport.java
@@ -2797,6 +2797,47 @@ public abstract class BaseMainSupport extends 
BaseService {
         return bean;
     }
 
+    /**
+     * The beans of re-loaded properties (CAMEL-25767). A new bean is created 
and bound as when the application starts,
+     * so a component configured in the same reload can refer to it, and a 
component created later can autowire it. A
+     * bean that exists already is left as it is, as components and routes may 
hold it: when its properties changed in a
+     * properties file, it is logged that this needs a restart.
+     */
+    private void bindReloadedBeans(
+            CamelContext camelContext, OrderedLocationProperties 
reloadedProperties, boolean changed,
+            OrderedLocationProperties autoConfiguredProperties)
+            throws Exception {
+
+        OrderedLocationProperties created = new OrderedLocationProperties();
+        Set<String> kept = new LinkedHashSet<>();
+        // stringPropertyNames is a live view of the keys, which are removed 
below
+        for (String key : new 
ArrayList<>(reloadedProperties.stringPropertyNames())) {
+            if (!startsWithIgnoreCase(key, "camel.beans.")) {
+                continue;
+            }
+            // the name the bean is bound with, as when the application starts
+            String option = optionKey(key.substring(12));
+            String name = StringHelper.before(option, ".", option);
+            name = StringHelper.before(name, "[", name);
+            if (camelContext.getRegistry().lookupByName(name) == null) {
+                created.put(reloadedProperties.getLocation(key), option, 
reloadedProperties.getProperty(key));
+            } else {
+                kept.add(name);
+            }
+            reloadedProperties.remove(key);
+        }
+        if (!created.isEmpty()) {
+            LOG.debug("Creating and binding beans to registry from reloaded 
properties: {}", created.size());
+            bindBeansToRegistry(camelContext, created, "camel.beans.",
+                    mainConfigurationProperties.isAutoConfigurationFailFast(),
+                    
mainConfigurationProperties.isAutoConfigurationLogSummary(), true, 
autoConfiguredProperties);
+        }
+        if (changed && !kept.isEmpty()) {
+            LOG.warn("The properties of the bean(s) {} changed. A reload only 
creates new beans: restart to apply the change.",
+                    String.join(", ", kept));
+        }
+    }
+
     private void bindBeansToRegistry(
             CamelContext camelContext, OrderedLocationProperties properties,
             String optionPrefix, boolean failIfNotSet, boolean logSummary, 
boolean ignoreCase,
@@ -3071,6 +3112,21 @@ public abstract class BaseMainSupport extends 
BaseService {
     protected void autoConfigurationFromReloadedProperties(
             CamelContext camelContext, OrderedLocationProperties 
reloadedProperties)
             throws Exception {
+        autoConfigurationFromReloadedProperties(camelContext, 
reloadedProperties, false);
+    }
+
+    /**
+     * Configures from properties that were re-loaded.
+     *
+     * @param camelContext       the context
+     * @param reloadedProperties the properties
+     * @param changed            whether these are the properties of a 
properties file that changed, such as
+     *                           application.properties in dev mode, rather 
than options that are applied again (such as
+     *                           by a context reload, for secret rotation)
+     */
+    protected void autoConfigurationFromReloadedProperties(
+            CamelContext camelContext, OrderedLocationProperties 
reloadedProperties, boolean changed)
+            throws Exception {
 
         Map<PropertyOptionKey, OrderedLocationProperties> properties = new 
LinkedHashMap<>();
 
@@ -3087,6 +3143,8 @@ public abstract class BaseMainSupport extends BaseService 
{
         }
 
         OrderedLocationProperties autoConfiguredProperties = new 
OrderedLocationProperties();
+        // the beans first, as the components that are configured next may 
refer to them (CAMEL-25767)
+        bindReloadedBeans(camelContext, reloadedProperties, changed, 
autoConfiguredProperties);
         doAutoConfigurationFromProperties(camelContext, reloadedProperties, 
properties, true, autoConfiguredProperties);
 
         // log summary of configurations
diff --git 
a/core/camel-main/src/main/java/org/apache/camel/main/MainPropertiesReload.java 
b/core/camel-main/src/main/java/org/apache/camel/main/MainPropertiesReload.java
index c02ba5a8dcad..7abdd23bed33 100644
--- 
a/core/camel-main/src/main/java/org/apache/camel/main/MainPropertiesReload.java
+++ 
b/core/camel-main/src/main/java/org/apache/camel/main/MainPropertiesReload.java
@@ -51,8 +51,18 @@ public class MainPropertiesReload extends ServiceSupport
 
     @Override
     public void onReload(String name, Properties properties) throws Exception {
+        // such as a context reload, which applies the options with a property 
placeholder again (secret rotation)
         if (properties instanceof OrderedLocationProperties prop) {
-            main.autoConfigurationFromReloadedProperties(camelContext, prop);
+            main.autoConfigurationFromReloadedProperties(camelContext, prop, 
false);
+            main.autowireWildcardProperties(camelContext);
+        }
+    }
+
+    @Override
+    public void onChanged(String name, Properties properties) throws Exception 
{
+        // a properties file that changed, such as application.properties in 
dev mode: the properties that changed
+        if (properties instanceof OrderedLocationProperties prop) {
+            main.autoConfigurationFromReloadedProperties(camelContext, prop, 
true);
             main.autowireWildcardProperties(camelContext);
         }
     }
diff --git 
a/core/camel-main/src/test/java/org/apache/camel/main/MainPropertiesReloadBeansTest.java
 
b/core/camel-main/src/test/java/org/apache/camel/main/MainPropertiesReloadBeansTest.java
new file mode 100644
index 000000000000..13008ed0c98a
--- /dev/null
+++ 
b/core/camel-main/src/test/java/org/apache/camel/main/MainPropertiesReloadBeansTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.main;
+
+import java.util.List;
+import java.util.Properties;
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import org.apache.camel.CamelContext;
+import org.apache.camel.component.log.LogComponent;
+import org.apache.camel.support.processor.DefaultExchangeFormatter;
+import org.apache.camel.util.OrderedLocationProperties;
+import org.apache.logging.log4j.Level;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.appender.AbstractAppender;
+import org.apache.logging.log4j.core.config.Property;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * CAMEL-25767: a properties file that changed creates the new beans in it, so 
a component that is configured in the
+ * same reload can refer to them. A bean that exists already is left as it is, 
as components may hold it, and a change
+ * to it in a properties file is logged as needing a restart.
+ */
+public class MainPropertiesReloadBeansTest {
+
+    private static final String FORMATTER = 
"#class:org.apache.camel.support.processor.DefaultExchangeFormatter";
+
+    private final List<String> warnings = new CopyOnWriteArrayList<>();
+    private Appender appender;
+
+    @BeforeEach
+    public void captureWarnings() {
+        appender = new AbstractAppender("reload-warnings", null, null, true, 
Property.EMPTY_ARRAY) {
+            @Override
+            public void append(LogEvent event) {
+                if (event.getLevel().isMoreSpecificThan(Level.WARN)) {
+                    warnings.add(event.getMessage().getFormattedMessage());
+                }
+            }
+        };
+        appender.start();
+        LoggerContext context = (LoggerContext) LogManager.getContext(false);
+        context.getConfiguration().getRootLogger().addAppender(appender, 
Level.ALL, null);
+        context.updateLoggers();
+    }
+
+    @AfterEach
+    public void stopCapture() {
+        LoggerContext context = (LoggerContext) LogManager.getContext(false);
+        
context.getConfiguration().getRootLogger().removeAppender(appender.getName());
+        context.updateLoggers();
+        appender.stop();
+    }
+
+    @Test
+    public void aNewBeanIsCreatedAndAComponentOfTheSameReloadRefersToIt() 
throws Exception {
+        Main main = main(new Properties());
+        try {
+            main.start();
+            CamelContext context = main.getCamelContext();
+
+            // application.properties saved in dev mode: a new bean, and the 
log component configured with it
+            reload(main).onChanged("file:application.properties", properties(
+                    "camel.beans.myFormatter", FORMATTER,
+                    "camel.beans.myFormatter.show-all", "true",
+                    "camel.component.log.exchange-formatter", 
"#bean:myFormatter"));
+
+            DefaultExchangeFormatter bean
+                    = context.getRegistry().lookupByNameAndType("myFormatter", 
DefaultExchangeFormatter.class);
+            assertThat(bean).isNotNull();
+            assertThat(bean.isShowAll()).isTrue();
+            assertThat(context.getComponent("log", 
LogComponent.class).getExchangeFormatter()).isSameAs(bean);
+            assertThat(warnings).noneMatch(w -> w.contains("restart"));
+        } finally {
+            main.stop();
+        }
+    }
+
+    @Test
+    public void aBeanThatExistsIsLeftAsItIsAndNeedsARestart() throws Exception 
{
+        Main main = main(properties("camel.beans.myFormatter", FORMATTER));
+        try {
+            main.start();
+            CamelContext context = main.getCamelContext();
+            DefaultExchangeFormatter bean
+                    = context.getRegistry().lookupByNameAndType("myFormatter", 
DefaultExchangeFormatter.class);
+
+            reload(main).onChanged("file:application.properties", 
properties("camel.beans.myFormatter.show-all", "true"));
+
+            
assertThat(context.getRegistry().lookupByName("myFormatter")).isSameAs(bean);
+            assertThat(bean.isShowAll()).isFalse();
+            assertThat(warnings).anyMatch(w -> w.contains("myFormatter") && 
w.contains("restart"));
+        } finally {
+            main.stop();
+        }
+    }
+
+    @Test
+    public void aContextReloadLeavesABeanThatExistsWithoutAWarning() throws 
Exception {
+        Main main = main(properties("camel.beans.myFormatter", FORMATTER));
+        try {
+            main.start();
+            CamelContext context = main.getCamelContext();
+            DefaultExchangeFormatter bean
+                    = context.getRegistry().lookupByNameAndType("myFormatter", 
DefaultExchangeFormatter.class);
+
+            // a context reload applies the options with a property 
placeholder again (secret rotation)
+            reload(main).onReload("ContextReload", 
properties("camel.beans.myFormatter.show-all", "true"));
+
+            
assertThat(context.getRegistry().lookupByName("myFormatter")).isSameAs(bean);
+            assertThat(warnings).noneMatch(w -> w.contains("restart"));
+        } finally {
+            main.stop();
+        }
+    }
+
+    private static Main main(Properties properties) {
+        Main main = new Main();
+        main.setDefaultPropertyPlaceholderLocation("false");
+        main.setOverrideProperties(properties);
+        return main;
+    }
+
+    private static MainPropertiesReload reload(Main main) {
+        MainPropertiesReload reload = new MainPropertiesReload(main);
+        reload.setCamelContext(main.getCamelContext());
+        return reload;
+    }
+
+    private static OrderedLocationProperties properties(String... 
keysAndValues) {
+        OrderedLocationProperties answer = new OrderedLocationProperties();
+        for (int i = 0; i < keysAndValues.length; i += 2) {
+            answer.put("file:application.properties", keysAndValues[i], 
keysAndValues[i + 1]);
+        }
+        return answer;
+    }
+}
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
index bb9d767da998..5c91fff49ae1 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/RouteWatcherReloadStrategy.java
@@ -20,6 +20,7 @@ import java.io.File;
 import java.io.InputStream;
 import java.net.URI;
 import java.nio.file.Files;
+import java.nio.file.InvalidPathException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayDeque;
@@ -357,6 +358,10 @@ public class RouteWatcherReloadStrategy extends 
FileWatcherResourceReloadStrateg
     }
 
     protected boolean onPropertiesReload(Resource resource, boolean 
reloadRoutes) throws Exception {
+        // the location the properties component knows the file by, which can 
be written another way than the file
+        // that changed, such as file:./application.properties for 
file:application.properties (CAMEL-25767)
+        String location = knownLocation(resource);
+
         // optimize to only update if something changed
         OrderedLocationProperties changed = null;
 
@@ -372,7 +377,7 @@ public class RouteWatcherReloadStrategy extends 
FileWatcherResourceReloadStrateg
                 IOHelper.close(is);
             }
             changed = new OrderedLocationProperties();
-            changed.putAll(resource.getLocation(), tmp);
+            changed.putAll(location, tmp);
             // filter to only keep changed properties
             pc.keepOnlyChangeProperties(changed);
         }
@@ -381,16 +386,16 @@ public class RouteWatcherReloadStrategy extends 
FileWatcherResourceReloadStrateg
         if (changed != null && !changed.isEmpty()) {
             LOG.info("Reloading properties: {}. (Only Camel routes and 
components can be updated with changes)",
                     resource.getLocation());
-            reloaded = pc.reloadProperties(resource.getLocation());
+            reloaded = pc.reloadProperties(location);
             if (reloaded) {
-                pr.onReload(resource.getLocation(), changed);
+                pr.onChanged(location, changed);
                 // trigger all routes to be reloaded
                 if (reloadRoutes) {
                     retryFailedOrReloadAll();
                 }
             } else {
                 // this may be a new properties file, so we need to add as new 
known location
-                String existing = 
getPropertiesByLocation(resource.getLocation());
+                String existing = getPropertiesByLocation(location);
                 if (existing == null) {
                     // remove scheme
                     String loc = resource.getLocation();
@@ -400,6 +405,11 @@ public class RouteWatcherReloadStrategy extends 
FileWatcherResourceReloadStrateg
                     PropertiesSource ps = 
pc.getPropertiesSourceFactory().newFilePropertiesSource(loc);
                     pc.addPropertiesSource(ps);
                     reloaded = true;
+                    // the configuration in a new properties file is applied 
as well (CAMEL-25767)
+                    pr.onChanged(location, changed);
+                    if (reloadRoutes) {
+                        retryFailedOrReloadAll();
+                    }
                 }
             }
         }
@@ -427,6 +437,37 @@ public class RouteWatcherReloadStrategy extends 
FileWatcherResourceReloadStrateg
         }
     }
 
+    /**
+     * The location of the properties component for the file of the resource, 
as the same file can be written in other
+     * ways (file:./application.properties and file:application.properties), 
else the location of the resource.
+     */
+    private String knownLocation(Resource resource) {
+        String location = resource.getLocation();
+        Path file = filePath(location);
+        if (file == null) {
+            return location;
+        }
+        for (String s : 
getCamelContext().getPropertiesComponent().getLocations()) {
+            String known = s.endsWith(";optional=true") ? s.substring(0, 
s.length() - 14) : s;
+            if (file.equals(filePath(known))) {
+                return known;
+            }
+        }
+        return location;
+    }
+
+    // the absolute path of a file: location, or null
+    private static Path filePath(String location) {
+        if (location == null || !location.startsWith("file:")) {
+            return null;
+        }
+        try {
+            return 
Paths.get(location.substring(5)).toAbsolutePath().normalize();
+        } catch (InvalidPathException e) {
+            return null;
+        }
+    }
+
     private String getPropertiesByLocation(String loc) {
         PropertiesComponent pc = getCamelContext().getPropertiesComponent();
         for (String s : pc.getLocations()) {
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index be17cc8fe5c7..f73972ebe986 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -1808,3 +1808,22 @@ the one of a miss, with the lines the file has there. 
`matchedLines` in the answ
 `~/.camel/camel-launch-<number>.log` or `camel-restart-<number>.log`, which 
stayed until the MCP server exited. An
 integration that still runs when the server exits keeps the file while it 
runs: `camel stop` removes it, and
 `camel dirty --clean` once the integration has ended.
+
+=== camel-main - a properties file that changed while reloading applies its 
beans and components
+
+With live reloading (such as `camel run --dev`), a change to 
application.properties now applies its configuration:
+
+* The file is matched to the properties file the application loaded, also when 
its location is written another way:
+  `camel run --source-dir=.` loads `file:./application.properties`, and the 
file watcher reports
+  `file:application.properties`. Before, the two did not match, so the file 
was added once more for its property
+  placeholders, but its `camel.component.*`, `camel.dataformat.*` and 
`camel.language.*` options were not applied.
+* A new bean (`camel.beans.*`) is created and bound, before the components are 
configured again, so a component can
+  refer to it (`#bean:name`), and a component that is created later can 
autowire it. With camel-jbang, the class of
+  the bean is downloaded when camel-jbang knows it, such as the Artemis 
client. A dependency that is added to
+  `camel.jbang.dependencies` while the application runs is not downloaded 
until a restart (CAMEL-25833).
+* A bean that exists is left as it is, as components may hold it. When its 
properties change, a `WARN` says that a
+  restart is needed.
+* A properties file that is created while the application runs is applied as 
well.
+
+`PropertiesReload` has a new default method, `onChanged`, which a properties 
file that changed calls with the properties
+that changed. A context reload (such as for secret rotation) still calls 
`onReload`.

Reply via email to