0
# Configuration Management
1
2
Dynamic configuration management with real-time updates, listeners, and fuzzy watching capabilities. Perfect for application settings, feature flags, environment-specific configurations, and any data that needs to be updated without application restarts.
3
4
## Capabilities
5
6
### ConfigService
7
8
Main interface for all configuration operations including retrieving, publishing, and managing configuration data with real-time change notifications.
9
10
```java { .api }
11
/**
12
* Main interface for configuration operations
13
*/
14
interface ConfigService {
15
/**
16
* Get configuration content
17
* @param dataId Configuration identifier
18
* @param group Configuration group name
19
* @param timeoutMs Timeout in milliseconds
20
* @return Configuration content as string
21
* @throws NacosException If retrieval fails
22
*/
23
String getConfig(String dataId, String group, long timeoutMs) throws NacosException;
24
25
/**
26
* Get configuration content and register listener atomically
27
* @param dataId Configuration identifier
28
* @param group Configuration group name
29
* @param timeoutMs Timeout in milliseconds
30
* @param listener Change listener to register
31
* @return Configuration content as string
32
* @throws NacosException If operation fails
33
*/
34
String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener) throws NacosException;
35
36
/**
37
* Publish configuration content
38
* @param dataId Configuration identifier
39
* @param group Configuration group name
40
* @param content Configuration content
41
* @return true if published successfully
42
* @throws NacosException If publishing fails
43
*/
44
boolean publishConfig(String dataId, String group, String content) throws NacosException;
45
46
/**
47
* Publish configuration with specific content type
48
* @param dataId Configuration identifier
49
* @param group Configuration group name
50
* @param content Configuration content
51
* @param type Content type (JSON, YAML, XML, etc.)
52
* @return true if published successfully
53
* @throws NacosException If publishing fails
54
*/
55
boolean publishConfig(String dataId, String group, String content, String type) throws NacosException;
56
57
/**
58
* Publish configuration with CAS (Compare and Swap) operation
59
* @param dataId Configuration identifier
60
* @param group Configuration group name
61
* @param content New configuration content
62
* @param casMd5 Expected MD5 hash of current content
63
* @return true if CAS operation succeeded
64
* @throws NacosException If operation fails
65
*/
66
boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException;
67
68
/**
69
* Remove configuration
70
* @param dataId Configuration identifier
71
* @param group Configuration group name
72
* @return true if removed successfully
73
* @throws NacosException If removal fails
74
*/
75
boolean removeConfig(String dataId, String group) throws NacosException;
76
77
/**
78
* Add configuration change listener
79
* @param dataId Configuration identifier
80
* @param group Configuration group name
81
* @param listener Change listener
82
* @throws NacosException If listener registration fails
83
*/
84
void addListener(String dataId, String group, Listener listener) throws NacosException;
85
86
/**
87
* Remove configuration change listener
88
* @param dataId Configuration identifier
89
* @param group Configuration group name
90
* @param listener Change listener to remove
91
*/
92
void removeListener(String dataId, String group, Listener listener);
93
94
/**
95
* Watch multiple configurations with group pattern (3.0+)
96
* @param groupNamePattern Group name pattern (supports wildcards)
97
* @param watcher Event watcher for fuzzy matches
98
* @throws NacosException If watch setup fails
99
*/
100
void fuzzyWatch(String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
101
102
/**
103
* Watch multiple configurations with data ID and group patterns (3.0+)
104
* @param dataIdPattern Data ID pattern (supports wildcards)
105
* @param groupNamePattern Group name pattern (supports wildcards)
106
* @param watcher Event watcher for fuzzy matches
107
* @throws NacosException If watch setup fails
108
*/
109
void fuzzyWatch(String dataIdPattern, String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
110
111
/**
112
* Watch with group pattern and return matched keys (3.0+)
113
* @param groupNamePattern Group name pattern
114
* @param watcher Event watcher
115
* @return Future containing matched configuration keys
116
* @throws NacosException If operation fails
117
*/
118
Future<Set<String>> fuzzyWatchWithGroupKeys(String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
119
120
/**
121
* Get server status
122
* @return Server status string
123
*/
124
String getServerStatus();
125
126
/**
127
* Add configuration filter for preprocessing
128
* @param configFilter Filter to add
129
*/
130
void addConfigFilter(IConfigFilter configFilter);
131
132
/**
133
* Shutdown configuration service
134
* @throws NacosException If shutdown fails
135
*/
136
void shutDown() throws NacosException;
137
}
138
```
139
140
### Configuration Listeners
141
142
Event-driven configuration change handling with different listener implementations for various use cases.
143
144
```java { .api }
145
/**
146
* Base interface for configuration listeners
147
*/
148
interface Listener {
149
/**
150
* Get executor for handling configuration changes
151
* @return Executor for async processing, null for synchronous
152
*/
153
Executor getExecutor();
154
155
/**
156
* Receive configuration change notification
157
* @param configInfo New configuration content
158
*/
159
void receiveConfigInfo(String configInfo);
160
}
161
162
/**
163
* Abstract base class for configuration listeners
164
*/
165
abstract class AbstractListener implements Listener {
166
/**
167
* Default implementation returns null for synchronous processing
168
*/
169
@Override
170
public Executor getExecutor() {
171
return null;
172
}
173
174
/**
175
* Abstract method to be implemented by subclasses
176
*/
177
@Override
178
public abstract void receiveConfigInfo(String configInfo);
179
}
180
181
/**
182
* Configuration change listener with detailed change information
183
*/
184
abstract class AbstractSharedListener implements Listener {
185
/**
186
* Receive detailed configuration change information
187
* @param dataId Configuration identifier
188
* @param group Configuration group
189
* @param configInfo New configuration content
190
*/
191
public abstract void innerReceive(String dataId, String group, String configInfo);
192
193
/**
194
* Get filters for configuration content
195
* @return Array of config filters
196
*/
197
public ConfigFilter[] getConfigFilters() {
198
return new ConfigFilter[0];
199
}
200
}
201
202
/**
203
* Fuzzy watch event watcher for pattern-based configuration monitoring (3.0+)
204
*/
205
interface FuzzyWatchEventWatcher {
206
/**
207
* Handle fuzzy watch events
208
* @param event Configuration change event
209
*/
210
void onEvent(FuzzyWatchEvent event);
211
212
/**
213
* Get executor for event processing
214
* @return Executor for async processing
215
*/
216
default Executor getExecutor() {
217
return null;
218
}
219
}
220
```
221
222
### Configuration Events and Change Tracking
223
224
Event classes for tracking configuration changes with detailed information about what changed.
225
226
```java { .api }
227
/**
228
* Configuration change event containing detailed change information
229
*/
230
class ConfigChangeEvent {
231
/** Configuration data ID */
232
private final String dataId;
233
234
/** Configuration group */
235
private final String group;
236
237
/** Namespace */
238
private final String namespace;
239
240
/** Map of changed configuration items */
241
private final Map<String, ConfigChangeItem> data;
242
243
/**
244
* Constructor for configuration change event
245
*/
246
public ConfigChangeEvent(String dataId, String group, String namespace, Map<String, ConfigChangeItem> data);
247
248
/**
249
* Get configuration identifier
250
*/
251
public String getDataId();
252
253
/**
254
* Get configuration group
255
*/
256
public String getGroup();
257
258
/**
259
* Get namespace
260
*/
261
public String getNamespace();
262
263
/**
264
* Get all changed items
265
*/
266
public Map<String, ConfigChangeItem> getData();
267
268
/**
269
* Get specific changed item
270
*/
271
public ConfigChangeItem getChangeItem(String key);
272
}
273
274
/**
275
* Individual configuration change item
276
*/
277
class ConfigChangeItem {
278
/** Property key */
279
private final String key;
280
281
/** Old value */
282
private final String oldValue;
283
284
/** New value */
285
private final String newValue;
286
287
/** Type of change */
288
private final PropertyChangeType type;
289
290
/**
291
* Constructor for change item
292
*/
293
public ConfigChangeItem(String key, String oldValue, String newValue);
294
295
/**
296
* Get property key
297
*/
298
public String getKey();
299
300
/**
301
* Get old value
302
*/
303
public String getOldValue();
304
305
/**
306
* Get new value
307
*/
308
public String getNewValue();
309
310
/**
311
* Get change type
312
*/
313
public PropertyChangeType getType();
314
}
315
316
/**
317
* Types of property changes
318
*/
319
enum PropertyChangeType {
320
/** Property was added */
321
ADDED,
322
323
/** Property was modified */
324
MODIFIED,
325
326
/** Property was deleted */
327
DELETED
328
}
329
```
330
331
### Configuration Types and Filters
332
333
Support for different configuration file types and content filtering.
334
335
```java { .api }
336
/**
337
* Supported configuration file types
338
*/
339
enum ConfigType {
340
/** Unspecified type */
341
UNSET,
342
343
/** Plain text */
344
TEXT,
345
346
/** JSON format */
347
JSON,
348
349
/** XML format */
350
XML,
351
352
/** YAML format */
353
YAML,
354
355
/** HTML format */
356
HTML,
357
358
/** Properties format */
359
PROPERTIES;
360
361
/**
362
* Get config type from string
363
*/
364
public static ConfigType getType(String type);
365
}
366
367
/**
368
* Configuration filter interface for preprocessing content
369
*/
370
interface IConfigFilter {
371
/**
372
* Initialize filter
373
* @param filterConfig Filter configuration
374
*/
375
void init(IFilterConfig filterConfig);
376
377
/**
378
* Filter configuration content
379
* @param configRequest Configuration request
380
* @param configResponse Configuration response
381
* @throws NacosException If filtering fails
382
*/
383
void doFilter(IConfigRequest configRequest, IConfigResponse configResponse) throws NacosException;
384
385
/**
386
* Get filter name
387
*/
388
String getFilterName();
389
}
390
```
391
392
## Usage Examples
393
394
### Basic Configuration Operations
395
396
```java
397
import com.alibaba.nacos.api.NacosFactory;
398
import com.alibaba.nacos.api.PropertyKeyConst;
399
import com.alibaba.nacos.api.config.ConfigService;
400
import com.alibaba.nacos.api.config.listener.Listener;
401
import java.util.Properties;
402
import java.util.concurrent.Executor;
403
404
// Create configuration service
405
Properties properties = new Properties();
406
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
407
properties.setProperty(PropertyKeyConst.NAMESPACE, "development");
408
ConfigService configService = NacosFactory.createConfigService(properties);
409
410
// Get configuration
411
String dataId = "application.properties";
412
String group = "DEFAULT_GROUP";
413
String config = configService.getConfig(dataId, group, 5000);
414
System.out.println("Current config: " + config);
415
416
// Publish configuration
417
String content = "app.name=MyApplication\napp.version=1.0.0\ndatabase.url=jdbc:mysql://localhost:3306/mydb";
418
boolean result = configService.publishConfig(dataId, group, content);
419
System.out.println("Published: " + result);
420
421
// Publish with specific type
422
boolean jsonResult = configService.publishConfig(
423
"app-config.json",
424
group,
425
"{\"name\":\"MyApp\",\"version\":\"1.0\"}",
426
ConfigType.JSON.name()
427
);
428
```
429
430
### Configuration Change Listeners
431
432
```java
433
import com.alibaba.nacos.api.config.listener.AbstractListener;
434
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
435
436
// Simple configuration listener
437
Listener simpleListener = new AbstractListener() {
438
@Override
439
public void receiveConfigInfo(String configInfo) {
440
System.out.println("Configuration changed: " + configInfo);
441
// Parse and apply new configuration
442
applyConfiguration(configInfo);
443
}
444
445
@Override
446
public Executor getExecutor() {
447
// Return custom executor for async processing
448
return Executors.newSingleThreadExecutor();
449
}
450
};
451
452
// Add listener
453
configService.addListener(dataId, group, simpleListener);
454
455
// Shared listener with detailed change information
456
AbstractSharedListener detailedListener = new AbstractSharedListener() {
457
@Override
458
public void innerReceive(String dataId, String group, String configInfo) {
459
System.out.printf("Config changed - DataId: %s, Group: %s%n", dataId, group);
460
System.out.println("New content: " + configInfo);
461
462
// Handle different data IDs differently
463
if ("database.properties".equals(dataId)) {
464
reconfigureDatabase(configInfo);
465
} else if ("logging.properties".equals(dataId)) {
466
reconfigureLogging(configInfo);
467
}
468
}
469
};
470
471
configService.addListener("database.properties", group, detailedListener);
472
configService.addListener("logging.properties", group, detailedListener);
473
```
474
475
### Advanced Configuration Management
476
477
```java
478
import com.alibaba.nacos.api.config.ConfigChangeEvent;
479
import com.alibaba.nacos.api.config.ConfigChangeItem;
480
import com.alibaba.nacos.api.config.PropertyChangeType;
481
482
// Configuration change event handling
483
public class ConfigChangeHandler {
484
485
public void handleConfigChange(ConfigChangeEvent event) {
486
System.out.printf("Configuration change in %s:%s%n",
487
event.getGroup(), event.getDataId());
488
489
for (Map.Entry<String, ConfigChangeItem> entry : event.getData().entrySet()) {
490
ConfigChangeItem item = entry.getValue();
491
492
switch (item.getType()) {
493
case ADDED:
494
System.out.printf("Added: %s = %s%n",
495
item.getKey(), item.getNewValue());
496
break;
497
case MODIFIED:
498
System.out.printf("Modified: %s = %s (was: %s)%n",
499
item.getKey(), item.getNewValue(), item.getOldValue());
500
break;
501
case DELETED:
502
System.out.printf("Deleted: %s (was: %s)%n",
503
item.getKey(), item.getOldValue());
504
break;
505
}
506
}
507
}
508
}
509
510
// CAS (Compare and Swap) operations for atomic updates
511
public boolean atomicConfigUpdate(ConfigService configService,
512
String dataId, String group,
513
String expectedContent, String newContent) {
514
try {
515
// Get current config with MD5
516
String currentConfig = configService.getConfig(dataId, group, 3000);
517
518
if (!expectedContent.equals(currentConfig)) {
519
return false; // Content has changed
520
}
521
522
// Calculate MD5 of expected content
523
String expectedMd5 = calculateMD5(expectedContent);
524
525
// Perform atomic update
526
return configService.publishConfigCas(dataId, group, newContent, expectedMd5);
527
528
} catch (NacosException e) {
529
System.err.println("Failed to perform atomic update: " + e.getMessage());
530
return false;
531
}
532
}
533
```
534
535
### Fuzzy Watch (3.0+ Feature)
536
537
```java
538
import com.alibaba.nacos.api.config.listener.FuzzyWatchEventWatcher;
539
import java.util.concurrent.Future;
540
import java.util.Set;
541
542
// Watch all configurations in a group pattern
543
FuzzyWatchEventWatcher groupWatcher = new FuzzyWatchEventWatcher() {
544
@Override
545
public void onEvent(FuzzyWatchEvent event) {
546
System.out.printf("Fuzzy watch event: %s in group %s%n",
547
event.getDataId(), event.getGroup());
548
System.out.println("Content: " + event.getContent());
549
}
550
551
@Override
552
public Executor getExecutor() {
553
return Executors.newFixedThreadPool(4);
554
}
555
};
556
557
// Watch all configurations in groups matching pattern
558
configService.fuzzyWatch("app-*", groupWatcher);
559
560
// Watch specific data ID pattern in specific group pattern
561
configService.fuzzyWatch("*.properties", "DEFAULT_GROUP", groupWatcher);
562
563
// Watch with key retrieval
564
Future<Set<String>> future = configService.fuzzyWatchWithGroupKeys("microservice-*", groupWatcher);
565
Set<String> matchedKeys = future.get();
566
System.out.println("Matched configuration keys: " + matchedKeys);
567
```
568
569
### Configuration Filtering
570
571
```java
572
import com.alibaba.nacos.api.config.filter.IConfigFilter;
573
import com.alibaba.nacos.api.config.filter.IConfigRequest;
574
import com.alibaba.nacos.api.config.filter.IConfigResponse;
575
576
// Custom configuration filter for decryption
577
public class DecryptionFilter implements IConfigFilter {
578
579
@Override
580
public void init(IFilterConfig filterConfig) {
581
// Initialize decryption keys, etc.
582
}
583
584
@Override
585
public void doFilter(IConfigRequest request, IConfigResponse response) throws NacosException {
586
String content = response.getContent();
587
588
// Decrypt sensitive configuration values
589
if (content != null && content.contains("encrypted:")) {
590
String decryptedContent = decryptContent(content);
591
response.setContent(decryptedContent);
592
}
593
}
594
595
@Override
596
public String getFilterName() {
597
return "decryption-filter";
598
}
599
600
private String decryptContent(String encryptedContent) {
601
// Implement decryption logic
602
return encryptedContent.replaceAll("encrypted:(\\w+)", "decrypted_value");
603
}
604
}
605
606
// Add filter to configuration service
607
configService.addConfigFilter(new DecryptionFilter());
608
```
609
610
### Error Handling and Best Practices
611
612
```java
613
import com.alibaba.nacos.api.exception.NacosException;
614
615
public class ConfigurationManager {
616
617
private final ConfigService configService;
618
private final Map<String, String> configCache = new ConcurrentHashMap<>();
619
620
public ConfigurationManager(ConfigService configService) {
621
this.configService = configService;
622
}
623
624
public String getConfigSafely(String dataId, String group, String defaultValue) {
625
try {
626
String config = configService.getConfig(dataId, group, 3000);
627
628
if (config != null) {
629
configCache.put(dataId + ":" + group, config);
630
return config;
631
}
632
633
// Return cached value if available
634
String cached = configCache.get(dataId + ":" + group);
635
return cached != null ? cached : defaultValue;
636
637
} catch (NacosException e) {
638
System.err.printf("Failed to get config %s:%s - %s%n",
639
group, dataId, e.getMessage());
640
641
// Return cached value or default
642
String cached = configCache.get(dataId + ":" + group);
643
return cached != null ? cached : defaultValue;
644
}
645
}
646
647
public boolean publishConfigSafely(String dataId, String group, String content) {
648
for (int retry = 0; retry < 3; retry++) {
649
try {
650
boolean result = configService.publishConfig(dataId, group, content);
651
if (result) {
652
configCache.put(dataId + ":" + group, content);
653
return true;
654
}
655
} catch (NacosException e) {
656
System.err.printf("Attempt %d failed to publish config %s:%s - %s%n",
657
retry + 1, group, dataId, e.getMessage());
658
659
if (retry == 2) {
660
return false; // Final attempt failed
661
}
662
663
try {
664
Thread.sleep(1000 * (retry + 1)); // Exponential backoff
665
} catch (InterruptedException ie) {
666
Thread.currentThread().interrupt();
667
return false;
668
}
669
}
670
}
671
return false;
672
}
673
674
public void setupResillientListener(String dataId, String group,
675
Consumer<String> configHandler) {
676
Listener resilientListener = new AbstractListener() {
677
@Override
678
public void receiveConfigInfo(String configInfo) {
679
try {
680
configHandler.accept(configInfo);
681
configCache.put(dataId + ":" + group, configInfo);
682
} catch (Exception e) {
683
System.err.printf("Error processing config change for %s:%s - %s%n",
684
group, dataId, e.getMessage());
685
}
686
}
687
688
@Override
689
public Executor getExecutor() {
690
// Use dedicated thread pool for configuration processing
691
return Executors.newSingleThreadExecutor(r -> {
692
Thread t = new Thread(r, "config-processor-" + dataId);
693
t.setDaemon(true);
694
return t;
695
});
696
}
697
};
698
699
try {
700
configService.addListener(dataId, group, resilientListener);
701
} catch (NacosException e) {
702
System.err.printf("Failed to add listener for %s:%s - %s%n",
703
group, dataId, e.getMessage());
704
}
705
}
706
}