Commit 311d8788 by Dave Syer

Re-instate @EnableZuulServer and simplifiy configuration a bit

With this change users can elect not to install the proxy features but still have a Zuul server with @Beans of type ZuulFilter added automatically. Fixes gh-104
parent 789cf6d7
......@@ -609,3 +609,22 @@ An application with the `@EnableZuulProxy` could act as a standalone
server if you set a default route ("/"), for example `zuul.route.home:
/` would route all traffic (i.e. "/**") to the "home" service.
=== Plain Embedded Zuul
You can also run a Zuul server without the proxying, or switch on parts of the proxying platform selectively, if you
use `@EnableZuulServer` (instead of `@EnableZuulProxy`). Any beans that you add to the application of type `ZuulFilter`
will be installed automatically.
In this case the routes into the Zuul server are
still specified by configuring "zuul.routes.*", but there is no service discovery and no proxying, so the
"serviceId" and "url" settings are ignored. For example:
.application.yml
[source,yaml]
----
zuul:
routes:
api: /api/**
----
maps all paths in "/api/**" to the Zuul filter chain.
package org.springframework.cloud.netflix.feign;
import java.net.URI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.archaius.ConfigurableEnvironmentConfiguration;
import org.springframework.context.annotation.Configuration;
......@@ -78,7 +76,6 @@ public class FeignConfiguration {
}
protected <T> T loadBalance(Feign.Builder builder, Class<T> type, String schemeName) {
URI.create(schemeName).getHost();
if(ribbonClient != null) {
return builder.client(ribbonClient).target(type, schemeName);
} else {
......
......@@ -10,12 +10,19 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Sets up a Zuul server endpoint and installs some reverse proxy filters in it, so it can
* forward requests to backend servers. The backends can be registered manually through
* configuration or via Eureka.
*
* @see EnableZuulServer for how to get a Zuul server without any proxying
*
* @author Spencer Gibb
* @author Dave Syer
*/
@EnableCircuitBreaker
@EnableDiscoveryClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ZuulConfiguration.class)
@Import(ZuulProxyConfiguration.class)
public @interface EnableZuulProxy {
}
package org.springframework.cloud.netflix.zuul;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.context.annotation.Import;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.annotation.*;
import org.springframework.context.annotation.Import;
/**
* Set up the application to act as a generic Zuul server without any built-in reverse
* proxy features. The routes into the Zuul server can be configured through
* {@link ZuulProperties} (by default there are none).
*
* @see EnableZuulProxy to see how to get reverse proxy out of the box
*
* @author Spencer Gibb
* @deprecated @see org.springframework.cloud.netflix.zuul.EnableZuulProxy
*/
@EnableCircuitBreaker
@EnableDiscoveryClient
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
......
......@@ -10,6 +10,7 @@ import java.util.concurrent.atomic.AtomicReference;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.netflix.zuul.ZuulProperties.ZuulRoute;
import org.springframework.util.AntPathMatcher;
......@@ -20,7 +21,7 @@ import org.springframework.util.StringUtils;
* @author Spencer Gibb
*/
@Slf4j
public class ProxyRouteLocator {
public class ProxyRouteLocator implements RouteLocator {
public static final String DEFAULT_ROUTE = "/**";
......@@ -49,6 +50,7 @@ public class ProxyRouteLocator {
resetRoutes();
}
@Override
public Collection<String> getRoutePaths() {
return getRoutes().keySet();
}
......@@ -95,11 +97,11 @@ public class ProxyRouteLocator {
break;
}
}
return location == null ? null : new ProxyRouteSpec(id, targetPath, location, prefix);
return location == null ? null : new ProxyRouteSpec(id, targetPath, location,
prefix);
}
// Package access so ZuulHandlerMapping can reset it's mappings
void resetRoutes() {
public void resetRoutes() {
routes.set(locateRoutes());
}
......@@ -110,15 +112,17 @@ public class ProxyRouteLocator {
addConfiguredRoutes(routesMap);
routesMap.putAll(staticRoutes);
// Add routes for discovery services by default
List<String> services = discovery.getServices();
for (String serviceId : services) {
// Ignore specifically ignored services and those that were manually
// configured
String key = "/" + serviceId + "/**";
if (!properties.getIgnoredServices().contains(serviceId)
&& !routesMap.containsKey(key)) {
routesMap.put(key, new ZuulRoute(key, serviceId));
if (discovery != null) {
// Add routes for discovery services by default
List<String> services = discovery.getServices();
for (String serviceId : services) {
// Ignore specifically ignored services and those that were manually
// configured
String key = "/" + serviceId + "/**";
if (!properties.getIgnoredServices().contains(serviceId)
&& !routesMap.containsKey(key)) {
routesMap.put(key, new ZuulRoute(key, serviceId));
}
}
}
......@@ -154,7 +158,7 @@ public class ProxyRouteLocator {
}
protected void addConfiguredRoutes(Map<String, ZuulRoute> routes) {
Map<String, ZuulRoute> routeEntries = properties.getRoutesWithDefaultServiceIds();
Map<String, ZuulRoute> routeEntries = properties.getRoutes();
for (ZuulRoute entry : routeEntries.values()) {
String route = entry.getPath();
if (routes.containsKey(route)) {
......
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.zuul;
import java.util.Collection;
/**
* @author Dave Syer
*
*/
public interface RouteLocator {
Collection<String> getRoutePaths();
}
package org.springframework.cloud.netflix.zuul;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.boot.actuate.endpoint.mvc.MvcEndpoint;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Map;
/**
* Endpoint to display and reset the zuul proxy routes
*
* @author Spencer Gibb
* @author Dave Syer
*/
public class RoutesEndpoint implements MvcEndpoint {
@ManagedResource(description = "Can be used to list and reset the reverse proxy routes")
public class RoutesEndpoint implements MvcEndpoint, ApplicationEventPublisherAware {
private ZuulHandlerMapping handlerMapping;
private ProxyRouteLocator routes;
private ApplicationEventPublisher publisher;
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
this.publisher = publisher;
}
@Autowired
public RoutesEndpoint(ZuulHandlerMapping handlerMapping) {
this.handlerMapping = handlerMapping;
public RoutesEndpoint(ProxyRouteLocator routes) {
this.routes = routes;
}
@RequestMapping(method = RequestMethod.POST)
@ResponseBody
@ManagedOperation
public Map<String, String> reset() {
return handlerMapping.reset();
publisher.publishEvent(new RoutesRefreshedEvent(routes));
return getRoutes();
}
@RequestMapping(method = RequestMethod.GET)
@ResponseBody
@ManagedAttribute
public Map<String, String> getRoutes() {
return handlerMapping.getRoutes();
return routes.getRoutes();
}
@Override
......
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.zuul;
import org.springframework.context.ApplicationEvent;
/**
* @author Dave Syer
*
*/
@SuppressWarnings("serial")
public class RoutesRefreshedEvent extends ApplicationEvent {
private RouteLocator locator;
public RoutesRefreshedEvent(RouteLocator locator) {
super(locator);
this.locator = locator;
}
public RouteLocator getLocator() {
return locator;
}
}
/*
* Copyright 2013-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.netflix.zuul;
import java.util.Collection;
import java.util.LinkedHashSet;
import org.springframework.cloud.netflix.zuul.ZuulProperties.ZuulRoute;
/**
* @author Dave Syer
*
*/
public class SimpleRouteLocator implements RouteLocator {
private ZuulProperties properties;
public SimpleRouteLocator(ZuulProperties properties) {
this.properties = properties;
}
@Override
public Collection<String> getRoutePaths() {
Collection<String> paths = new LinkedHashSet<String>();
for (ZuulRoute route : properties.getRoutes().values()) {
paths.add(route.getPath());
}
return paths;
}
}
......@@ -3,51 +3,37 @@ package org.springframework.cloud.netflix.zuul;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.cloud.netflix.zuul.filters.post.SendErrorFilter;
import org.springframework.cloud.netflix.zuul.filters.post.SendResponseFilter;
import org.springframework.cloud.netflix.zuul.filters.pre.DebugFilter;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
import org.springframework.cloud.netflix.zuul.filters.pre.Servlet30WrapperFilter;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter;
import org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.http.ZuulServlet;
/**
* @author Spencer Gibb
* @author Dave Syer
*/
@Configuration
@EnableConfigurationProperties(ZuulProperties.class)
@ConditionalOnClass(ZuulServlet.class)
@ConditionalOnExpression("${zuul.enabled:true}")
public class ZuulConfiguration {
@Autowired(required = false)
private TraceRepository traces;
@Autowired
private SpringClientFactory clientFactory;
@Autowired
private DiscoveryClient discovery;
@Autowired
private ZuulProperties zuulProperties;
@Bean
public ProxyRouteLocator routes() {
return new ProxyRouteLocator(discovery, zuulProperties);
public RouteLocator routes() {
return new SimpleRouteLocator(zuulProperties);
}
@Bean
......@@ -56,9 +42,8 @@ public class ZuulConfiguration {
}
@Bean
@RefreshScope
public ZuulHandlerMapping zuulHandlerMapping() {
return new ZuulHandlerMapping(routes(), zuulController());
public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes) {
return new ZuulHandlerMapping(routes, zuulController());
}
@Configuration
......@@ -75,8 +60,23 @@ public class ZuulConfiguration {
}
@Bean
public RoutesEndpoint zuulEndpoint() {
return new RoutesEndpoint(zuulHandlerMapping());
public ApplicationListener<ApplicationEvent> zuulRefreshRoutesListener() {
return new ZuulRefreshListener();
}
private static class ZuulRefreshListener implements
ApplicationListener<ApplicationEvent> {
@Autowired
private ZuulHandlerMapping zuulHandlerMapping;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent
|| event instanceof RefreshScopeRefreshedEvent)
zuulHandlerMapping.registerHandlers();
}
}
// pre filters
......@@ -86,35 +86,10 @@ public class ZuulConfiguration {
}
@Bean
public PreDecorationFilter preDecorationFilter() {
return new PreDecorationFilter(routes(), zuulProperties);
}
@Bean
public Servlet30WrapperFilter servlet30WrapperFilter() {
return new Servlet30WrapperFilter();
}
// route filters
@Bean
public RibbonRoutingFilter ribbonRoutingFilter() {
ProxyRequestHelper helper = new ProxyRequestHelper();
if (traces != null) {
helper.setTraces(traces);
}
RibbonRoutingFilter filter = new RibbonRoutingFilter(helper , clientFactory);
return filter;
}
@Bean
public SimpleHostRoutingFilter simpleHostRoutingFilter() {
ProxyRequestHelper helper = new ProxyRequestHelper();
if (traces != null) {
helper.setTraces(traces);
}
return new SimpleHostRoutingFilter(helper);
}
// post filters
@Bean
public SendResponseFilter sendResponseFilter() {
......@@ -125,4 +100,5 @@ public class ZuulConfiguration {
public SendErrorFilter sendErrorFilter() {
return new SendErrorFilter();
}
}
package org.springframework.cloud.netflix.zuul;
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.discovery.DiscoveryHeartbeatEvent;
import org.springframework.cloud.client.discovery.InstanceRegisteredEvent;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
import java.util.Collection;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;
/**
* MVC HandlerMapping that maps incoming request paths to remote services.
*
* @author Spencer Gibb
* @author Dave Syer
*/
@ManagedResource(description = "Can be used to list and reset the reverse proxy routes")
public class ZuulHandlerMapping extends AbstractUrlHandlerMapping implements
ApplicationListener<ApplicationEvent> {
public class ZuulHandlerMapping extends AbstractUrlHandlerMapping {
private ProxyRouteLocator routeLocator;
private RouteLocator routeLocator;
private ZuulController zuul;
private AtomicReference<Object> latestHeartbeat = new AtomicReference<>();
@Autowired
public ZuulHandlerMapping(ProxyRouteLocator routeLocator, ZuulController zuul) {
public ZuulHandlerMapping(RouteLocator routeLocator, ZuulController zuul) {
this.routeLocator = routeLocator;
this.zuul = zuul;
setOrder(-200);
}
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof InstanceRegisteredEvent
|| event instanceof RefreshScopeRefreshedEvent) {
reset();
} else if (event instanceof DiscoveryHeartbeatEvent) {
DiscoveryHeartbeatEvent e = (DiscoveryHeartbeatEvent) event;
if (latestHeartbeat.get() == null || !latestHeartbeat.get().equals(e.getValue())) {
latestHeartbeat.set(e.getValue());
reset();
}
}
}
protected void registerHandlers() {
Collection<String> routes = routeLocator.getRoutePaths();
if (routes.isEmpty()) {
......@@ -64,16 +36,4 @@ public class ZuulHandlerMapping extends AbstractUrlHandlerMapping implements
}
}
@ManagedOperation
public Map<String, String> reset() {
routeLocator.resetRoutes();
registerHandlers();
return getRoutes();
}
@ManagedAttribute
public Map<String, String> getRoutes() {
return routeLocator.getRoutes();
}
}
......@@ -6,6 +6,8 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
......@@ -26,7 +28,8 @@ public class ZuulProperties {
private boolean addProxyHeaders = true;
private List<String> ignoredServices = new ArrayList<String>();
public Map<String, ZuulRoute> getRoutesWithDefaultServiceIds() {
@PostConstruct
public void init() {
for (Entry<String, ZuulRoute> entry : this.routes.entrySet()) {
ZuulRoute value = entry.getValue();
if (!StringUtils.hasText(value.getLocation())) {
......@@ -39,7 +42,6 @@ public class ZuulProperties {
value.path = "/" + entry.getKey() + "/**";
}
}
return this.routes;
}
@Data
......@@ -91,10 +93,10 @@ public class ZuulProperties {
serviceId = location;
}
}
private String extractId(String path) {
path = path.startsWith("/") ? path.substring(1) : path;
path = path.replace("/*","").replace("*", "");
path = path.replace("/*", "").replace("*", "");
return path;
}
}
......
package org.springframework.cloud.netflix.zuul;
import java.util.concurrent.atomic.AtomicReference;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.actuate.trace.TraceRepository;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.cloud.client.discovery.DiscoveryHeartbeatEvent;
import org.springframework.cloud.client.discovery.InstanceRegisteredEvent;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper;
import org.springframework.cloud.netflix.zuul.filters.pre.PreDecorationFilter;
import org.springframework.cloud.netflix.zuul.filters.route.RibbonRoutingFilter;
import org.springframework.cloud.netflix.zuul.filters.route.SimpleHostRoutingFilter;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author Spencer Gibb
* @author Dave Syer
*/
@Configuration
public class ZuulProxyConfiguration extends ZuulConfiguration {
@Autowired(required = false)
private TraceRepository traces;
@Autowired
private SpringClientFactory clientFactory;
@Autowired
private DiscoveryClient discovery;
@Autowired
private ZuulProperties zuulProperties;
@Bean
@Override
public ProxyRouteLocator routes() {
return new ProxyRouteLocator(discovery, zuulProperties);
}
@Bean
// @RefreshScope
public RoutesEndpoint zuulEndpoint() {
return new RoutesEndpoint(routes());
}
// pre filters
@Bean
public PreDecorationFilter preDecorationFilter() {
return new PreDecorationFilter(routes(), zuulProperties);
}
// route filters
@Bean
public RibbonRoutingFilter ribbonRoutingFilter() {
ProxyRequestHelper helper = new ProxyRequestHelper();
if (traces != null) {
helper.setTraces(traces);
}
RibbonRoutingFilter filter = new RibbonRoutingFilter(helper, clientFactory);
return filter;
}
@Bean
public SimpleHostRoutingFilter simpleHostRoutingFilter() {
ProxyRequestHelper helper = new ProxyRequestHelper();
if (traces != null) {
helper.setTraces(traces);
}
return new SimpleHostRoutingFilter(helper);
}
@Bean
@Override
public ApplicationListener<ApplicationEvent> zuulRefreshRoutesListener() {
return new ZuulRefreshListener();
}
private static class ZuulRefreshListener implements
ApplicationListener<ApplicationEvent> {
private AtomicReference<Object> latestHeartbeat = new AtomicReference<>();
@Autowired
private ProxyRouteLocator routeLocator;
@Autowired
ZuulHandlerMapping zuulHandlerMapping;
@Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof InstanceRegisteredEvent
|| event instanceof RefreshScopeRefreshedEvent
|| event instanceof RoutesRefreshedEvent) {
reset();
}
else if (event instanceof DiscoveryHeartbeatEvent) {
DiscoveryHeartbeatEvent e = (DiscoveryHeartbeatEvent) event;
if (latestHeartbeat.get() == null
|| !latestHeartbeat.get().equals(e.getValue())) {
latestHeartbeat.set(e.getValue());
reset();
}
}
}
private void reset() {
routeLocator.resetRoutes();
zuulHandlerMapping.registerHandlers();
}
}
}
......@@ -46,6 +46,7 @@ public class ProxyRouteLocatorTests {
public void testGetMatchingPath() throws Exception {
ProxyRouteLocator routeLocator = new ProxyRouteLocator(this.discovery, this.properties);
this.properties.getRoutes().put("foo", new ZuulRoute("/foo/**"));
properties.init();
routeLocator.getRoutes(); // force refresh
ProxyRouteSpec route = routeLocator.getMatchingRoute("/foo/1");
assertEquals("foo", route.getLocation());
......@@ -57,6 +58,7 @@ public class ProxyRouteLocatorTests {
ProxyRouteLocator routeLocator = new ProxyRouteLocator(this.discovery, this.properties);
this.properties.getRoutes().put("foo", new ZuulRoute("/foo/**"));
this.properties.setPrefix("/proxy");
properties.init();
routeLocator.getRoutes(); // force refresh
ProxyRouteSpec route = routeLocator.getMatchingRoute("/proxy/foo/1");
assertEquals("foo", route.getLocation());
......@@ -104,6 +106,7 @@ public class ProxyRouteLocatorTests {
ZuulRoute zuulRoute = new ZuulRoute("/foo/**");
zuulRoute.setStripPrefix(true);
this.properties.getRoutes().put("foo", zuulRoute);
properties.init();
routeLocator.getRoutes(); // force refresh
ProxyRouteSpec route = routeLocator.getMatchingRoute("/foo/1");
assertEquals("foo", route.getLocation());
......@@ -114,6 +117,7 @@ public class ProxyRouteLocatorTests {
public void testGetRoutes() {
ProxyRouteLocator routeLocator = new ProxyRouteLocator(this.discovery, this.properties);
this.properties.getRoutes().put(ASERVICE, new ZuulRoute("/"+ASERVICE + "/**"));
properties.init();
Map<String, String> routesMap = routeLocator.getRoutes();
......
......@@ -2,13 +2,20 @@ package org.springframework.cloud.netflix.zuul;
import static org.junit.Assert.assertEquals;
import java.util.Arrays;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
......@@ -16,6 +23,15 @@ import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.appinfo.EurekaInstanceConfig;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.netflix.zuul.ZuulFilter;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SampleZuulProxyApplication.class)
......@@ -33,7 +49,7 @@ public class SampleZuulProxyApplicationTests {
private ProxyRouteLocator routes;
@Autowired
private ZuulHandlerMapping mapping;
private RoutesEndpoint endpoint;
@Test
public void bindRouteUsingPhysicalRoute() {
......@@ -47,7 +63,6 @@ public class SampleZuulProxyApplicationTests {
@Test
public void getOnSelfViaRibbonRoutingFilter() {
mapping.reset();
ResponseEntity<String> result = new TestRestTemplate().exchange(
"http://localhost:" + port + "/simple/local/1", HttpMethod.GET,
new HttpEntity<Void>((Void) null), String.class);
......@@ -58,7 +73,7 @@ public class SampleZuulProxyApplicationTests {
@Test
public void deleteOnSelfViaSimpleHostRoutingFilter() {
routes.addRoute("/self/**", "http://localhost:" + port + "/local");
mapping.reset();
endpoint.reset();
ResponseEntity<String> result = new TestRestTemplate().exchange(
"http://localhost:" + port + "/self/1", HttpMethod.DELETE,
new HttpEntity<Void>((Void) null), String.class);
......@@ -67,3 +82,79 @@ public class SampleZuulProxyApplicationTests {
}
}
//Don't use @SpringBootApplication because we don't want to component scan
@Configuration
@EnableAutoConfiguration
@RestController
@EnableZuulProxy
@RibbonClient(name = "simple", configuration = SimpleRibbonClientConfiguration.class)
class SampleZuulProxyApplication {
@RequestMapping("/testing123")
public String testing123() {
throw new RuntimeException("myerror");
}
@RequestMapping("/local")
public String local() {
return "Hello local";
}
@RequestMapping(value = "/local/{id}", method = RequestMethod.DELETE)
public String delete() {
return "Deleted!";
}
@RequestMapping(value = "/local/{id}", method = RequestMethod.GET)
public String get() {
return "Gotten!";
}
@RequestMapping("/")
public String home() {
return "Hello world";
}
@Bean
public ZuulFilter sampleFilter() {
return new ZuulFilter() {
@Override
public String filterType() {
return "pre";
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
return null;
}
@Override
public int filterOrder() {
return 0;
}
};
}
public static void main(String[] args) {
SpringApplication.run(SampleZuulProxyApplication.class, args);
}
}
//Load balancer with fixed server list for "simple" pointing to localhost
@Configuration
class SimpleRibbonClientConfiguration {
@Bean
public ILoadBalancer ribbonLoadBalancer(EurekaInstanceConfig instance) {
BaseLoadBalancer balancer = new BaseLoadBalancer();
balancer.setServersList(Arrays.asList(new Server("localhost", instance
.getNonSecurePort())));
return balancer;
}
}
package org.springframework.cloud.netflix.zuul;
import java.util.Arrays;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.boot.test.TestRestTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.netflix.appinfo.EurekaInstanceConfig;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
import com.netflix.zuul.ZuulFilter;
// Don't use @SpringBootApplication because we don't want to component scan
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = SimpleZuulServerApplication.class)
@WebAppConfiguration
@IntegrationTest({ "server.port: 0"})
@DirtiesContext
public class SimpleZuulServerApplicationTests {
@Value("${local.server.port}")
private int port;
@Autowired
private RouteLocator routes;
@Test
public void bindRoute() {
assertTrue(routes.getRoutePaths().contains("/testing123/**"));
}
@Test
public void getOnSelf() {
ResponseEntity<String> result = new TestRestTemplate().exchange(
"http://localhost:" + port + "/", HttpMethod.GET,
new HttpEntity<Void>((Void) null), String.class);
assertEquals(HttpStatus.OK, result.getStatusCode());
assertEquals("Hello world", result.getBody());
}
@Test
public void getOnSelfViaFilter() {
ResponseEntity<String> result = new TestRestTemplate().exchange(
"http://localhost:" + port + "/testing123/1", HttpMethod.GET,
new HttpEntity<Void>((Void) null), String.class);
assertEquals(HttpStatus.OK, result.getStatusCode());
}
}
//Don't use @SpringBootApplication because we don't want to component scan
@Configuration
@EnableAutoConfiguration
@RestController
@EnableZuulProxy
@EnableDiscoveryClient
@RibbonClient(name = "simple", configuration = SimpleRibbonClientConfiguration.class)
public class SampleZuulProxyApplication {
@RequestMapping("/testing123")
public String testing123() {
throw new RuntimeException("myerror");
}
@EnableZuulServer
class SimpleZuulServerApplication {
@RequestMapping("/local")
public String local() {
return "Hello local";
}
@RequestMapping(value = "/local/{id}", method = RequestMethod.DELETE)
public String delete() {
return "Deleted!";
}
@RequestMapping(value = "/local/{id}", method = RequestMethod.GET)
public String get() {
return "Gotten!";
}
@RequestMapping("/")
public String home() {
return "Hello world";
......@@ -82,15 +110,3 @@ public class SampleZuulProxyApplication {
}
}
// Load balancer with fixed server list for "simple" pointing to localhost
@Configuration
class SimpleRibbonClientConfiguration {
@Bean
public ILoadBalancer ribbonLoadBalancer(EurekaInstanceConfig instance) {
BaseLoadBalancer balancer = new BaseLoadBalancer();
balancer.setServersList(Arrays.asList(new Server("localhost", instance
.getNonSecurePort())));
return balancer;
}
}
\ No newline at end of file
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