Note: This document is intended for users of Apollo systems. If you are a developer/maintainer of Apollo systems in your company, it is recommended to refer to Apollo Development Guide first.
Note: For Apollo client, you can make a few code changes to downgrade to Java 1.6 if needed, see Issue 483 for details
Apollo client depends on AppId
, Apollo Meta Server
and other environment information to work, so please make sure to read the following instructions and do the correct configuration.
AppId is the identity of the application and is an important piece of information to get the configuration from the server.
There are several ways to set it, from highest to lowest priority, as follows.
Apollo 0.7.0+ supports passing in app.id information via System Property, such as
-Dapp.id=YOUR-APP-ID
Apollo 1.4.0+ supports passing app.id information via the operating system's System Environment APP_ID
, as in
APP_ID=YOUR-APP-ID
Apollo 1.0.0+ supports configuration via Spring Boot's application.properties file, such as
app.id=YOUR-APP-ID
This configuration does not work with multiple war packages deployed in the same tomcat
Make sure that the classpath:/META-INF/app.properties file exists and that its contents look like.
app.id=YOUR-APP-ID
The file location reference is as follows.
Note: app.id is a unique id used to identify the application identity in the format string.
Apollo supports applications with different configurations in different environments, so you need to provide the Apollo Meta Server information of the current environment to Apollo clients at runtime. By default, the meta server and config service are deployed in the same JVM process, so the address of the meta server is the address of the config service.
To achieve high availability of meta server, it is recommended to do dynamic load balancing by SLB (Software Load Balancer). meta server address can also be filled with IP, such as http://1.1.1.1:8080,http://2.2.2.2:8080
, but it is still recommended for production environment Use the domain name (go SLB), because machine expansion, shrinkage, etc. may lead to changes in the IP list.
The following ways to configure apollo meta server information are supported since version 1.0.0, in descending order of priority
apollo.meta
apollo.meta
-Dapollo.meta=http://config-service-url
java -Dapollo.meta=http://config-service-url -jar xxx.jar
System.setProperty("apollo.meta", "http://config-service-url");
apollo.meta=http://config-service-url
in application.properties
or bootstrap.properties
of Spring BootThis configuration does not work with multiple war packages deployed in the same tomcat
APOLLO_META
APOLLO_META
of the operating system_
.server.properties
configuration file
apollo.meta=http://config-service-url
in the server.properties
configuration file/sopt/settings/server.properties
.C:\opt\settings\server.properties
app.properties
configuration file
apollo.meta=http://config-service-url
in classpath:/META-INF/app.properties
${env}_meta
dev
, then the user can configure -Ddev_meta=http://config-service-url
${ENV}_META
(supported since version 1.2.0)
dev
, then the user can configure the OS System Environment DEV_META=http://config-service-url
Via the apollo-env.properties
file
apollo-env.properties
and put it under the classpath of the application or under the config directory of the spring boot applicationThe contents of the file look like this.
dev.meta=http://1.1.1.1:8080
fat.meta=http://apollo.fat.xxx.com
uat.meta=http://apollo.uat.xxx.com
pro.meta=http://apollo.xxx.com
If the Meta Server address cannot be obtained by any of the above means, Apollo will eventually fallback to
http://apollo.meta
as the Meta Server address
In version 1.0.0, Apollo provides the MetaServerProvider SPI, which allows users to inject their own MetaServerProvider to customize the Meta Server address location logic.
Since we use the typical Java Service Loader pattern, it is still relatively simple to implement.
One thing to note is that apollo will iterate through all MetaServerProviders in order at runtime until a MetaServerProvider provides a non-empty Meta Server address, so users need to pay extra attention to the Order of the custom MetaServerProvider. The rule is that smaller Order has higher priority, so MetaServerProvider with Order=0 will be ranked ahead of MetaServerProvider with Order=1.
If your company has many applications that need to access Apollo, it is recommended to package a jar package and then provide a custom Apollo Meta Server positioning logic so that the applications that access Apollo can be used with zero configuration. For example, write your own xx-company-apollo-client
, the jar package depends on apollo-client
, define a custom MetaServerProvider implementation in the jar package by spi, and then the application directly depends on xx-company-apollo-client
.
The implementation of MetaServerProvider can be found in LegacyMetaServerProvider and DefaultMetaServerProvider.
For apollo-client version 0.11.0 and above
In general, it is recommended to use Apollo's Meta Server mechanism to implement service discovery for Config Service, so that high availability of Config Service can be achieved. However, apollo-client also supports skipping Meta Server service discovery, which is mainly used in the following scenarios: 1.
For the above scenarios, you can skip Meta Server service discovery by directly specifying the Config Service address, in descending order of priority, as follows
apollo.config-service
(1.9.0+) or apollo.configService
(before 1.9.0)
apollo.config-service
(1.9.0+) or apollo.configService
(before 1.9.0)-Dapollo.config-service=http://config-service-url:port
java -Dapollo.configService=http://config-service-url:port -jar xxx.jar
System.setProperty("apollo.config-service", "http://config-service-url:port");
APOLLO_CONFIG_SERVICE
(1.9.0+) or APOLLO_CONFIGSERVICE
(before 1.9.0)
APOLLO_CONFIG_SERVICE
(1.9.0+) or APOLLO_CONFIGSERVICE
(before 1.9.0) of the operating system_
.server.properties
configuration file
apollo.config-service=http://config-service-url:port
(1.9.0+) or apollo.configService=http://config-service-url:port
in the server.properties
configuration file (before 1.9.0)/opt/settings/server.properties
C:\opt\settings\server.properties
The Apollo client will cache a copy of the configuration obtained from the server in the local file system, so that if the service is unavailable or the network is down, the configuration can still be restored locally without affecting the normal operation of the application.
The local cache path is located in the following path by default, so please make sure /opt/data
or C:\opt\data\
directory exists and the application has read/write permission.
The local configuration file will be placed under the local cache path in the following filename format.
{appId}+{cluster}+{namespace}.properties
namespace
used by the application, usually application
The content of the file is stored in properties format, for example, if there are two keys, one is request.timeout, and the other is batch, then the content of the file is in the following format.
request.timeout=2000
batch=2000
Note: If deployed in a Kubernetes environment, you can also enable the configMap cache to further improve availability
The following custom cache paths are supported since version 1.0.0, in descending order of priority
apollo.cache-dir
(1.9.0+) or apollo.cacheDir
(before 1.9.0)
apollo.cache-dir
(1.9.0+) or apollo.cacheDir
(before 1.9.0)-Dapollo.cache-dir=/opt/data/some-cache-dir
(1.9.0+) or apollo.cacheDir=/opt/data/some-cache-dir
(before 1.9.0)
java -Dapollo.cache-dir=/opt/data/some-cache-dir -jar xxx.jar
(1.9.0+) or java -Dapollo.cacheDir=/opt/data/some-cache-dir -jar xxx.jar
(before 1.9.0)System.setProperty("apollo.cache-dir", "/opt/data/some-cache-dir");
(1.9.0+) or System.setProperty("apollo.cacheDir", "/opt/data/some-cache-dir");
(before 1.9.0)apollo.cache-dir=/opt/data/some-cache-dir
(1.9.0+) or apollo. cacheDir=/opt/data/some-cache-dir
(before 1.9.0)APOLLO_CACHE_DIR
(1.9.0+) or APOLLO_CACHEDIR
(before 1.9.0)
APOLLO_CACHE_DIR
(1.9.0+) or APOLLO_CACHEDIR
(before 1.9.0)_
.server.properties
configuration file
apollo.cache-dir=/opt/data/some-cache-dir
(1.9.0+) or apollo.cacheDir=/opt/data/some-cache-dir
(before 1.9. 0) in the server.properties
configuration file. 0 or earlier)/opt/settings/server.properties
C:\opt\settings\server.properties
Note: The local cache path can also be used for the disaster recovery directory. If the application needs to be expanded when all the config services are down, then the configuration can also be copied from the cache path on the existing machine to the same cache path on the new machine first
The Environment can be configured in any of the following 3 ways.
Via Java System Property
env
.-Denv=YOUR-ENVIRONMENT
java -Denv=YOUR-ENVIRONMENT -jar xxx.jar
Through the operating system's System Environment
ENV
of the operating systemThrough the configuration file
env=YOUR-ENVIRONMENT
through the configuration file/opt/settings/server.properties
.C:\opt\settings\server.properties
.The contents of the file look like :
env=DEV
Currently, env
supports the following values (case-insensitive).
For more environment definitions, you can refer to Env.java
Apollo supports configuration by cluster, which means that for an appId and an environment, there can be different configurations for different clusters.
The following ways of clustering are supported since version 1.0.0, in descending order of priority.
apollo.cluster
apollo.cluster
-Dapollo.cluster=SomeCluster
java -Dapollo.cluster=SomeCluster -jar xxx.jar
System.setProperty("apollo.cluster", "SomeCluster");
apollo.cluster=SomeCluster
in application.properties
or bootstrap.properties
of Spring Bootidc
.-Didc=xxx
java -Didc=xxx -jar xxx.jar
server.properties
configuration file
idc=xxx
in the server.properties
configuration file/opt/settings/server.properties
.C:\opt\settings\server.properties
Cluster Precedence (cluster order)
If apollo.cluster
and idc
are both specified.
apollo.cluster
idc
.default
)If only apollo.cluster
is specified.
apollo.cluster
default
)If only idc
is specified.
idc
default
)If neither apollo.cluster
nor idc
is specified.
default
)For versions 1.6.0 and above
By default, the in-memory configuration of the apollo client is stored in Properties (Hashtable underneath) and is not intentionally kept in the same order as seen on the page, which has no effect on most scenarios. However, some scenarios will strongly rely on the order of configuration items (such as the routing rules of spring cloud zuul), for this case, you can turn on the OrderedProperties feature to make the in-memory configuration order consistent with what you see on the page.
The configuration methods, in descending order of priority, are
apollo.property.order.enable
-Dapollo.property.order.enable=true
in the Java program startup script
java -Dapollo.property.order.enable=true -jar xxx.jar
System.setProperty("apollo.property.order.enable", "true");
apollo.properties.order.enable=true
in Spring Boot's application.properties
or bootstrap.properties
app.properties
configuration file
apollo.properties.order.enable=true
in classpath:/META-INF/app.properties
For versions 1.6.0 and above
Apollo has added an access key mechanism since version 1.6.0 so that only authenticated clients can access sensitive configurations. If the application has access keys enabled, the client needs to configure the keys, otherwise the configuration cannot be accessed.
The configuration methods are as follows, in descending order of priority
apollo.access-key.secret
(1.9.0+) or apollo.accessskey.secret
(before 1.9.0)
apollo.access-key.secret
(1.9.0+) or apollo.accessskey.secret
(before 1.9.0)-Dapollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719
(1.9.0+) or -Dapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719
(before 1.9.0)
java -Dapollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719 -jar xxx.jar
(1.9.0+) or java -Dapollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719 -jar xxx.jar
(before 1.9.0)System.setProperty("apollo.access-key.secret", "1cf998c4e2ad4704b45a98a509d15719");
(1.9.0+) or System.setProperty("apollo.accesskey.secret", "1cf998c4e2ad4704b45a98a509d15719");
(before 1.9.0)apollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719
in application.properties
or bootstrap.properties
of Spring Boot (1.9.0 +) or apollo.accesskey.secret=1cf998c4e2ad4704b45a98a509d15719
(before 1.9.0)APOLLO_ACCESS_KEY_SECRET
(1.9.0+) or APOLLO_ACCESSKEY_SECRET
(before 1.9.0)app.properties
configuration file
apollo.access-key.secret=1cf998c4e2ad4704b45a98a509d15719
(1.9.0+) or apollo.accessskey.secret=1cf998c4e2ad4704b45a98a509d15719
(before 1.9.0)for version 1.8.0 and above
The following ways to customize the server.properties path are supported since version 1.8.0, in descending order of priority
apollo.path.server.properties
apollo.path.server.properties
-Dapollo.path.server.properties=/some-dir/some-file.properties
in the Java program startup script
java -Dapollo.path.server.properties=/some-dir/some-file.properties -jar xxx.jar
System.setProperty("apollo.path.server.properties", "/some-dir/some-file.properties");
APOLLO_PATH_SERVER_PROPERTIES
APOLLO_PATH_SERVER_PROPERTIES
of the operating system_
.propertyNames
caching, which can significantly improve startup speed in a large number of configuration scenariosFor version 1.9.0 and above
In scenarios where @ConfigurationProperties
is used and there are a large number of configuration items, the Spring container can be slow to start. This configuration can be turned on to significantly improve startup speed, and the cache will be automatically cleared when the configuration changes, default is false
. See: issue 3800
The configuration methods, in descending order of priority, are
apollo.property.names.cache.enable
apollo.property.names.cache.enable
-Dapollo.property.names.cache.enable=true
in the Java program startup script
java -Dapollo.property.names.cache.enable=true -jar xxx.jar
System.setProperty("apollo.property.names.cache.enable", "true");
APOLLO_PROPERTY_NAMES_CACHE_ENABLE=true
before starting the program to specify_
.apollo.properties.names.cache.enable=true
in Spring Boot's application.properties
or bootstrap.properties
.app.properties
configuration file
apollo.property.names.cache.enable=true
in classpath:/META-INF/app.properties
ApolloLabel is the label information of the application, an important piece of information to get the configuration from the server side for the grayscale rules.
There are several ways to set it, from highest to lowest priority, as follows.
Apollo 2.0.0+ supports passing in apollo.label information via System Property, such as
-Dapollo.label=YOUR-APOLLO-LABEL
Apollo 2.0.0+ supports passing apollo.label information through the operating system's System Environment APP_LABEL
, as in
APOLLO_LABEL=YOUR-APOLLO-LABEL
application.properties
Apollo 2.0.0+ supports configuration via Spring Boot's application.properties file, such as
apollo.label=YOUR-APOLLO-LABEL
This configuration is not suitable for multiple war packages deployed in the same tomcat scenario
app.properties
Make sure that the classpath:/META-INF/app.properties
file exists and that its contents are shaped like.
apollo.label=YOUR-APOLLO-LABEL
The file location reference is as follows.
Note: apollo.label is a label used to identify the application identity in the format string.
For version 2.1.0 and above
Flag to indicate that Apollo's remote properties should override system properties. Default true.
The configuration methods, in descending order of priority, are
apollo.override-system-properties
apollo.override-system-properties
-Dapollo.override-system-properties=true
in the Java program startup script
java -Dapollo.override-system-properties=true -jar xxx.jar
System.setProperty("apollo.override-system-properties", "true");
apollo.override-system-properties=true
in Spring Boot's application.properties
or bootstrap.properties
app.properties
configuration file
apollo.override-system-properties=true
in classpath:/META-INF/app.properties
For version 2.4.0 and above
Starting from version 2.4.0, the availability of the client in the Kubernetes environment has been enhanced. After enabling the ConfigMap cache, the client will cache a copy of the configuration information fetched from the server in the ConfigMap. In the case of service unavailability, network issues, and loss of local cache files, the configuration can still be restored from the ConfigMap. Here are the relevant configurations:
apollo.cache.kubernetes.enable
:Whether to enable the ConfigMap cache mechanism, the default is false.
apollo.cache.kubernetes.namespace
:The namespace of the ConfigMap to be used (the namespace in Kubernetes), the default value is "default".
The configuration information will be placed in the specified ConfigMap according to the following correspondence:
namespace: Use the specified value, if not specified, the default is "default"
configMapName: apollo-configcache-{appId}
key:{cluster}___{namespace}
value: The content is the JSON format string of the corresponding configuration information.
appId is the application's own appId, such as 100004458.
cluster is the cluster used by the application, which is usually default if not configured locally
namespace Indicates the configuration namespace used by the application. If '_' appears in the namespace, it will be escaped to '__' when the key is concatenated. Since this feature is extended, so the client-java dependency is set to optional. You need to import the matching version Since read and write operations on the ConfigMap are required, the pod where the client is located must have the corresponding permissions. The specific configuration method can be referred to below.
How to authorize a Pod's Service Account to have read and write permissions for ConfigMap:
Create a Service Account: If there is no Service Account, you need to create one.
apiVersion: v1
kind: ServiceAccount
metadata:
name: my-service-account
namespace: default
Create a Role or ClusterRole: Define a Role or ClusterRole to grant read and write permissions for a specific ConfigMap. If the ConfigMap is used across multiple Namespaces, a ClusterRole should be used.
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: configmap-role
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["get", "list", "watch", "create", "update", "delete"]
Bind the Service Account to the Role or ClusterRole: Use RoleBinding or ClusterRoleBinding to bind the Service Account to the Role or ClusterRole created above.
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: configmap-reader-binding
namespace: default
subjects:
- kind: ServiceAccount
name: my-service-account
namespace: default
roleRef:
kind: Role
name: configmap-role
apiGroup: rbac.authorization.k8s.io
Specify the Service Account in the Pod configuration: Ensure that the Pod's configuration uses the Service Account created above.
apiVersion: v1
kind: Pod
metadata:
name: my-pod
namespace: default
spec:
serviceAccountName: my-service-account
containers:
- name: my-container
image: my-image
Apply the configuration: Use the kubectl command-line tool to apply these configurations.
kubectl apply -f service-account.yaml
kubectl apply -f role.yaml
kubectl apply -f role-binding.yaml
kubectl apply -f pod.yaml
These steps give the Service Account in the Pod read and write permissions for the specified ConfigMap. If the ConfigMap is cross-namespace, use ClusterRole and ClusterRoleBinding instead of Role and RoleBinding, and ensure that these configurations are applied in all Namespaces that need to access the ConfigMap.
Apollo's client jar package has been uploaded to the central repository, the application only needs to be introduced in the following way when it is actually used.
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client</artifactId>
<version>1.7.0</version>
</dependency>
Apollo supports API approach and Spring integration approach, how to choose which one to use?
The API approach is flexible, fully functional, configuration values are updated in real time (hot release), and supports all Java environments.
Spring approach is easy to access and has N cool ways to play with Spring, such as
@Value("${someKeyFromApollo:someDefaultValue}")
spring.datasource.url: ${someKeyFromApollo:someDefaultValue}
spring.datasource.url=jdbc:mysql://localhost:3306/somedb?characterEncoding=utf8
in apolloThe Spring approach can also be used in combination with the API approach, such as injecting Apollo's Config object, you can get the configuration as usual through the API approach:
@ApolloConfig
private Config config; //inject config for namespace application
For more interesting practical usage scenarios and sample code, please refer to apollo-use-cases
The API approach is the easiest and most efficient way to use Apollo configuration without relying on the Spring Framework to use it.
Config config = ConfigService.getAppConfig(); //config instance is singleton for each namespace and is never null
String someKey = "someKeyFromDefaultNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);
With the above config.getProperty you can get the real-time latest configuration value corresponding to someKey.
In addition, the configuration values are fetched from memory, so there is no need for the application to do its own caching.
Listening for configuration change events is only used when the application really cares about configuration changes and needs to be notified when the configuration changes, e.g. when the database connection string changes and the connection needs to be rebuilt, etc.
If you just want to fetch the latest configuration every time, just follow the example above and call config.getProperty.
Config config = ConfigService.getAppConfig(); //config instance is singleton for each namespace and is never null
config.addChangeListener(new ConfigChangeListener() {
@Override
public void onChange(ConfigChangeEvent changeEvent) {
System.out.println("Changes for namespace " + changeEvent.getNamespace());
for (String key : changeEvent.changedKeys()) {
ConfigChange change = changeEvent.getChange(key);
System.out.println(String.format("Found change - key: %s, oldValue: %s, newValue: %s, changeType: %s", change.getPropertyName(), change. getOldValue(), change.getNewValue(), change.getChangeType()));
}
}
});
String somePublicNamespace = "CAT";
Config config = ConfigService.getConfig(somePublicNamespace); //config instance is singleton for each namespace and is never null
String someKey = "someKeyFromPublicNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);
Apollo-Client version 1.3.0 starts to make better support for yaml/yml
, which is used in the same way as properties format.
Config config = ConfigService.getConfig("application.yml");
String someKey = "someKeyFromYmlNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);
To get it, you need to use the ConfigService.getConfigFile
interface and specify the Format, such as ConfigFileFormat.XML
.
String someNamespace = "test";
ConfigFile configFile = ConfigService.getConfigFile("test", ConfigFileFormat.XML);
String content = configFile.getContent();
Specify the corresponding appid and namespace to retrieve the config, and then obtain the properties.
String someAppId = "Animal";
String somePublicNamespace = "CAT";
Config config = ConfigService.getConfig(someAppId, somePublicNamespace);
String someKey = "someKeyFromPublicNamespace";
String someDefaultValue = "someDefaultValueForTheKey";
String value = config.getProperty(someKey, someDefaultValue);
Apollo also supports integration with Spring (Spring 3.1.1+), and only requires some simple configuration.
Apollo currently supports both the more traditional XML-based
configuration and the currently more popular Java-based (recommended)
configuration.
In case of Spring Boot environments, it is recommended to refer to 3.2.1.3 Spring Boot integration methods (recommended) for configuration.
Note that if you have previously used org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
, please replace it with org.springframework.context.support.PropertySourcesPlaceholderConfigurer
. It is not recommended to use PropertyPlaceholderConfigurer after Spring 3.1, use PropertySourcesPlaceholderConfigurer instead.
If you have used <context:property-placeholder>
before, please note that the spring-context.xsd
version introduced in the xml needs to be 3.1 or higher (usually it will be upgraded automatically as long as no version is specified), and it is recommended to introduce it without the version number, e.g.: http://www.springframework.org/schema/context/spring-context.xsd
Note 1: namespace in yaml/yml format supports integration with Spring since version 1.3.0, when injecting you need to fill in the full name with a suffix, such as application.yml
Note 2: Non-properties, non-yaml/yml formatted namespace (e.g. xml, json, etc.) do not support integration with Spring at this time.
Note: You need to add apollo related xml namespace to the configuration file header, otherwise it will report xml syntax errors.
Inject the default namespace configuration into Spring
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:apollo="http://www.ctrip.com/schema/apollo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.ctrip.com/schema/apollo http://www.ctrip.com/schema/apollo.xsd">
<! -- This is the simplest form of configuration, which is generally sufficient for applications, and is used to instruct Apollo to inject the configuration of the application namespace into the Spring environment -->
<apollo:config/>
<bean class="com.ctrip.framework.apollo.spring.TestXmlBean">
<property name="timeout" value="${timeout:100}"/>
<property name="batch" value="${batch:200}"/>
</bean>
</beans>
Inject multiple namespace configuration into Spring
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:apollo="http://www.ctrip.com/schema/apollo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.ctrip.com/schema/apollo http://www.ctrip.com/schema/apollo.xsd">
<! -- This is the simplest form of configuration, which is generally sufficient for applications, and is used to instruct Apollo to inject the configuration of the application namespace into the Spring environment -->
<apollo:config/>
<! -- This is a slightly more complex form of configuration that instructs Apollo to inject the configuration of FX.apollo and application.yml namespace into the Spring environment -->
<apollo:config namespaces="FX.apollo,application.yml"/>
<bean class="com.ctrip.framework.apollo.spring.TestXmlBean">
<property name="timeout" value="${timeout:100}"/>
<property name="batch" value="${batch:200}"/>
</bean>
</beans>
Inject multiple namespaces and specify the order
If multiple property sources have the same key, then the configuration with the highest order will take effect.
If apollo:config does not specify an order, then the default is the lowest priority.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:apollo="http://www.ctrip.com/schema/apollo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.ctrip.com/schema/apollo http://www.ctrip.com/schema/apollo.xsd">
<apollo:config order="2"/>
<! -- This is the most complex form of configuration, instructing Apollo to inject the configuration of FX.apollo and application.yml namespace into the Spring environment, and in order before application -->
<apollo:config namespaces="FX.apollo,application.yml" order="1"/>
<bean class="com.ctrip.framework.apollo.spring.TestXmlBean">
<property name="timeout" value="${timeout:100}"/>
<property name="batch" value="${batch:200}"/>
</bean>
</beans>
Java-based configuration is currently the more popular approach as opposed to XML-based configuration.
Note that @EnableApolloConfig
should be used together with @Configuration
, otherwise it will not take effect.
Inject the default namespace configuration into Spring
// This is the simplest form of configuration and is generally used by applications to instruct Apollo to inject the configuration of application namespace into the Spring environment
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
Inject multiple namespace configuration into Spring
@Configuration
@EnableApolloConfig
public class SomeAppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
// This is a slightly more complex form of configuration, instructing Apollo to inject the configuration of FX.apollo and application.yml namespace into the Spring environment
@Configuration
@EnableApolloConfig({"FX.apollo", "application.yml"})
public class AnotherAppConfig {}
Inject multiple namespaces and specify the order
// This is the most complex form of configuration, instructing Apollo to inject the configuration of FX.apollo and application.yml namespace into the Spring environment, and in the order before application
@Configuration
@EnableApolloConfig(order = 2)
public class SomeAppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
@Configuration
@EnableApolloConfig(value = {"FX.apollo", "application.yml"}, order = 1)
public class AnotherAppConfig {}
4.Support for multiple appid (added in version 2.4.0)
// Added support for loading multiple appid their corresponding namespaces.
// Note that when using multiple appid, if there are keys that are the same,
// only the key from the prioritized loaded appid will be retrieved
@Configuration
@EnableApolloConfig(value = {"FX.apollo", "application.yml"},
multipleConfigs = {@MultipleConfig(appid = "ORDER_SERVICE", namespaces = {"ORDER.apollo"})}
)
public class SomeAppConfig {}
Spring Boot supports the above two integration methods in addition to configuration via application.properties/bootstrap.properties, which enables configuration to be injected at an earlier stage, such as scenarios that use @ConditionalOnProperty
or have some spring-boot-starter needs to read the configuration to do something in the startup phase (e.g. dubbo-spring-boot-project). So for Spring Boot environment it is recommended to access Apollo (requires version 0.10.0 and above) by the following way.
It is very simple to use, you just need to configure it in application.properties/bootstrap.properties according to the following sample.
Example configuration with default application
namespace injected
# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true
Example configuration for injecting non-default application
namespace or multiple namespaces
apollo.bootstrap.enabled = true
# will inject 'application', 'FX.apollo' and 'application.yml' namespaces in bootstrap phase
apollo.bootstrap.namespaces = application,FX.apollo,application.yml
Load Apollo configuration before initializing the logging system (1.2.0+)
Starting with version 1.2.0, if you wish to put logging-related configuration (such as logging.level.root=info
or parameters in logback-spring.xml
) in Apollo management as well, then you can additionally configure apollo.bootstrap.eagerLoad. enabled=true
to put Apollo loading order before logging system loading, for more information you can refer to PR 1614. The reference configuration example is as follows.
# will inject 'application' namespace in bootstrap phase
apollo.bootstrap.enabled = true
# put apollo initialization before logging system initialization
apollo.bootstrap.eagerLoad.enabled = true
For Spring Boot 2.4+ versions there is also support for loading configurations via Config Data Loader mode
apollo-client-config-data
already depends on apollo-client
, so you only need to add this one dependency, not the apollo-client dependency
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client-config-data</artifactId>
<version>1.9.0</version>
</dependency
</dependencies>
app.id
, env
, apollo.meta
(or apollo.config-service
), apollo.cluster
as described aboveapplication.properties
or application.yml
Use the default namespace application
# old way
# apollo.bootstrap.enabled=true
# do not configure apollo.bootstrap.namespaces
# new way
spring.config.import=apollo://
or
# old way
# apollo.bootstrap.enabled=true
# apollo.bootstrap.namespaces=application
# new way
spring.config.import=apollo://application
Use custom namespace
# old way
# apollo.bootstrap.enabled=true
# apollo.bootstrap.namespaces=your-namespace
# new way
spring.config.import=apollo://your-namespace
Using multiple namespaces
Note: spring.config.import
loads the configuration from back to front, while apollo.bootstrap.namespaces
loads it from back to front, just the opposite. To ensure consistency with the original logic, reverse the order of namespaces
# old way
# apollo.bootstrap.enabled=true
# apollo.bootstrap.namespaces=namespace1,namespace2,namespace3
# new way
spring.config.import=apollo://namespace3, apollo://namespace2, apollo://namespace1
For Spring Boot version 2.4 and above, it also supports loading configuration through Config Data Loader mode Apollo's Config Data Loader also provides a webClient-based http client to replace the original http client, so as to easily extend the http client
WebClient can be based on multiple implementations (reactor netty httpclient, jetty reactive httpclient, apache httpclient5), the dependencies to be added are as follows
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client-config-data</artifactId>
<version>1.9.0</version>
</dependency>
<!-- webclient -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<!-- reactor netty httpclient -->
<dependency>
<groupId>io.projectreactor.netty</groupId>
<artifactId>reactor-netty-http</artifactId>
</dependency>
</dependencies>
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client-config-data</artifactId>
<version>1.9.0</version>
</dependency>
<!-- webclient -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<!-- jetty reactive httpclient -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-reactive-httpclient</artifactId>
</dependency>
</dependencies>
Spring boot does not specify the version of apache httpclient5, so you need to manually specify the version here
<dependencies>
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-client-config-data</artifactId>
<version>1.9.0</version>
</dependency>
<!-- webclient -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webflux</artifactId>
</dependency>
<!-- apache httpclient5 -->
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.core5</groupId>
<artifactId>httpcore5-reactive</artifactId>
<version>5.1</version>
</dependency>
</dependencies>
app.id
, env
, apollo.meta
(or apollo.config-service
), apollo.cluster
as described aboveapplication.properties
or application.yml
The default namespace is used here as an example. Please refer to 3.2.1.4.3 for the configuration of namespace.
spring.config.import=apollo://application
apollo.client.extension.enabled=true
Provides a spi implementation of interface com.ctrip.framework.apollo.config.data.extension.webclient.customizer.spi.ApolloClientWebClientCustomizerFactory
After configuring apollo.client.extension.enabled=true
, Apollo's Config Data Loader will try to load the spi's implementation class to customize the webClient
Spring applications usually use Placeholder to inject configuration in the form of ${someKey:someDefaultValue}, such as ${timeout:100}. The key before the colon is the key, and the default value after the colon.
It is recommended to give the default value as much as possible in actual use, so as to avoid runtime errors due to the undefined key.
Versions starting from v0.10.0 support automatic update of placeholders at runtime, see PR #972.
If you need to turn off the automatic update function of placeholder at runtime, you can turn it off in the following two ways:
By setting the System Property apollo.autoUpdateInjectedSpringProperties
, such as passing in -Dapollo.autoUpdateInjectedSpringProperties=false
at startup
By setting the apollo.autoUpdateInjectedSpringProperties
property in META-INF/app.properties, such as
app.id=SampleApp
apollo.autoUpdateInjectedSpringProperties=false
Suppose I have a TestXmlBean with two configuration items that need to be injected:
public class TestXmlBean {
private int timeout;
private int batch;
public void setTimeout(int timeout) {
this.timeout = timeout;
}
public void setBatch(int batch) {
this.batch = batch;
}
public int getTimeout() {
return timeout;
}
public int getBatch() {
return batch;
}
}
Then, I will use the following way to define in XML (assuming that the default application namespace of the application has timeout and batch configuration items):
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:apollo="http://www.ctrip.com/schema/apollo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.ctrip.com/schema/apollo http://www.ctrip.com/schema/apollo.xsd">
<apollo:config/>
<bean class="com.ctrip.framework.apollo.spring.TestXmlBean">
<property name="timeout" value="${timeout:100}"/>
<property name="batch" value="${batch:200}"/>
</bean>
</beans>
Suppose I have a TestJavaConfigBean, which can also be injected using @Value through Java Config:
public class TestJavaConfigBean {
@Value("${timeout:100}")
private int timeout;
private int batch;
@Value("${batch:200}")
public void setBatch(int batch) {
this.batch = batch;
}
public int getTimeout() {
return timeout;
}
public int getBatch() {
return batch;
}
}
In the Configuration class, use it in the following way (assuming the default application namespace of the application has timeout
and batch
configuration items):
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestJavaConfigBean javaConfigBean() {
return new TestJavaConfigBean();
}
}
Spring Boot provides @ConfigurationProperties to inject configuration into bean objects .
Apollo also supports this method. The following example will inject redis.cache.expireSeconds
and redis.cache.commandTimeout
into the expireSeconds
and commandTimeout
fields of SampleRedisConfig respectively.
@ConfigurationProperties(prefix = "redis.cache")
public class SampleRedisConfig {
private int expireSeconds;
private int commandTimeout;
public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}
public void setCommandTimeout(int commandTimeout) {
this.commandTimeout = commandTimeout;
}
}
In the Configuration class, use it in the following way (assuming the default application namespace of the application has redis.cache.expireSeconds
and redis.cache.commandTimeout
configuration items):
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public SampleRedisConfig sampleRedisConfig() {
return new SampleRedisConfig();
}
}
It should be noted that if @ConfigurationProperties
needs to automatically update the injected value when the Apollo configuration changes, you need to use EnvironmentChangeEvent or RefreshScope. For related code implementation, please refer to ZuulPropertiesRefresher.java and SampleRedisConfig.java and SpringBootApolloRefreshConfig.java
Apollo also adds several new Annotations to simplify usage in the Spring environment.
Example of usage is as follows:
public class TestApolloAnnotationBean {
@ApolloConfig
private Config config; //inject config for namespace application
@ApolloConfig("application")
private Config anotherConfig; //inject config for namespace application
@ApolloConfig("FX.apollo")
private Config yetAnotherConfig; //inject config for namespace FX.apollo
@ApolloConfig("application.yml")
private Config ymlConfig; //inject config for namespace application.yml
/**
* ApolloJsonValue annotated on fields example, the default value is specified as empty list - []
* <br />
* jsonBeanProperty=[{"someString":"hello","someInt":100},{"someString":"world!","someInt":200}]
*/
@ApolloJsonValue("${jsonBeanProperty:[]}")
private List<JsonBean> anotherJsonBeans;
@Value("${batch:100}")
private int batch;
//config change listener for namespace application
@ApolloConfigChangeListener
private void someOnChange(ConfigChangeEvent changeEvent) {
//update injected value of batch if it is changed in Apollo
if (changeEvent.isChanged("batch")) {
batch = config.getIntProperty("batch", 100);
}
}
//config change listener for namespace application
@ApolloConfigChangeListener("application")
private void anotherOnChange(ConfigChangeEvent changeEvent) {
//do something
}
//config change listener for namespaces application, FX.apollo and application.yml
@ApolloConfigChangeListener({"application", "FX.apollo", "application.yml"})
private void yetAnotherOnChange(ConfigChangeEvent changeEvent) {
//do something
}
//example of getting config from Apollo directly
//this will always return the latest value of timeout
public int getTimeout() {
return config.getIntProperty("timeout", 200);
}
//example of getting config from injected value
//the program needs to update the injected value when batch is changed in Apollo using @ApolloConfigChangeListener shown above
public int getBatch() {
return this.batch;
}
private static class JsonBean{
private String someString;
private int someInt;
}
}
Use it in the Configuration class as follows:
@Configuration
@EnableApolloConfig
public class AppConfig {
@Bean
public TestApolloAnnotationBean testApolloAnnotationBean() {
return new TestApolloAnnotationBean();
}
}
In many cases, the application may already have a lot of configuration, such as Spring Boot application, there will be configurations such as bootstrap.properties/yml, application.properties/yml, etc.
After the application is connected to Apollo, these configurations can be easily migrated to Apollo. The specific steps are as follows:
META-INF/app.properties
in the applicationapollo-client
to be version 1.3.0
and aboveserver.port
must ensure that the configuration item has been deleted from the local fileSuch as:
spring.application.name=reservation-service
server.port = 8080
logging.level = ERROR
eureka.client.service-url.defaultZone = http://127.0.0.1:8761/eureka/
eureka.client.healthcheck.enabled=true
eureka.client.register-with-eureka = true
eureka.client.fetch-registry = true
eureka.client.eureka-service-url-poll-interval-seconds = 60
eureka.instance.prefer-ip-address = true
There is a sample client project in the project: apollo-demo
, for details, please refer to 2.3 Java Sample Client Start in Apollo Development Guide section.
For more use case demos, please refer to Apollo usage scenarios and sample code.
The above diagram briefly describes the principle of Apollo client implementation.
apollo.refreshInterval
at runtime, in minutes.Apollo client also supports local development mode, which is mainly used when the development environment cannot connect to Apollo server, such as doing related function development on cruise ships or airplanes.
In local development mode, Apollo will only read configuration information from local files, not from Apollo server.
You can enable Apollo local development mode by following the steps below.
Modify the /opt/settings/server.properties
(Mac/Linux) or C:\opt\settings\server.properties
(Windows) file to set the env to Local:
env=Local
For more ways to configure the environment, please refer to 1.2.4.1 Environment
In local development mode, Apollo client will read the files from local, so we need to prepare the configuration file beforehand.
The local configuration directory is located at.
The appId is the appId of the application, e.g. 100004458.
Please make sure the directory exists and the application has read access to it.
[Tip] The recommended way is to use Apollo in normal mode first, so that Apollo will automatically create the directory and generate the configuration file under it.
Local configuration files need to be placed in the local configuration directory according to a certain file name format, which is as follows.
{appId}+{cluster}+{namespace}.properties
namespace
used by the application
, usually application
The content of the file is stored in properties format, for example, if there are two keys, one is request.timeout and the other is batch, then the content of the file is in the following format.
request.timeout=2000
batch=2000
In local development mode, Apollo does not monitor the file content for changes in real time, so if you modify the configuration, you need to restart the application to take effect.
The apollo-mockserver
has been added since version 1.1.0, so that it can well support scenarios where mock configuration is required for unit testing, using the following methods.
<dependency>
<groupId>com.ctrip.framework.apollo</groupId>
<artifactId>apollo-mockserver</artifactId>
<version>1.7.0</version>
</dependency>
The file name convention is mockdata-{namespace}.properties
For more usage demos, see ApolloMockServerApiTest.java and ApolloMockServerSpringIntegrationTest.java.
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestConfiguration.class)
public class SpringIntegrationTest {
// startup apollo's mockserver
@ClassRule
public static EmbeddedApollo embeddedApollo = new EmbeddedApollo();
@Test
@DirtiesContext // This annotation is necessary because configuration injection can mess up the application context
public void testPropertyInject(){
assertEquals("value1", testBean.key1);
assertEquals("value2", testBean.key2);
}
@Test
@DirtiesContext
public void testListenerTriggeredByAdd() throws InterruptedException, ExecutionException, TimeoutException {
String otherNamespace = "othernamespace";
embeddedApollo.addOrModifyPropery(otherNamespace,"someKey","someValue");
ConfigChangeEvent changeEvent = testBean.futureData.get(5000, TimeUnit.MILLISECONDS);
assertEquals(otherNamespace, changeEvent.getNamespace());
assertEquals("someValue", changeEvent.getChange("someKey").getNewValue());
}
@EnableApolloConfig("application")
@Configuration
static class TestConfiguration{
@Bean
public TestBean testBean(){
return new TestBean();
}
}
static class TestBean{
@Value("${key1:default}")
String key1;
@Value("${key2:default}")
String key2;
SettableFuture<ConfigChangeEvent> futureData = SettableFuture.create();
@ApolloConfigChangeListener("othernamespace")
private void onChange(ConfigChangeEvent changeEvent) {
futureData.set(changeEvent);
}
}
}
from version 2.1.0
To satisfy users' different demands on ConfigService load balancing algorithm when using apollo-client, we provide spi since version 2.1.0
The interface is com.ctrip.framework.apollo.spi.ConfigServiceLoadBalancerClient
.
The Input is multiple ConfigServices returned by meta server, and the output is a ConfigService selected.
The default service provider is com.ctrip.framework.apollo.spi.RandomConfigServiceLoadBalancerClient
, which chooses one ConfigService from multiple ConfigServices using random strategy .