Nacos API package providing interfaces and common classes for dynamic service discovery, configuration management, and service management in cloud native applications and microservices
—
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.
Main interface for all configuration operations including retrieving, publishing, and managing configuration data with real-time change notifications.
/**
* Main interface for configuration operations
*/
interface ConfigService {
/**
* Get configuration content
* @param dataId Configuration identifier
* @param group Configuration group name
* @param timeoutMs Timeout in milliseconds
* @return Configuration content as string
* @throws NacosException If retrieval fails
*/
String getConfig(String dataId, String group, long timeoutMs) throws NacosException;
/**
* Get configuration content and register listener atomically
* @param dataId Configuration identifier
* @param group Configuration group name
* @param timeoutMs Timeout in milliseconds
* @param listener Change listener to register
* @return Configuration content as string
* @throws NacosException If operation fails
*/
String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener) throws NacosException;
/**
* Publish configuration content
* @param dataId Configuration identifier
* @param group Configuration group name
* @param content Configuration content
* @return true if published successfully
* @throws NacosException If publishing fails
*/
boolean publishConfig(String dataId, String group, String content) throws NacosException;
/**
* Publish configuration with specific content type
* @param dataId Configuration identifier
* @param group Configuration group name
* @param content Configuration content
* @param type Content type (JSON, YAML, XML, etc.)
* @return true if published successfully
* @throws NacosException If publishing fails
*/
boolean publishConfig(String dataId, String group, String content, String type) throws NacosException;
/**
* Publish configuration with CAS (Compare and Swap) operation
* @param dataId Configuration identifier
* @param group Configuration group name
* @param content New configuration content
* @param casMd5 Expected MD5 hash of current content
* @return true if CAS operation succeeded
* @throws NacosException If operation fails
*/
boolean publishConfigCas(String dataId, String group, String content, String casMd5) throws NacosException;
/**
* Remove configuration
* @param dataId Configuration identifier
* @param group Configuration group name
* @return true if removed successfully
* @throws NacosException If removal fails
*/
boolean removeConfig(String dataId, String group) throws NacosException;
/**
* Add configuration change listener
* @param dataId Configuration identifier
* @param group Configuration group name
* @param listener Change listener
* @throws NacosException If listener registration fails
*/
void addListener(String dataId, String group, Listener listener) throws NacosException;
/**
* Remove configuration change listener
* @param dataId Configuration identifier
* @param group Configuration group name
* @param listener Change listener to remove
*/
void removeListener(String dataId, String group, Listener listener);
/**
* Watch multiple configurations with group pattern (3.0+)
* @param groupNamePattern Group name pattern (supports wildcards)
* @param watcher Event watcher for fuzzy matches
* @throws NacosException If watch setup fails
*/
void fuzzyWatch(String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/**
* Watch multiple configurations with data ID and group patterns (3.0+)
* @param dataIdPattern Data ID pattern (supports wildcards)
* @param groupNamePattern Group name pattern (supports wildcards)
* @param watcher Event watcher for fuzzy matches
* @throws NacosException If watch setup fails
*/
void fuzzyWatch(String dataIdPattern, String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/**
* Watch with group pattern and return matched keys (3.0+)
* @param groupNamePattern Group name pattern
* @param watcher Event watcher
* @return Future containing matched configuration keys
* @throws NacosException If operation fails
*/
Future<Set<String>> fuzzyWatchWithGroupKeys(String groupNamePattern, FuzzyWatchEventWatcher watcher) throws NacosException;
/**
* Get server status
* @return Server status string
*/
String getServerStatus();
/**
* Add configuration filter for preprocessing
* @param configFilter Filter to add
*/
void addConfigFilter(IConfigFilter configFilter);
/**
* Shutdown configuration service
* @throws NacosException If shutdown fails
*/
void shutDown() throws NacosException;
}Event-driven configuration change handling with different listener implementations for various use cases.
/**
* Base interface for configuration listeners
*/
interface Listener {
/**
* Get executor for handling configuration changes
* @return Executor for async processing, null for synchronous
*/
Executor getExecutor();
/**
* Receive configuration change notification
* @param configInfo New configuration content
*/
void receiveConfigInfo(String configInfo);
}
/**
* Abstract base class for configuration listeners
*/
abstract class AbstractListener implements Listener {
/**
* Default implementation returns null for synchronous processing
*/
@Override
public Executor getExecutor() {
return null;
}
/**
* Abstract method to be implemented by subclasses
*/
@Override
public abstract void receiveConfigInfo(String configInfo);
}
/**
* Configuration change listener with detailed change information
*/
abstract class AbstractSharedListener implements Listener {
/**
* Receive detailed configuration change information
* @param dataId Configuration identifier
* @param group Configuration group
* @param configInfo New configuration content
*/
public abstract void innerReceive(String dataId, String group, String configInfo);
/**
* Get filters for configuration content
* @return Array of config filters
*/
public ConfigFilter[] getConfigFilters() {
return new ConfigFilter[0];
}
}
/**
* Fuzzy watch event watcher for pattern-based configuration monitoring (3.0+)
*/
interface FuzzyWatchEventWatcher {
/**
* Handle fuzzy watch events
* @param event Configuration change event
*/
void onEvent(FuzzyWatchEvent event);
/**
* Get executor for event processing
* @return Executor for async processing
*/
default Executor getExecutor() {
return null;
}
}Event classes for tracking configuration changes with detailed information about what changed.
/**
* Configuration change event containing detailed change information
*/
class ConfigChangeEvent {
/** Configuration data ID */
private final String dataId;
/** Configuration group */
private final String group;
/** Namespace */
private final String namespace;
/** Map of changed configuration items */
private final Map<String, ConfigChangeItem> data;
/**
* Constructor for configuration change event
*/
public ConfigChangeEvent(String dataId, String group, String namespace, Map<String, ConfigChangeItem> data);
/**
* Get configuration identifier
*/
public String getDataId();
/**
* Get configuration group
*/
public String getGroup();
/**
* Get namespace
*/
public String getNamespace();
/**
* Get all changed items
*/
public Map<String, ConfigChangeItem> getData();
/**
* Get specific changed item
*/
public ConfigChangeItem getChangeItem(String key);
}
/**
* Individual configuration change item
*/
class ConfigChangeItem {
/** Property key */
private final String key;
/** Old value */
private final String oldValue;
/** New value */
private final String newValue;
/** Type of change */
private final PropertyChangeType type;
/**
* Constructor for change item
*/
public ConfigChangeItem(String key, String oldValue, String newValue);
/**
* Get property key
*/
public String getKey();
/**
* Get old value
*/
public String getOldValue();
/**
* Get new value
*/
public String getNewValue();
/**
* Get change type
*/
public PropertyChangeType getType();
}
/**
* Types of property changes
*/
enum PropertyChangeType {
/** Property was added */
ADDED,
/** Property was modified */
MODIFIED,
/** Property was deleted */
DELETED
}Support for different configuration file types and content filtering.
/**
* Supported configuration file types
*/
enum ConfigType {
/** Unspecified type */
UNSET,
/** Plain text */
TEXT,
/** JSON format */
JSON,
/** XML format */
XML,
/** YAML format */
YAML,
/** HTML format */
HTML,
/** Properties format */
PROPERTIES;
/**
* Get config type from string
*/
public static ConfigType getType(String type);
}
/**
* Configuration filter interface for preprocessing content
*/
interface IConfigFilter {
/**
* Initialize filter
* @param filterConfig Filter configuration
*/
void init(IFilterConfig filterConfig);
/**
* Filter configuration content
* @param configRequest Configuration request
* @param configResponse Configuration response
* @throws NacosException If filtering fails
*/
void doFilter(IConfigRequest configRequest, IConfigResponse configResponse) throws NacosException;
/**
* Get filter name
*/
String getFilterName();
}import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import java.util.Properties;
import java.util.concurrent.Executor;
// Create configuration service
Properties properties = new Properties();
properties.setProperty(PropertyKeyConst.SERVER_ADDR, "127.0.0.1:8848");
properties.setProperty(PropertyKeyConst.NAMESPACE, "development");
ConfigService configService = NacosFactory.createConfigService(properties);
// Get configuration
String dataId = "application.properties";
String group = "DEFAULT_GROUP";
String config = configService.getConfig(dataId, group, 5000);
System.out.println("Current config: " + config);
// Publish configuration
String content = "app.name=MyApplication\napp.version=1.0.0\ndatabase.url=jdbc:mysql://localhost:3306/mydb";
boolean result = configService.publishConfig(dataId, group, content);
System.out.println("Published: " + result);
// Publish with specific type
boolean jsonResult = configService.publishConfig(
"app-config.json",
group,
"{\"name\":\"MyApp\",\"version\":\"1.0\"}",
ConfigType.JSON.name()
);import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
// Simple configuration listener
Listener simpleListener = new AbstractListener() {
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println("Configuration changed: " + configInfo);
// Parse and apply new configuration
applyConfiguration(configInfo);
}
@Override
public Executor getExecutor() {
// Return custom executor for async processing
return Executors.newSingleThreadExecutor();
}
};
// Add listener
configService.addListener(dataId, group, simpleListener);
// Shared listener with detailed change information
AbstractSharedListener detailedListener = new AbstractSharedListener() {
@Override
public void innerReceive(String dataId, String group, String configInfo) {
System.out.printf("Config changed - DataId: %s, Group: %s%n", dataId, group);
System.out.println("New content: " + configInfo);
// Handle different data IDs differently
if ("database.properties".equals(dataId)) {
reconfigureDatabase(configInfo);
} else if ("logging.properties".equals(dataId)) {
reconfigureLogging(configInfo);
}
}
};
configService.addListener("database.properties", group, detailedListener);
configService.addListener("logging.properties", group, detailedListener);import com.alibaba.nacos.api.config.ConfigChangeEvent;
import com.alibaba.nacos.api.config.ConfigChangeItem;
import com.alibaba.nacos.api.config.PropertyChangeType;
// Configuration change event handling
public class ConfigChangeHandler {
public void handleConfigChange(ConfigChangeEvent event) {
System.out.printf("Configuration change in %s:%s%n",
event.getGroup(), event.getDataId());
for (Map.Entry<String, ConfigChangeItem> entry : event.getData().entrySet()) {
ConfigChangeItem item = entry.getValue();
switch (item.getType()) {
case ADDED:
System.out.printf("Added: %s = %s%n",
item.getKey(), item.getNewValue());
break;
case MODIFIED:
System.out.printf("Modified: %s = %s (was: %s)%n",
item.getKey(), item.getNewValue(), item.getOldValue());
break;
case DELETED:
System.out.printf("Deleted: %s (was: %s)%n",
item.getKey(), item.getOldValue());
break;
}
}
}
}
// CAS (Compare and Swap) operations for atomic updates
public boolean atomicConfigUpdate(ConfigService configService,
String dataId, String group,
String expectedContent, String newContent) {
try {
// Get current config with MD5
String currentConfig = configService.getConfig(dataId, group, 3000);
if (!expectedContent.equals(currentConfig)) {
return false; // Content has changed
}
// Calculate MD5 of expected content
String expectedMd5 = calculateMD5(expectedContent);
// Perform atomic update
return configService.publishConfigCas(dataId, group, newContent, expectedMd5);
} catch (NacosException e) {
System.err.println("Failed to perform atomic update: " + e.getMessage());
return false;
}
}import com.alibaba.nacos.api.config.listener.FuzzyWatchEventWatcher;
import java.util.concurrent.Future;
import java.util.Set;
// Watch all configurations in a group pattern
FuzzyWatchEventWatcher groupWatcher = new FuzzyWatchEventWatcher() {
@Override
public void onEvent(FuzzyWatchEvent event) {
System.out.printf("Fuzzy watch event: %s in group %s%n",
event.getDataId(), event.getGroup());
System.out.println("Content: " + event.getContent());
}
@Override
public Executor getExecutor() {
return Executors.newFixedThreadPool(4);
}
};
// Watch all configurations in groups matching pattern
configService.fuzzyWatch("app-*", groupWatcher);
// Watch specific data ID pattern in specific group pattern
configService.fuzzyWatch("*.properties", "DEFAULT_GROUP", groupWatcher);
// Watch with key retrieval
Future<Set<String>> future = configService.fuzzyWatchWithGroupKeys("microservice-*", groupWatcher);
Set<String> matchedKeys = future.get();
System.out.println("Matched configuration keys: " + matchedKeys);import com.alibaba.nacos.api.config.filter.IConfigFilter;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
// Custom configuration filter for decryption
public class DecryptionFilter implements IConfigFilter {
@Override
public void init(IFilterConfig filterConfig) {
// Initialize decryption keys, etc.
}
@Override
public void doFilter(IConfigRequest request, IConfigResponse response) throws NacosException {
String content = response.getContent();
// Decrypt sensitive configuration values
if (content != null && content.contains("encrypted:")) {
String decryptedContent = decryptContent(content);
response.setContent(decryptedContent);
}
}
@Override
public String getFilterName() {
return "decryption-filter";
}
private String decryptContent(String encryptedContent) {
// Implement decryption logic
return encryptedContent.replaceAll("encrypted:(\\w+)", "decrypted_value");
}
}
// Add filter to configuration service
configService.addConfigFilter(new DecryptionFilter());import com.alibaba.nacos.api.exception.NacosException;
public class ConfigurationManager {
private final ConfigService configService;
private final Map<String, String> configCache = new ConcurrentHashMap<>();
public ConfigurationManager(ConfigService configService) {
this.configService = configService;
}
public String getConfigSafely(String dataId, String group, String defaultValue) {
try {
String config = configService.getConfig(dataId, group, 3000);
if (config != null) {
configCache.put(dataId + ":" + group, config);
return config;
}
// Return cached value if available
String cached = configCache.get(dataId + ":" + group);
return cached != null ? cached : defaultValue;
} catch (NacosException e) {
System.err.printf("Failed to get config %s:%s - %s%n",
group, dataId, e.getMessage());
// Return cached value or default
String cached = configCache.get(dataId + ":" + group);
return cached != null ? cached : defaultValue;
}
}
public boolean publishConfigSafely(String dataId, String group, String content) {
for (int retry = 0; retry < 3; retry++) {
try {
boolean result = configService.publishConfig(dataId, group, content);
if (result) {
configCache.put(dataId + ":" + group, content);
return true;
}
} catch (NacosException e) {
System.err.printf("Attempt %d failed to publish config %s:%s - %s%n",
retry + 1, group, dataId, e.getMessage());
if (retry == 2) {
return false; // Final attempt failed
}
try {
Thread.sleep(1000 * (retry + 1)); // Exponential backoff
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
return false;
}
}
}
return false;
}
public void setupResillientListener(String dataId, String group,
Consumer<String> configHandler) {
Listener resilientListener = new AbstractListener() {
@Override
public void receiveConfigInfo(String configInfo) {
try {
configHandler.accept(configInfo);
configCache.put(dataId + ":" + group, configInfo);
} catch (Exception e) {
System.err.printf("Error processing config change for %s:%s - %s%n",
group, dataId, e.getMessage());
}
}
@Override
public Executor getExecutor() {
// Use dedicated thread pool for configuration processing
return Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r, "config-processor-" + dataId);
t.setDaemon(true);
return t;
});
}
};
try {
configService.addListener(dataId, group, resilientListener);
} catch (NacosException e) {
System.err.printf("Failed to add listener for %s:%s - %s%n",
group, dataId, e.getMessage());
}
}
}Install with Tessl CLI
npx tessl i tessl/maven-com-alibaba-nacos--nacos-api