Netflix的archaius

intro

archaius是Netflix oss(open source software)的配置核心。它有很強大的功能,可以讀配置文件的配置,系統的配置,還有zookeeper的配置等等的。

archaius原意是一種變色龍,那麼含義就是根據環境的不同可以改變配置。

我們會講一下它的基本用法和各個配置的覆蓋。

pom

各種依賴衝突把我折騰的都快放棄了,最後調出來的可用版本爲:

<dependencies>
		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-framework</artifactId>
			<version>2.8.0</version>
		</dependency>
		<dependency>
			<groupId>org.apache.curator</groupId>
			<artifactId>curator-recipes</artifactId>
			<version>2.8.0</version>
		</dependency>

		<dependency>
			<groupId>com.netflix.archaius</groupId>
			<artifactId>archaius-core</artifactId>
			<version>0.7.4</version>
		</dependency>

		<dependency>
			<groupId>com.netflix.archaius</groupId>
			<artifactId>archaius-zookeeper</artifactId>
			<version>0.7.4</version>
		</dependency>

		<dependency>
			<groupId>com.netflix.curator</groupId>
			<artifactId>curator-test</artifactId>
			<version>1.3.3</version>
		</dependency>

		<dependency>
			<groupId>commons-configuration</groupId>
			<artifactId>commons-configuration</artifactId>
			<version>1.10</version>
		</dependency>


		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>compile</scope>
		</dependency>

	</dependencies>

basics

一個掌管配置的框架,一定能讀resources下的配置文件。

先建一個config.properties,archaius找resources下的配置文件時,默認找的名字就是config.properties

stringprop=propvalue
listprop=value1, value2, value3
mapprop=key1=value1, key2=value2
longprop=100

我們存放普通的string值,list,map,還有long值,看它是不是都能讀。

@Test
	public void testBasicStringProps() throws InterruptedException {
		DynamicStringProperty sampleProp = DynamicPropertyFactory.getInstance().getStringProperty("stringprop", "");
		System.out.println(sampleProp.get());
	}

取出stringprop對應的value,如果沒有的話就是空字符串。

DynamicPropertyFactory.getInstance()是一個double check的單例模式:

public static DynamicPropertyFactory getInstance() {
        if (config == null) {
            synchronized (ConfigurationManager.class) {
                if (config == null) {
                    AbstractConfiguration configFromManager = ConfigurationManager.getConfigInstance();
                    if (configFromManager != null) {
                        initWithConfigurationSource(configFromManager);
                        initializedWithDefaultConfig = !ConfigurationManager.isConfigurationInstalled();
                        logger.info("DynamicPropertyFactory is initialized with configuration sources: " + configFromManager);
                    }
                }
            }
        }
        return instance;
    }
	@Test
	public void testBasicListProps() {
		DynamicStringListProperty listProperty = new DynamicStringListProperty("listprop", Collections.<String>emptyList());
		listProperty.get().stream().forEach(System.out::println);
	}

取出list的值。

@Test
	public void testBasicMapProps() {
		DynamicStringMapProperty mapProperty = new DynamicStringMapProperty("mapprop", Collections.emptyMap());
		Map<String, String> map = mapProperty.getMap();
		map.forEach((k, v) -> System.out.println(k + "\t" + v));
	}

取出map的值。

@Test
	public void testBasicLongProperty() {
		DynamicLongProperty longProp = DynamicPropertyFactory.getInstance().getLongProperty("longprop", 1000);
		System.out.println(longProp.get());
	}

取出long值。默認是1000,但是我們在配置文件中配了,所以結果是100。


config.properties override

如果我的配置文件不叫config.properties,比如叫newconfig.properties呢?

我們在newconfig.properties中寫:

newstringprop=newstringvalue

如何把它加入進來呢?

@Before
	public void setup() throws IOException {
		ConfigurationManager.loadCascadedPropertiesFromResources("newconfig");
		//System.setProperty("archaius.configurationSource.defaultFileName", "newconfig.properties");
	}
@Test
	public void testBasicStringProps() throws InterruptedException {
		DynamicStringProperty sampleProp = DynamicPropertyFactory.getInstance().getStringProperty("newstringprop", "");
		System.out.println(sampleProp.get());
	}

這樣子就可以取出newstringprop

另一方面,config.properties中的值照舊有效。

如果你使用System.setProperty()的方式:

@Before
	public void setup() throws IOException {
		//ConfigurationManager.loadCascadedPropertiesFromResources("newconfig");
		System.setProperty("archaius.configurationSource.defaultFileName", "newconfig.properties");
	}


那就把newconfig.properties當作默認配置文件了。這時config.properties就失效了。


我們也可以進行配置文件的關聯動態地改值。比如對於環境的修改:

sample.properties中:

sampleprop=samplevalue
@next=sample-$(@environment).properties 

現在我這個sampleprop的值要去sample-xxx.properties的文件中找,@environment需要我們動態地給值。

比如最終找的是sample-test.properties

sampleprop=propvalue-test

測試:

public class TestArchaiusOverriding {
	@Before
	public void setUp() throws IOException {
		ConfigurationManager.getConfigInstance().setProperty("@environment", "test");
		ConfigurationManager.loadCascadedPropertiesFromResources("sample");
	}

	@Test
	public void testOverringEnvironment() {
		DynamicStringProperty sampleProperty = DynamicPropertyFactory.getInstance().getStringProperty("sampleprop", "");
		System.out.println(sampleProperty.get());
	}
}

