Skip to content

Commit

Permalink
Add non-spring-client support and added a demo for it
Browse files Browse the repository at this point in the history
  • Loading branch information
nobodyiam committed Mar 31, 2016
1 parent 46d6e00 commit efa84db
Show file tree
Hide file tree
Showing 34 changed files with 432 additions and 31 deletions.
4 changes: 0 additions & 4 deletions apollo-client/pom.xml
Expand Up @@ -21,10 +21,6 @@
</dependency>
<!-- end of apollo -->
<!-- spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
Expand Down
Expand Up @@ -31,7 +31,8 @@
import java.util.concurrent.atomic.AtomicReference;

/**
* Client side config manager
* Apollo Config for Spring Application
* Requires Spring 3.1+
*
* @author Jason Song(song_s@ctrip.com)
*/
Expand All @@ -57,7 +58,7 @@ public ApolloConfigManager() {
this.configLoaderManager = ConfigLoaderFactory.getInstance().getConfigLoaderManager();
this.configUtil = ConfigUtil.getInstance();
executorService =
Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ConfigManager", true));
Executors.newScheduledThreadPool(1, ApolloThreadFactory.create("ApolloConfigManager", true));
}

@Override
Expand Down Expand Up @@ -135,6 +136,8 @@ private void updateEnvironmentPropertySource(CompositePropertySource currentProp
}

