Commit ce1fcb15 by Dave Syer

Remove ugly depednency on Environment

You can bind to a Map<String,String> with application.yml, so there's no need to work so hard to extract the zuul routes.
parent 243e163d
......@@ -4,127 +4,95 @@ import java.lang.reflect.Field;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.bind.PropertySourceUtils;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.context.environment.EnvironmentChangeEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.util.ReflectionUtils;
/**
* @author Spencer Gibb
*/
@Slf4j
public class RouteLocator implements ApplicationListener<EnvironmentChangeEvent>, EnvironmentAware {
public class RouteLocator implements ApplicationListener<EnvironmentChangeEvent> {
public static final String DEFAULT_ROUTE = "/";
public static final String DEFAULT_ROUTE = "/";
private ConfigurableEnvironment env = new StandardEnvironment();
private DiscoveryClient discovery;
private DiscoveryClient discovery;
private ZuulProperties properties;
private ZuulProperties properties;
private Field propertySourcesField;
private AtomicReference<LinkedHashMap<String, String>> routes = new AtomicReference<>();
private Field propertySourcesField;
private AtomicReference<LinkedHashMap<String, String>> routes = new AtomicReference<>();
@Override
public void setEnvironment(Environment environment) {
env = (ConfigurableEnvironment) environment;
}
public RouteLocator(DiscoveryClient discovery, ZuulProperties properties) {
this.discovery = discovery;
public RouteLocator(DiscoveryClient discovery, ZuulProperties properties) {
this.discovery = discovery;
this.properties = properties;
initField();
}
private void initField() {
propertySourcesField = ReflectionUtils.findField(CompositePropertySource.class, "propertySources");
propertySourcesField.setAccessible(true);
}
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
for (String key : event.getKeys()) {
if (key.startsWith(properties.getRoutePrefix())) {
routes.set(locateRoutes());
return;
}
}
}
//TODO: respond to changes in eureka
public Map<String, String> getRoutes() {
if (routes.get() == null) {
routes.set(locateRoutes());
}
return routes.get();
}
protected LinkedHashMap<String, String> locateRoutes() {
LinkedHashMap<String, String> routesMap = new LinkedHashMap<>();
//Add routes for discovery services by default
List<String> services = discovery.getServices();
for (String serviceId : services) {
//Ignore specified services
if (!properties.getIgnoredServices().contains(serviceId))
routesMap.put("/" + serviceId + "/**", serviceId);
}
MutablePropertySources propertySources = env.getPropertySources();
for (PropertySource<?> propertySource : propertySources) {
getRoutes(propertySource, routesMap);
}
String defaultServiceId = routesMap.get(DEFAULT_ROUTE);
if (defaultServiceId != null) {
//move the defaultServiceId to the end
routesMap.remove(DEFAULT_ROUTE);
routesMap.put(DEFAULT_ROUTE, defaultServiceId);
}
return routesMap;
}
protected void getRoutes(PropertySource<?> propertySource, Map<String, String> routes) {
if (propertySource instanceof CompositePropertySource) {
try {
@SuppressWarnings("unchecked")
Set<PropertySource<?>> sources = (Set<PropertySource<?>>) propertySourcesField.get(propertySource);
for (PropertySource<?> source : sources) {
getRoutes(source, routes);
}
} catch (IllegalAccessException e) {
return;
}
} else {
//EnumerablePropertySource enumerable = (EnumerablePropertySource) propertySource;
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addLast(propertySource);
Map<String, Object> routeEntries = PropertySourceUtils.getSubProperties(propertySources, properties.getRoutePrefix());
for (Map.Entry<String, Object> entry : routeEntries.entrySet()) {
String serviceId = entry.getKey();
String route = entry.getValue().toString();
if (routes.containsKey(route)) {
log.warn("Overwriting route {}: already defined by {}", route, routes.get(route));
}
routes.put(route, serviceId);
}
}
}
}
private void initField() {
propertySourcesField = ReflectionUtils.findField(CompositePropertySource.class,
"propertySources");
propertySourcesField.setAccessible(true);
}
@Override
public void onApplicationEvent(EnvironmentChangeEvent event) {
for (String key : event.getKeys()) {
if (key.startsWith(properties.getMapping())) {
routes.set(locateRoutes());
return;
}
}
}
public Map<String, String> getRoutes() {
if (routes.get() == null) {
routes.set(locateRoutes());
}
return routes.get();
}
protected LinkedHashMap<String, String> locateRoutes() {
LinkedHashMap<String, String> routesMap = new LinkedHashMap<>();
// Add routes for discovery services by default
List<String> services = discovery.getServices();
for (String serviceId : services) {
// Ignore specified services
if (!properties.getIgnoredServices().contains(serviceId))
routesMap.put("/" + serviceId + "/**", serviceId);
}
addConfiguredRoutes(routesMap);
String defaultServiceId = routesMap.get(DEFAULT_ROUTE);
if (defaultServiceId != null) {
// move the defaultServiceId to the end
routesMap.remove(DEFAULT_ROUTE);
routesMap.put(DEFAULT_ROUTE, defaultServiceId);
}
return routesMap;
}
protected void addConfiguredRoutes(Map<String, String> routes) {
Map<String, String> routeEntries = properties.getRoute();
for (Map.Entry<String, String> entry : routeEntries.entrySet()) {
String serviceId = entry.getKey();
String route = entry.getValue() ;
if (routes.containsKey(route)) {
log.warn("Overwriting route {}: already defined by {}", route,
routes.get(route));
}
routes.put(route, serviceId);
}
}
}
......@@ -58,7 +58,7 @@ public class ZuulHandlerMapping extends AbstractUrlHandlerMapping implements
url = "/" + url;
}
if (StringUtils.hasText(properties.getRoutePrefix())) {
if (StringUtils.hasText(properties.getMapping())) {
url = properties.getMapping() + url;
if (!url.startsWith("/")) {
url = "/" + url;
......
package org.springframework.cloud.netflix.zuul;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author Spencer Gibb
......@@ -14,7 +17,7 @@ import java.util.List;
public class ZuulProperties {
private String mapping = "";
private boolean stripMapping = false;
private String routePrefix = "zuul.route.";
private Map<String,String> route = new HashMap<String, String>();
private boolean addProxyHeaders = true;
private List<String> ignoredServices = Collections.emptyList();
}
package org.springframework.cloud.netflix.zuul;
import com.google.common.collect.Lists;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.mock.env.MockPropertySource;
import java.util.Map;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import static org.mockito.MockitoAnnotations.initMocks;
import com.google.common.collect.Lists;
/**
* @author Spencer Gibb
......@@ -23,6 +25,7 @@ public class RouteLocatorTests {
public static final String IGNOREDSERVICE = "ignoredservice";
public static final String ASERVICE = "aservice";
public static final String MYSERVICE = "myservice";
@Mock
ConfigurableEnvironment env;
......@@ -39,12 +42,8 @@ public class RouteLocatorTests {
ZuulProperties properties = new ZuulProperties();
RouteLocator routeLocator = new RouteLocator(this.discovery, properties);
properties.setIgnoredServices(Lists.newArrayList(IGNOREDSERVICE));
routeLocator.setEnvironment(this.env);
properties.getRoute().put(ASERVICE, "/"+ASERVICE + "/**");
MutablePropertySources propertySources = new MutablePropertySources();
propertySources.addFirst(new MockPropertySource().withProperty("zuul.route."
+ ASERVICE, getMapping(ASERVICE)));
when(env.getPropertySources()).thenReturn(propertySources);
when(discovery.getServices()).thenReturn(
Lists.newArrayList(MYSERVICE, IGNOREDSERVICE));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment