这是indexloc提供的服务,不要输入任何密码
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions spring-boot-modules/spring-boot-3-3/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,25 @@
<artifactId>langchain4j-ollama</artifactId>
<version>${langchain4j.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
<version>${spring-cloud-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
<version>${spring-cloud-starter.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.awaitility</groupId>
<artifactId>awaitility</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
Expand All @@ -65,5 +84,6 @@
<spring-boot.version>3.2.4</spring-boot.version>
<apache-camel.version>4.7.0</apache-camel.version>
<langchain4j.version>0.33.0</langchain4j.version>
<spring-cloud-starter.version>4.1.3</spring-cloud-starter.version>
</properties>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.baeldung.dynamically.updating.properties;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class UpdatingPropertiesApplication {

public static void main(String[] args) {
SpringApplication.run(UpdatingPropertiesApplication.class, args);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package com.baeldung.dynamically.updating.properties.controllers;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import com.baeldung.dynamically.updating.properties.services.ExampleBean;
import com.baeldung.dynamically.updating.properties.services.PropertyUpdaterService;

@RestController
@RequestMapping("/properties")
public class PropertyController {

@Autowired
private PropertyUpdaterService propertyUpdaterService;

@Autowired
private ExampleBean exampleBean;

@PostMapping("/update")
public String updateProperty(@RequestParam String key, @RequestParam String value) {
propertyUpdaterService.updateProperty(key, value);
return "Property updated. Remember to call the actuator /actuator/refresh";
}

@GetMapping("/customProperty")
public String getCustomProperty() {
return exampleBean.getCustomProperty();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.baeldung.dynamically.updating.properties.services;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;

@RefreshScope
@Component
public class ExampleBean {

@Value("${my.custom.property}")
private String customProperty;

public String getCustomProperty() {
return customProperty;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.baeldung.dynamically.updating.properties.services;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.stereotype.Service;

@Service
public class PropertyUpdaterService {

private static final String DYNAMIC_PROPERTIES_SOURCE_NAME = "dynamicProperties";

@Autowired
private ConfigurableEnvironment environment;

public void updateProperty(String key, String value) {
MutablePropertySources propertySources = environment.getPropertySources();
if (!propertySources.contains(DYNAMIC_PROPERTIES_SOURCE_NAME)) {
Map<String, Object> dynamicProperties = new HashMap<>();
dynamicProperties.put(key, value);
propertySources.addFirst(new MapPropertySource(DYNAMIC_PROPERTIES_SOURCE_NAME, dynamicProperties));
} else {
MapPropertySource propertySource = (MapPropertySource) propertySources.get(DYNAMIC_PROPERTIES_SOURCE_NAME);
propertySource.getSource().put(key, value);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.baeldung.dynamically.updating.properties.utility;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

@Configuration
public class CustomConfig {

@Bean
@Scope("prototype")
public MyService myService(@Value("${custom.property:default}") String property) {
return new MyService(property);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.baeldung.dynamically.updating.properties.utility;

public class MyService {

private final String property;

public MyService(String property) {
this.property = property;
}

public String getProperty() {
return property;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,15 @@ ollama.max_response_length=1000
# Logging configuration
logging.level.root=INFO
logging.level.com.baeldung.chatbot=DEBUG
logging.level.com.baeldung.dynamically.updating.properties=DEBUG
logging.level.org.springframework.boot.actuate=DEBUG

# We can disable Spring Cloud Config to prevent the application from trying to connect to a configuration server
spring.cloud.config.enabled=false
# Enable the Spring Boot Actuator endpoints to trigger a refresh
management.endpoint.refresh.enabled=true
management.endpoints.web.exposure.include=refresh

# Example property to be changed at runtime
my.custom.property=defaultValue

Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.baeldung.dynamically.updating.properties;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import com.baeldung.dynamically.updating.properties.utility.MyService;

import org.junit.jupiter.api.extension.ExtendWith;

import static org.junit.jupiter.api.Assertions.assertEquals;

@ExtendWith(SpringExtension.class)
@SpringBootTest(classes = UpdatingPropertiesApplication.class)
public class CustomConfigUnitTest {

@Autowired
private ApplicationContext context;

@Test
void whenPropertyInjected_thenServiceUsesCustomProperty() {
MyService service = context.getBean(MyService.class);
assertEquals("default", service.getProperty());
}

@Test
void whenPropertyChanged_thenServiceUsesUpdatedProperty() {
System.setProperty("custom.property", "updated");
MyService service = context.getBean(MyService.class);
assertEquals("updated", service.getProperty());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.baeldung.dynamically.updating.properties;

import static org.awaitility.Awaitility.await;

import java.util.concurrent.TimeUnit;

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.web.client.RestTemplate;

import com.baeldung.dynamically.updating.properties.services.ExampleBean;
import com.baeldung.dynamically.updating.properties.services.PropertyUpdaterService;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PropertyUpdaterServiceUnitTest {

@Autowired
private PropertyUpdaterService propertyUpdaterService;

@Autowired
private ExampleBean exampleBean;

@LocalServerPort
private int port;

@Test
@Timeout(5)
public void whenUpdatingProperty_thenPropertyIsUpdatedAndRefreshed() throws InterruptedException {
// Injects a new property into the test context
propertyUpdaterService.updateProperty("my.custom.property", "newValue");

// Trigger the refresh by calling the actuator endpoint
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(null, headers);
RestTemplate restTemplate = new RestTemplate();
restTemplate.postForEntity("http://localhost:" + port + "/actuator/refresh", entity, String.class);

// Awaitility to wait until the property is updated
await().atMost(5, TimeUnit.SECONDS).until(() -> "newValue".equals(exampleBean.getCustomProperty()));
}
}