void schedulePeriodicRefresh() {
logger.info("Schedule periodic refresh with interval: {} {}",
configUtil.getRefreshInterval(), configUtil.getRefreshTimeUnit());
executorService.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
Expand Down
@@ -0,0 +1,72 @@
package com.ctrip.apollo.client;

import com.ctrip.apollo.client.model.PropertyChange;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.env.CompositePropertySource;

import java.util.List;

/**
* Apollo config for non-Spring application
*
* @author Jason Song(song_s@ctrip.com)
*/
public class ApolloEnvironment {
private static final Logger logger = LoggerFactory.getLogger(ApolloEnvironment.class);
private static ApolloEnvironment instance = new ApolloEnvironment();

private volatile CompositePropertySource propertySource;
private ApolloEnvironmentManager apolloEnvironmentManager;

private ApolloEnvironment() {
apolloEnvironmentManager = new ApolloEnvironmentManager(this);
}

public void init() {
this.apolloEnvironmentManager.init();
}

public static ApolloEnvironment getInstance() {
return instance;
}

/**
* Return the property value with the given key, or {@code null}
* if the key doesn't exist.
*
* @param key the property name
* @return the property value
*/
public String getProperty(String key) {
if (this.propertySource == null) {
throw new IllegalStateException(
"ApolloEnvironment not initialized, please call ApolloEnvironment.init() first");
}
Object value = this.propertySource.getProperty(key);
if (value == null) {
return null;
}
return (String) value;
}

/**
* Return the property value with the given key, or
* {@code defaultValue} if the key doesn't exist.
*/
public String getProperty(String key, String defaultValue) {
String value = getProperty(key);
return value == null ? defaultValue : value;
}

void updatePropertySource(CompositePropertySource propertySource) {
this.propertySource = propertySource;
}

void updatePropertySource(CompositePropertySource propertySource, List<PropertyChange> changes) {
this.updatePropertySource(propertySource);
//TODO broadcast changes
}

}
@@ -0,0 +1,75 @@
package com.ctrip.apollo.client;

import com.ctrip.apollo.client.loader.ConfigLoaderFactory;
import com.ctrip.apollo.client.loader.ConfigLoaderManager;
import com.ctrip.apollo.client.model.PropertySourceReloadResult;
import com.ctrip.apollo.client.util.ConfigUtil;
import com.ctrip.apollo.core.utils.ApolloThreadFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;

/**
* @author Jason Song(song_s@ctrip.com)
*/
class ApolloEnvironmentManager {
private static final Logger logger = LoggerFactory.getLogger(ApolloEnvironmentManager.class);
private ConfigLoaderManager configLoaderManager;
private ConfigUtil configUtil;
private ScheduledExecutorService executorService;
private ApolloEnvironment apolloEnvironment;

private AtomicBoolean initDone;

ApolloEnvironmentManager(ApolloEnvironment apolloEnvironment) {
this.apolloEnvironment = apolloEnvironment;
this.configLoaderManager = ConfigLoaderFactory.getInstance().getConfigLoaderManager();
this.configUtil = ConfigUtil.getInstance();
this.executorService =
Executors
.newScheduledThreadPool(1,
ApolloThreadFactory.create("ApolloEnvironmentManager", true));
this.initDone = new AtomicBoolean();
}

synchronized void init() {
if (initDone.get()) {
logger.warn("ApolloEnvironmentManager init already done");
return;
}

this.apolloEnvironment.updatePropertySource(this.configLoaderManager.loadPropertySource());
this.schedulePeriodicRefresh();
initDone.set(true);
}

void schedulePeriodicRefresh() {
logger.info("Schedule periodic refresh with interval: {} {}",
configUtil.getRefreshInterval(), configUtil.getRefreshTimeUnit());
this.executorService.scheduleAtFixedRate(
new Runnable() {
@Override
public void run() {
try {
updatePropertySource();
} catch (Throwable ex) {
logger.error("Refreshing config failed", ex);
}
}
}, configUtil.getRefreshInterval(), configUtil.getRefreshInterval(),
configUtil.getRefreshTimeUnit());
}

void updatePropertySource() {
PropertySourceReloadResult result = this.configLoaderManager.reloadPropertySource();
if (result.hasChanges()) {
logger.info("Found changes, refresh environment.");
this.apolloEnvironment.updatePropertySource(result.getPropertySource(), result.getChanges());
}
}

}
Expand Up @@ -11,7 +11,7 @@
@RunWith(Suite.class)
@SuiteClasses({
ApolloConfigManagerTest.class, ConfigLoaderManagerTest.class, RemoteConfigLoaderTest.class,
ConfigUtilTest.class
ConfigUtilTest.class, ApolloEnvironmentTest.class, ApolloEnvironmentManagerTest.class
})
public class AllTests {

Expand Down
@@ -0,0 +1,81 @@
package com.ctrip.apollo.client;

import com.google.common.collect.Lists;

import com.ctrip.apollo.client.loader.ConfigLoaderManager;
import com.ctrip.apollo.client.model.PropertyChange;
import com.ctrip.apollo.client.model.PropertySourceReloadResult;
import com.ctrip.apollo.client.util.ConfigUtil;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.List;
import java.util.concurrent.TimeUnit;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith(MockitoJUnitRunner.class)
public class ApolloEnvironmentManagerTest {
private ApolloEnvironmentManager apolloEnvironmentManager;
@Mock
private ConfigLoaderManager configLoaderManager;
@Mock
private ConfigUtil configUtil;
@Mock
private ApolloEnvironment apolloEnvironment;

@Before
public void setUp() throws Exception {
apolloEnvironmentManager = spy(new ApolloEnvironmentManager(apolloEnvironment));
ReflectionTestUtils
.setField(apolloEnvironmentManager, "configLoaderManager", configLoaderManager);
ReflectionTestUtils.setField(apolloEnvironmentManager, "configUtil", configUtil);

int someInterval = 1;
TimeUnit someUnit = TimeUnit.MINUTES;
when(configUtil.getRefreshInterval()).thenReturn(someInterval);
when(configUtil.getRefreshTimeUnit()).thenReturn(someUnit);
}

@Test
public void testInit() throws Exception {
CompositePropertySource somePropertySource = mock(CompositePropertySource.class);

when(configLoaderManager.loadPropertySource()).thenReturn(somePropertySource);

apolloEnvironmentManager.init();

verify(configLoaderManager, times(1)).loadPropertySource();
verify(apolloEnvironment, times(1)).updatePropertySource(somePropertySource);
}

@Test
public void testUpdatePropertySource() throws Exception {
PropertySourceReloadResult someResult = mock(PropertySourceReloadResult.class);
CompositePropertySource somePropertySource = mock(CompositePropertySource.class);
List<PropertyChange> someChanges = Lists.newArrayList();

when(someResult.hasChanges()).thenReturn(true);
when(someResult.getPropertySource()).thenReturn(somePropertySource);
when(someResult.getChanges()).thenReturn(someChanges);
when(configLoaderManager.reloadPropertySource()).thenReturn(someResult);

apolloEnvironmentManager.updatePropertySource();

verify(configLoaderManager, times(1)).reloadPropertySource();
verify(apolloEnvironment, times(1)).updatePropertySource(somePropertySource, someChanges);
}
}
@@ -0,0 +1,75 @@
package com.ctrip.apollo.client;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.test.util.ReflectionTestUtils;

import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

/**
* @author Jason Song(song_s@ctrip.com)
*/
@RunWith(MockitoJUnitRunner.class)
public class ApolloEnvironmentTest {
private ApolloEnvironment apolloEnvironment;
@Mock
private ApolloEnvironmentManager apolloEnvironmentManager;

@Before
public void setUp() throws Exception {
apolloEnvironment = spy(ApolloEnvironment.getInstance());
ReflectionTestUtils
.setField(apolloEnvironment, "apolloEnvironmentManager", apolloEnvironmentManager);

}

@Test
public void testInit() throws Exception {
apolloEnvironment.init();

verify(apolloEnvironmentManager, times(1)).init();
}

@Test
public void testGetProperty() throws Exception {
CompositePropertySource somePropertySource = mock(CompositePropertySource.class);
String someKey = "someKey";
String someValue = "someValue";
apolloEnvironment.updatePropertySource(somePropertySource);

when(somePropertySource.getProperty(someKey)).thenReturn(someValue);

String result = apolloEnvironment.getProperty(someKey);

assertEquals(someValue, result);
}

@Test
public void testGetPropertyWithDefaultValue() throws Exception {
CompositePropertySource somePropertySource = mock(CompositePropertySource.class);
String someKey = "someKey";
String someDefaultValue = "someDefault";
apolloEnvironment.updatePropertySource(somePropertySource);

when(somePropertySource.getProperty(someKey)).thenReturn(null);

String result = apolloEnvironment.getProperty(someKey, someDefaultValue);

assertEquals(someDefaultValue, result);
}

@Test(expected = IllegalStateException.class)
public void testGetPropertyWithNoPropertySource() throws Exception {
String someKey = "someKey";
apolloEnvironment.getProperty(someKey);
}
}

0 comments on commit efa84db

Please sign in to comment.