/** * POST TITLE: Nacos Configuration Management in Java * * Complete implementation of Nacos for dynamic configuration management in Java applications */ import com.alibaba.nacos.api.NacosFactory; import com.alibaba.nacos.api.config.ConfigService; import com.alibaba.nacos.api.config.listener.Listener; import com.alibaba.nacos.api.exception.NacosException; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.cloud.context.config.annotation.RefreshScope; import java.io.*; import java.nio.file.*; import java.util.*; import java.util.concurrent.*; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.net.URI; public class NacosJavaIntegration { /** * Nacos Configuration Manager */ public static class NacosConfigManager { private final String serverAddr; private final String namespace; private final ConfigService configService; private final Map<String, List<ConfigListener>> listeners; private final ScheduledExecutorService scheduler; public NacosConfigManager(String serverAddr, String namespace) throws NacosException { this.serverAddr = serverAddr; this.namespace = namespace; this.listeners = new ConcurrentHashMap<>(); this.scheduler = Executors.newScheduledThreadPool(2); Properties properties = new Properties(); properties.put("serverAddr", serverAddr); properties.put("namespace", namespace); this.configService = NacosFactory.createConfigService(properties); System.out.println("✅ Nacos Config Manager initialized: " + serverAddr); } /** * Configuration Data Class */ public static class ConfigData { private final String dataId; private final String group; private final String content; private final String type; private final long timestamp; public ConfigData(String dataId, String group, String content, String type) { this.dataId = dataId; this.group = group; this.content = content; this.type = type; this.timestamp = System.currentTimeMillis(); } // Getters public String getDataId() { return dataId; } public String getGroup() { return group; } public String getContent() { return content; } public String getType() { return type; } public long getTimestamp() { return timestamp; } public <T> T parseAs(Class<T> clazz) { // Implementation would use Jackson or similar for JSON/YAML parsing return null; // Simplified } } /** * Configuration Listener Interface */ public interface ConfigListener { void onConfigChanged(ConfigData newConfig); void onConfigDeleted(String dataId, String group); void onError(Exception exception); } /** * Get configuration */ public ConfigData getConfig(String dataId, String group) throws NacosException { return getConfig(dataId, group, 5000); } public ConfigData getConfig(String dataId, String group, long timeoutMs) throws NacosException { String content = configService.getConfig(dataId, group, timeoutMs); String type = inferConfigType(dataId); return new ConfigData(dataId, group, content, type); } /** * Get configuration with retry */ public ConfigData getConfigWithRetry(String dataId, String group, int maxRetries) throws NacosException { for (int attempt = 1; attempt <= maxRetries; attempt++) { try { return getConfig(dataId, group); } catch (NacosException e) { if (attempt == maxRetries) { throw e; } System.out.println("🔄 Retry attempt " + attempt + " for: " + dataId); try { Thread.sleep(1000 * attempt); } catch (InterruptedException ie) { Thread.currentThread().interrupt(); throw new NacosException(NacosException.SERVER_ERROR, "Retry interrupted", ie); } } } throw new NacosException(NacosException.SERVER_ERROR, "All retry attempts failed"); } /** * Publish configuration */ public boolean publishConfig(String dataId, String group, String content) throws NacosException { return publishConfig(dataId, group, content, inferConfigType(dataId)); } public boolean publishConfig(String dataId, String group, String content, String type) throws NacosException { boolean success = configService.publishConfig(dataId, group, content, type); if (success) { System.out.println("✅ Configuration published: " + dataId + " in group: " + group); } else { System.out.println("❌ Failed to publish configuration: " + dataId); } return success; } /** * Delete configuration */ public boolean deleteConfig(String dataId, String group) throws NacosException { boolean success = configService.removeConfig(dataId, group); if (success) { System.out.println("✅ Configuration deleted: " + dataId + " from group: " + group); notifyConfigDeleted(dataId, group); } return success; } /** * Listen for configuration changes */ public void addListener(String dataId, String group, ConfigListener listener) throws NacosException { String key = dataId + "|" + group; listeners.computeIfAbsent(key, k -> new CopyOnWriteArrayList<>()).add(listener); configService.addListener(dataId, group, new Listener() { @Override public void receiveConfigInfo(String configInfo) { ConfigData configData = new ConfigData(dataId, group, configInfo, inferConfigType(dataId)); notifyConfigChanged(dataId, group, configData); } @Override public Executor getExecutor() { return Executors.newSingleThreadExecutor(); } }); System.out.println("👂 Listening for changes: " + dataId + " in group: " + group); } /** * Remove listener */ public void removeListener(String dataId, String group, ConfigListener listener) { String key = dataId + "|" + group; List<ConfigListener> listenerList = listeners.get(key); if (listenerList != null) { listenerList.remove(listener); if (listenerList.isEmpty()) { listeners.remove(key); } } } /** * Batch get configurations */ public Map<String, ConfigData> getConfigs(List<String> dataIds, String group) throws NacosException { Map<String, ConfigData> configs = new HashMap<>(); for (String dataId : dataIds) { try { ConfigData config = getConfig(dataId, group); configs.put(dataId, config); } catch (NacosException e) { System.err.println("❌ Failed to get config: " + dataId + " - " + e.getMessage()); } } return configs; } /** * Batch publish configurations */ public Map<String, Boolean> publishConfigs(Map<String, String> configs, String group) throws NacosException { Map<String, Boolean> results = new HashMap<>(); for (Map.Entry<String, String> entry : configs.entrySet()) { try { boolean success = publishConfig(entry.getKey(), group, entry.getValue()); results.put(entry.getKey(), success); } catch (NacosException e) { results.put(entry.getKey(), false); System.err.println("❌ Failed to publish config: " + entry.getKey() + " - " + e.getMessage()); } } return results; } private String inferConfigType(String dataId) { if (dataId.endsWith(".yaml") || dataId.endsWith(".yml")) { return "yaml"; } else if (dataId.endsWith(".properties")) { return "properties"; } else if (dataId.endsWith(".json")) { return "json"; } else if (dataId.endsWith(".xml")) { return "xml"; } return "text"; } private void notifyConfigChanged(String dataId, String group, ConfigData newConfig) { String key = dataId + "|" + group; List<ConfigListener> listenerList = listeners.get(key); if (listenerList != null) { for (ConfigListener listener : listenerList) { try { listener.onConfigChanged(newConfig); } catch (Exception e) { System.err.println("❌ Error in config listener: " + e.getMessage()); listener.onError(e); } } } } private void notifyConfigDeleted(String dataId, String group) { String key = dataId + "|" + group; List<ConfigListener> listenerList = listeners.get(key); if (listenerList != null) { for (ConfigListener listener : listenerList) { try { listener.onConfigDeleted(dataId, group); } catch (Exception e) { System.err.println("❌ Error in config listener: " + e.getMessage()); listener.onError(e); } } } } /** * Health check */ public boolean healthCheck() { try { // Try to get server status configService.getServerStatus(); return true; } catch (NacosException e) { return false; } } /** * Shutdown */ public void shutdown() { try { configService.shutDown(); scheduler.shutdown(); if (!scheduler.awaitTermination(5, TimeUnit.SECONDS)) { scheduler.shutdownNow(); } } catch (Exception e) { System.err.println("❌ Error shutting down Nacos config manager: " + e.getMessage()); } } } /** * Configuration Properties Manager */ public static class ConfigPropertiesManager { private final NacosConfigManager configManager; private final Map<String, Properties> cachedProperties; private final ScheduledExecutorService refreshScheduler; public ConfigPropertiesManager(NacosConfigManager configManager) { this.configManager = configManager; this.cachedProperties = new ConcurrentHashMap<>(); this.refreshScheduler = Executors.newScheduledThreadPool(1); startAutoRefresh(); } /** * Get properties from Nacos */ public Properties getProperties(String dataId, String group) throws NacosException { String cacheKey = dataId + "|" + group; Properties props = cachedProperties.get(cacheKey); if (props == null) { props = loadPropertiesFromNacos(dataId, group); cachedProperties.put(cacheKey, props); // Register for changes configManager.addListener(dataId, group, new NacosConfigManager.ConfigListener() { @Override public void onConfigChanged(NacosConfigManager.ConfigData newConfig) { try { Properties newProps = parseProperties(newConfig.getContent(), newConfig.getType()); cachedProperties.put(cacheKey, newProps); System.out.println("🔄 Properties updated: " + dataId); } catch (Exception e) { System.err.println("❌ Failed to parse updated properties: " + e.getMessage()); } } @Override public void onConfigDeleted(String deletedDataId, String deletedGroup) { cachedProperties.remove(cacheKey); System.out.println("🗑️ Properties removed from cache: " + deletedDataId); } @Override public void onError(Exception exception) { System.err.println("❌ Error in properties listener: " + exception.getMessage()); } }); } return props; } /** * Get property value */ public String getProperty(String dataId, String group, String key) throws NacosException { Properties props = getProperties(dataId, group); return props.getProperty(key); } public String getProperty(String dataId, String group, String key, String defaultValue) throws NacosException { String value = getProperty(dataId, group, key); return value != null ? value : defaultValue; } /** * Get integer property */ public Integer getIntProperty(String dataId, String group, String key) throws NacosException { String value = getProperty(dataId, group, key); return value != null ? Integer.parseInt(value) : null; } public int getIntProperty(String dataId, String group, String key, int defaultValue) throws NacosException { Integer value = getIntProperty(dataId, group, key); return value != null ? value : defaultValue; } /** * Get boolean property */ public Boolean getBooleanProperty(String dataId, String group, String key) throws NacosException { String value = getProperty(dataId, group, key); return value != null ? Boolean.parseBoolean(value) : null; } public boolean getBooleanProperty(String dataId, String group, String key, boolean defaultValue) throws NacosException { Boolean value = getBooleanProperty(dataId, group, key); return value != null ? value : defaultValue; } private Properties loadPropertiesFromNacos(String dataId, String group) throws NacosException { NacosConfigManager.ConfigData config = configManager.getConfig(dataId, group); return parseProperties(config.getContent(), config.getType()); } private Properties parseProperties(String content, String type) { Properties props = new Properties(); try { if ("properties".equals(type)) { props.load(new StringReader(content)); } else if ("yaml".equals(type) || "yml".equals(type)) { // For YAML, we'd use SnakeYAML or similar // This is a simplified implementation parseYamlToProperties(content, props); } else { // For other types, treat as key=value props.load(new StringReader(content)); } } catch (Exception e) { System.err.println("❌ Failed to parse properties: " + e.getMessage()); } return props; } private void parseYamlToProperties(String yamlContent, Properties props) { // Simplified YAML parsing - in production use SnakeYAML String[] lines = yamlContent.split("\n"); for (String line : lines) { line = line.trim(); if (!line.isEmpty() && !line.startsWith("#") && line.contains(":")) { String[] parts = line.split(":", 2); if (parts.length == 2) { String key = parts[0].trim(); String value = parts[1].trim(); props.setProperty(key, value); } } } } private void startAutoRefresh() { // Refresh all cached properties every 5 minutes refreshScheduler.scheduleAtFixedRate(() -> { try { refreshAllProperties(); } catch (Exception e) { System.err.println("❌ Auto-refresh failed: " + e.getMessage()); } }, 5, 5, TimeUnit.MINUTES); } private void refreshAllProperties() throws NacosException { for (String cacheKey : cachedProperties.keySet()) { String[] parts = cacheKey.split("\\|"); if (parts.length == 2) { String dataId = parts[0]; String group = parts[1]; try { Properties freshProps = loadPropertiesFromNacos(dataId, group); cachedProperties.put(cacheKey, freshProps); } catch (NacosException e) { System.err.println("❌ Failed to refresh properties: " + dataId); } } } } /** * Clear cache */ public void clearCache() { cachedProperties.clear(); System.out.println("🧹 Properties cache cleared"); } /** * Shutdown */ public void shutdown() { refreshScheduler.shutdown(); try { if (!refreshScheduler.awaitTermination(5, TimeUnit.SECONDS)) { refreshScheduler.shutdownNow(); } } catch (InterruptedException e) { refreshScheduler.shutdownNow(); Thread.currentThread().interrupt(); } } } /** * Spring Boot Integration */ @Configuration @ConfigurationProperties(prefix = "nacos.config") public static class NacosConfigProperties { private String serverAddr = "localhost:8848"; private String namespace = ""; private String group = "DEFAULT_GROUP"; private String fileExtension = "properties"; private int timeout = 3000; private boolean autoRefresh = true; // Getters and setters public String getServerAddr() { return serverAddr; } public void setServerAddr(String serverAddr) { this.serverAddr = serverAddr; } public String getNamespace() { return namespace; } public void setNamespace(String namespace) { this.namespace = namespace; } public String getGroup() { return group; } public void setGroup(String group) { this.group = group; } public String getFileExtension() { return fileExtension; } public void setFileExtension(String fileExtension) { this.fileExtension = fileExtension; } public int getTimeout() { return timeout; } public void setTimeout(int timeout) { this.timeout = timeout; } public boolean isAutoRefresh() { return autoRefresh; } public void setAutoRefresh(boolean autoRefresh) { this.autoRefresh = autoRefresh; } } @SpringBootApplication public static class NacosIntegrationApplication { @Bean public NacosConfigManager nacosConfigManager(NacosConfigProperties properties) throws NacosException { return new NacosConfigManager(properties.getServerAddr(), properties.getNamespace()); } @Bean public ConfigPropertiesManager configPropertiesManager(NacosConfigManager configManager) { return new ConfigPropertiesManager(configManager); } @Bean @RefreshScope public ApplicationConfig applicationConfig(ConfigPropertiesManager propertiesManager, NacosConfigProperties nacosProperties) throws NacosException { return new ApplicationConfig(propertiesManager, nacosProperties.getGroup()); } } @RefreshScope @Component public static class ApplicationConfig { private final ConfigPropertiesManager propertiesManager; private final String group; public ApplicationConfig(ConfigPropertiesManager propertiesManager, String group) { this.propertiesManager = propertiesManager; this.group = group; } @Value("${app.name:${spring.application.name:unknown}}") private String appName; public String getDatabaseUrl() { try { return propertiesManager.getProperty("datasource.properties", group, "url"); } catch (Exception e) { return "jdbc:mysql://localhost:3306/mydb"; } } public String getDatabaseUsername() { try { return propertiesManager.getProperty("datasource.properties", group, "username"); } catch (Exception e) { return "root"; } } public String getDatabasePassword() { try { return propertiesManager.getProperty("datasource.properties", group, "password"); } catch (Exception e) { return "password"; } } public int getServerPort() { try { return propertiesManager.getIntProperty("server.properties", group, "port", 8080); } catch (Exception e) { return 8080; } } public boolean isFeatureEnabled(String featureName) { try { return propertiesManager.getBooleanProperty("features.properties", group, featureName, false); } catch (Exception e) { return false; } } public Map<String, String> getExternalServices() { try { Properties props = propertiesManager.getProperties("services.properties", group); Map<String, String> services = new HashMap<>(); for (String key : props.stringPropertyNames()) { if (key.startsWith("service.")) { String serviceName = key.substring(8); // Remove "service." prefix services.put(serviceName, props.getProperty(key)); } } return services; } catch (Exception e) { return Collections.emptyMap(); } } } @RestController @RequestMapping("/api/config") public static class ConfigController { private final NacosConfigManager configManager; private final ConfigPropertiesManager propertiesManager; private final ApplicationConfig applicationConfig; private final NacosConfigProperties nacosProperties; public ConfigController(NacosConfigManager configManager, ConfigPropertiesManager propertiesManager, ApplicationConfig applicationConfig, NacosConfigProperties nacosProperties) { this.configManager = configManager; this.propertiesManager = propertiesManager; this.applicationConfig = applicationConfig; this.nacosProperties = nacosProperties; } @GetMapping("/{dataId}") public ResponseEntity<?> getConfig(@PathVariable String dataId, @RequestParam(defaultValue = "DEFAULT_GROUP") String group) { try { NacosConfigManager.ConfigData config = configManager.getConfig(dataId, group); Map<String, Object> response = new HashMap<>(); response.put("dataId", config.getDataId()); response.put("group", config.getGroup()); response.put("type", config.getType()); response.put("timestamp", config.getTimestamp()); response.put("content", config.getContent()); return ResponseEntity.ok(response); } catch (NacosException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of("error", "Failed to get config: " + e.getMessage())); } } @PostMapping("/{dataId}") public ResponseEntity<String> publishConfig(@PathVariable String dataId, @RequestParam(defaultValue = "DEFAULT_GROUP") String group, @RequestBody Map<String, String> request) { try { String content = request.get("content"); String type = request.getOrDefault("type", inferTypeFromDataId(dataId)); boolean success = configManager.publishConfig(dataId, group, content, type); if (success) { return ResponseEntity.ok("Configuration published successfully"); } else { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("Failed to publish configuration"); } } catch (NacosException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("Failed to publish config: " + e.getMessage()); } } @DeleteMapping("/{dataId}") public ResponseEntity<String> deleteConfig(@PathVariable String dataId, @RequestParam(defaultValue = "DEFAULT_GROUP") String group) { try { boolean success = configManager.deleteConfig(dataId, group); if (success) { return ResponseEntity.ok("Configuration deleted successfully"); } else { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("Failed to delete configuration"); } } catch (NacosException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body("Failed to delete config: " + e.getMessage()); } } @GetMapping("/properties/{dataId}") public ResponseEntity<?> getProperties(@PathVariable String dataId, @RequestParam(defaultValue = "DEFAULT_GROUP") String group) { try { Properties props = propertiesManager.getProperties(dataId, group); return ResponseEntity.ok(props); } catch (NacosException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of("error", "Failed to get properties: " + e.getMessage())); } } @GetMapping("/app/config") public ResponseEntity<Map<String, Object>> getApplicationConfig() { Map<String, Object> config = new HashMap<>(); config.put("databaseUrl", applicationConfig.getDatabaseUrl()); config.put("databaseUsername", applicationConfig.getDatabaseUsername()); config.put("serverPort", applicationConfig.getServerPort()); config.put("externalServices", applicationConfig.getExternalServices()); // Check some feature flags config.put("featureAEnabled", applicationConfig.isFeatureEnabled("featureA")); config.put("featureBEnabled", applicationConfig.isFeatureEnabled("featureB")); return ResponseEntity.ok(config); } @PostMapping("/cache/clear") public ResponseEntity<String> clearCache() { propertiesManager.clearCache(); return ResponseEntity.ok("Cache cleared successfully"); } @GetMapping("/health") public ResponseEntity<Map<String, Object>> healthCheck() { Map<String, Object> health = new HashMap<>(); health.put("status", configManager.healthCheck() ? "UP" : "DOWN"); health.put("server", nacosProperties.getServerAddr()); health.put("namespace", nacosProperties.getNamespace()); health.put("timestamp", new Date()); return ResponseEntity.ok(health); } private String inferTypeFromDataId(String dataId) { if (dataId.endsWith(".yaml") || dataId.endsWith(".yml")) return "yaml"; if (dataId.endsWith(".properties")) return "properties"; if (dataId.endsWith(".json")) return "json"; if (dataId.endsWith(".xml")) return "xml"; return "text"; } } /** * Configuration Examples Generator */ public static class ConfigExamplesGenerator { private final NacosConfigManager configManager; public ConfigExamplesGenerator(NacosConfigManager configManager) { this.configManager = configManager; } /** * Generate sample configurations for a microservices application */ public void generateSampleConfigurations() throws NacosException { // Database configuration String datasourceConfig = """ spring.datasource.url=jdbc:mysql://localhost:3306/mydb spring.datasource.username=admin spring.datasource.password=secret123 spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver spring.jpa.hibernate.ddl-auto=update spring.jpa.show-sql=true """; configManager.publishConfig("datasource.properties", "DEFAULT_GROUP", datasourceConfig); // Server configuration String serverConfig = """ server.port=8080 server.servlet.context-path=/api spring.mvc.format.date=yyyy-MM-dd logging.level.com.example=DEBUG """; configManager.publishConfig("server.properties", "DEFAULT_GROUP", serverConfig); // Feature flags String featuresConfig = """ feature.payment.enabled=true feature.notification.enabled=false feature.analytics.enabled=true feature.experimental.ui=false """; configManager.publishConfig("features.properties", "DEFAULT_GROUP", featuresConfig); // External services String servicesConfig = """ service.payment.url=https://payment-service:8081 service.user.url=https://user-service:8082 service.product.url=https://product-service:8083 service.notification.url=https://notification-service:8084 """; configManager.publishConfig("services.properties", "DEFAULT_GROUP", servicesConfig); // YAML configuration example String applicationYaml = """ app: name: order-service version: 1.0.0 environment: development database: primary: host: localhost port: 5432 name: order_db replica: host: replica-host port: 5432 name: order_db_replica cache: redis: host: redis-host port: 6379 timeout: 5000 """; configManager.publishConfig("application.yaml", "DEFAULT_GROUP", applicationYaml, "yaml"); System.out.println("✅ Sample configurations generated successfully"); } /** * Generate configuration for specific service */ public void generateServiceConfig(String serviceName, int port, String databaseUrl) throws NacosException { String serviceConfig = String.format(""" spring.application.name=%s server.port=%d spring.datasource.url=%s spring.datasource.username=service_user spring.datasource.password=service_pass_123 logging.level.com.%s=INFO management.endpoints.web.exposure.include=health,info,metrics """, serviceName, port, databaseUrl, serviceName); String dataId = serviceName + ".properties"; configManager.publishConfig(dataId, "DEFAULT_GROUP", serviceConfig); System.out.println("✅ Service configuration generated: " + dataId); } } /** * Demo and Usage Examples */ public static void main(String[] args) { System.out.println("☁️ Nacos Configuration Management in Java"); System.out.println("==========================================\n"); try { // Demo 1: Initialize Nacos Config Manager System.out.println("1. ⚙️ Initializing Nacos Config Manager"); NacosConfigManager configManager = new NacosConfigManager("localhost:8848", ""); System.out.println(" Nacos server: localhost:8848"); System.out.println(" Health check: " + (configManager.healthCheck() ? "✅" : "❌")); // Demo 2: Configuration Operations System.out.println("\n2. 📝 Configuration Operations"); ConfigExamplesGenerator examplesGenerator = new ConfigExamplesGenerator(configManager); examplesGenerator.generateSampleConfigurations(); // Demo 3: Properties Management System.out.println("\n3. 🗂️ Properties Management"); ConfigPropertiesManager propsManager = new ConfigPropertiesManager(configManager); Properties datasourceProps = propsManager.getProperties("datasource.properties", "DEFAULT_GROUP"); System.out.println(" Database URL: " + datasourceProps.getProperty("spring.datasource.url")); System.out.println(" Database User: " + datasourceProps.getProperty("spring.datasource.username")); // Demo 4: Configuration Listening System.out.println("\n4. 👂 Configuration Change Listening"); configManager.addListener("features.properties", "DEFAULT_GROUP", new NacosConfigManager.ConfigListener() { @Override public void onConfigChanged(NacosConfigManager.ConfigData newConfig) { System.out.println(" 🔄 Features configuration changed!"); System.out.println(" New content: " + newConfig.getContent().substring(0, 50) + "..."); } @Override public void onConfigDeleted(String dataId, String group) { System.out.println(" 🗑️ Configuration deleted: " + dataId); } @Override public void onError(Exception exception) { System.err.println(" ❌ Listener error: " + exception.getMessage()); } }); System.out.println(" Listening for changes to features.properties"); // Demo 5: Spring-like Configuration System.out.println("\n5. 🌱 Spring-like Configuration Management"); ApplicationConfig appConfig = new ApplicationConfig(propsManager, "DEFAULT_GROUP"); System.out.println(" Database URL: " + appConfig.getDatabaseUrl()); System.out.println(" Server Port: " + appConfig.getServerPort()); // Demo 6: Cleanup System.out.println("\n6. 🧹 Cleanup"); propsManager.shutdown(); configManager.shutdown(); System.out.println("\n✅ Nacos Configuration Demo Completed"); System.out.println("\n📚 Key Features:"); System.out.println(" - Dynamic configuration management"); System.out.println(" - Real-time configuration updates"); System.out.println(" - Multiple configuration formats (Properties, YAML, JSON)"); System.out.println(" - Spring Boot integration with @RefreshScope"); System.out.println(" - Configuration change listeners"); System.out.println(" - Health monitoring and auto-refresh"); System.out.println(" - Batch operations for efficiency"); } catch (Exception e) { System.err.println("❌ Demo failed: " + e.getMessage()); e.printStackTrace(); } } } Maven Dependencies
<!-- pom.xml --> <dependencies> <!-- Nacos Client --> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>2.2.3</version> </dependency> <!-- Spring Cloud Alibaba Nacos Config --> <dependency> <groupId>com.alibaba.cloud</groupId> <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId> <version>2022.0.0.0</version> </dependency> <!-- Spring Boot --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.7.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> <version>2.7.0</version> </dependency> <!-- Spring Cloud Context (for @RefreshScope) --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-context</artifactId> <version>3.1.5</version> </dependency> </dependencies>
Configuration Examples
application.yml (Spring Boot)
spring: application: name: order-service cloud: nacos: config: server-addr: localhost:8848 namespace: dev group: DEFAULT_GROUP file-extension: yaml refresh-enabled: true config: import: optional:nacos:application.yaml server: port: 8080 management: endpoints: web: exposure: include: health,info,metrics,refresh
Nacos Configuration Examples
application.yaml in Nacos
app: name: order-service version: 1.0.0 environment: production database: primary: host: db-primary.example.com port: 5432 name: order_db replica: host: db-replica.example.com port: 5432 name: order_db_replica redis: host: redis-cluster.example.com port: 6379 password: ${REDIS_PASSWORD} timeout: 5000 features: payment-enabled: true notification-enabled: false analytics-enabled: true datasource.properties in Nacos
spring.datasource.url=jdbc:postgresql://db-primary.example.com:5432/order_db spring.datasource.username=order_service spring.datasource.password=${DB_PASSWORD} spring.datasource.driver-class-name=org.postgresql.Driver spring.jpa.hibernate.ddl-auto=validate spring.jpa.show-sql=false features.properties in Nacos
feature.payment.enabled=true feature.notification.enabled=false feature.analytics.enabled=true feature.experimental.ui=false feature.rate.limiting.enabled=true
Usage Examples
// Initialize Nacos config manager NacosConfigManager configManager = new NacosConfigManager("localhost:8848", "dev"); // Get configuration NacosConfigManager.ConfigData config = configManager.getConfig("application.yaml", "DEFAULT_GROUP"); System.out.println("Config content: " + config.getContent()); // Listen for changes configManager.addListener("application.yaml", "DEFAULT_GROUP", new NacosConfigManager.ConfigListener() { @Override public void onConfigChanged(NacosConfigManager.ConfigData newConfig) { System.out.println("Configuration updated!"); // Reload application configuration reloadApplicationConfig(); } @Override public void onConfigDeleted(String dataId, String group) { System.out.println("Configuration deleted: " + dataId); } @Override public void onError(Exception exception) { System.err.println("Error in config listener: " + exception.getMessage()); } }); // Use with Spring Boot @RefreshScope @Component public class DatabaseConfig { @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; // Configuration will be automatically refreshed when changed in Nacos } This Nacos configuration management implementation provides:
- Complete Nacos Integration with dynamic configuration management
- Multiple Configuration Formats support (Properties, YAML, JSON, XML)
- Real-time Configuration Updates with listener pattern
- Spring Boot Integration with @RefreshScope support
- Configuration Caching with automatic refresh
- Health Monitoring and connection management
- Batch Operations for efficient configuration handling
- Error Handling with retry mechanisms
- Namespace and Group Management for multi-environment support
- REST API for configuration management
The solution enables Java applications to leverage Nacos for centralized configuration management with dynamic updates and Spring Boot integration for seamless adoption.