more configurations and overriding

配置當然還有很多。在接下來的測試中,我們會使用zookeeper配置,自定義的map配置,和系統配置。

啓動zookeeper,建立/config節點。

//zookeeper的根路徑,在自己的zookeeper中建好這個節點
	private static final String CONFIG_ROOT_PATH = "/config";
	//客戶端
	private static CuratorFramework client;
	//zookeeper的配置資源類
	private static ZooKeeperConfigurationSource zkConfigSource;
	//自定義的配置類,就是一個map
	private static ConcurrentMapConfiguration mapConfig;

	private static final Charset charset = Charset.forName("UTF-8");

	@BeforeClass
	public static void setUp() throws Exception {
		//連上本地的zookeeper
		client = CuratorFrameworkFactory.newClient("localhost:2181", new ExponentialBackoffRetry(1000, 3));
		client.start();

		//本地緩存
		zkConfigSource = new ZooKeeperConfigurationSource(client, CONFIG_ROOT_PATH);
		zkConfigSource.start();

		// 設置系統值
		System.setProperty("test.key4", "test.value4-system");
		System.setProperty("test.key5", "test.value5-system");

		final ConcurrentMapConfiguration systemConfig = new ConcurrentMapConfiguration();
		//加載系統值到一個map
		systemConfig.loadProperties(System.getProperties());

		//動態監視zookeeper配置的變化
		final DynamicWatchedConfiguration zkDynamicOverrideConfig = new DynamicWatchedConfiguration(zkConfigSource);

		//自定義map配置
		mapConfig = new ConcurrentMapConfiguration();
		mapConfig.addProperty("test.key1", "test.value1-map");
		mapConfig.addProperty("test.key2", "test.value2-map");
		mapConfig.addProperty("test.key3", "test.value3-map");
		mapConfig.addProperty("test.key4", "test.value4-map");

		//把三種配置合起來
		final ConcurrentCompositeConfiguration compositeConfig = new ConcurrentCompositeConfiguration();
		compositeConfig.addConfiguration(zkDynamicOverrideConfig, "zk dynamic override configuration");
		compositeConfig.addConfiguration(mapConfig, "map configuration");
		compositeConfig.addConfiguration(systemConfig, "system configuration");

		// 設置zookeeper的配置
		setZkProperty("test.key1", "test.value1-zk");
		setZkProperty("test.key2", "test.value2-zk");
		setZkProperty("test.key4", "test.value4-zk");

		//加載配置
		ConfigurationManager.install(compositeConfig);
	}







這三種配置,有一些key是重合的。

比如mapConfigtest.key1test.key2test.key4就與zookeeper一樣,但是值是不同的。

然後我們這裏使用的是zookeeper的客戶端框架curator。

private static void setZkProperty(String key, String value) throws Exception {

		final String path = CONFIG_ROOT_PATH + "/" + key;

		byte[] data = value.getBytes(charset);

		//查看key是否原來存在,有就更新,沒有就建
		try {
			// attempt to create (intentionally doing this instead of checkExists())
			client.create().creatingParentsIfNeeded().forPath(path, data);
		} catch (KeeperException.NodeExistsException exc) {
			// key already exists - update the data instead
			client.setData().forPath(path, data);
		}

	}

這個方法通過zookeeper的client來創建或者更新配置中的值。

//關閉配置資源
	@AfterClass
	public static void tearDown() throws Exception {
		zkConfigSource.close();
	}

最後還要關一下ZooKeeperConfigurationSource

開始測試:

@Test
	public void testZkPropertyOverride() throws Exception {
		setZkProperty("test.key1", "test.value1-zk");
		// there is an override from ZK, so make sure the overridden value is being returned
		System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("test.key1", "default").get());
	}



zookeeper覆蓋mapConfig。

@Test
	public void testNoZkPropertyOverride() throws Exception {
		// there's no override, so the map config value should be returned
		System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("test.key3", "default")
				.get());
	}


沒被zookeeper覆蓋,返回mapConfig中的值。

@Test
	public void testDefault() throws Exception {
		// there's no property set, so the default should be returned
		System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("test.key99", "default")
				.get());
	}


沒有test.key99這個key,返回default。

@Test
	public void testSystemPropertyOverride() throws Exception {
		// there's a system property set, but this should not trump the zk override
		System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("test.key4", "default")
				.get());

		// there's a system property set, but no other overrides, so should return the system property
		System.out.println(DynamicPropertyFactory.getInstance().getStringProperty("test.key5", "default")
				.get());
	}





systemConfigmapConfig和zookeeper中都有test.key4,最終勝出的是zookeeper。

test.key5是系統屬性獨有的。

	@Test
	public void testUpdatePropertyOverride() throws Exception {
		setZkProperty("test.key1", "test.value1-zk");

		// update the map config's property and assert that the value is still the overridden value
		mapConfig.setProperty("test.key1", "prop1");
		System.out.println(DynamicPropertyFactory.getInstance()
				.getStringProperty("test.key1", "default").get());
	}




mapConfig試圖修改test.key1的值,不過那是不會成功的。

	@Test
	public void testUpdateZkProperty() throws Exception {
		setZkProperty("test.key1", "test.value1-zk-override");

		System.out.println(DynamicPropertyFactory.getInstance()
				.getStringProperty("test.key1", "default").get());
	}





zookeeper一動手,就能改成功。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章