Commit 1e716ff2 by Spencer Gibb

Upgrade eureka to v1.3.4

fixes gh-589
parent 55667497
......@@ -26,7 +26,7 @@
<spring-cloud-stream.version>1.0.0.BUILD-SNAPSHOT</spring-cloud-stream.version>
<main.basedir>${basedir}</main.basedir>
<archaius.version>0.6.5</archaius.version>
<eureka.version>1.2.5</eureka.version>
<eureka.version>1.3.4</eureka.version>
<feign.version>8.11.0</feign.version>
<hystrix.version>1.4.18</hystrix.version>
<ribbon.version>2.1.0</ribbon.version>
......
/*
* Copyright 2013-2015 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.eureka;
import com.netflix.discovery.shared.transport.EurekaTransportConfig;
import lombok.Data;
/**
* @author Spencer Gibb
*/
@Data
public class CloudEurkeaTransportConfig implements EurekaTransportConfig {
private int sessionedClientReconnectIntervalSeconds = 20 * 60;
private double retryableClientQuarantineRefreshPercentage = 0.66;
private int bootstrapResolverRefreshIntervalSeconds = 5 * 60;
private int applicationsResolverDataStalenessThresholdSeconds = 5 * 60;
private int asyncResolverRefreshIntervalMs = 5 * 60 * 1000;
private int asyncResolverWarmUpTimeoutMs = 5000;
private int asyncExecutorThreadPoolSize = 5;
private String readClusterVip;
private boolean bootstrapResolverForQuery = true;
@Override
public boolean useBootstrapResolverForQuery() {
return this.bootstrapResolverForQuery;
}
}
......@@ -22,22 +22,30 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.core.env.PropertyResolver;
import com.netflix.appinfo.EurekaAccept;
import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.shared.transport.EurekaTransportConfig;
import lombok.Data;
/**
* @author Dave Syer
*/
@Data
@ConfigurationProperties("eureka.client")
public class EurekaClientConfigBean implements EurekaClientConfig {
@ConfigurationProperties(EurekaClientConfigBean.PREFIX)
public class EurekaClientConfigBean implements EurekaClientConfig, EurekaConstants {
public static final String PREFIX = "eureka.client";
@Autowired(required = false)
PropertyResolver propertyResolver;
public static final String DEFAULT_URL = "http://localhost:8761"
+ EurekaServerConfigBean.DEFAULT_PREFIX + "/";
+ DEFAULT_PREFIX + "/";
public static final String DEFAULT_ZONE = "defaultZone";
......@@ -45,6 +53,8 @@ public class EurekaClientConfigBean implements EurekaClientConfig {
private boolean enabled = true;
private EurekaTransportConfig transport = new CloudEurkeaTransportConfig();
private int registryFetchIntervalSeconds = 30;
private int instanceInfoReplicationIntervalSeconds = 30;
......@@ -207,4 +217,17 @@ public class EurekaClientConfigBean implements EurekaClientConfig {
return this.onDemandUpdateStatusChange;
}
@Override
public String getExperimental(String name) {
if (propertyResolver != null) {
return propertyResolver.getProperty(PREFIX + ".experimental." + name,
String.class, null);
}
return null;
}
@Override
public EurekaTransportConfig getTransportConfig() {
return getTransport();
}
}
/*
* Copyright 2013-2014 the original author or authors.
* Copyright 2013-2015 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.
......@@ -14,16 +14,13 @@
* limitations under the License.
*/
package org.springframework.cloud.netflix.eureka.server.advice;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.eureka.lease.LeaseManager;
package org.springframework.cloud.netflix.eureka;
/**
* @author Dave Syer
* @author Spencer Gibb
*/
public interface LeaseManagerLite<T> extends LeaseManager<T> {
public interface EurekaConstants {
void register(InstanceInfo info, boolean isReplication);
String DEFAULT_PREFIX = "/eureka";
}
......@@ -68,6 +68,10 @@
<groupId>com.netflix.archaius</groupId>
<artifactId>archaius-core</artifactId>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
</dependency>
<!-- Eureka deps that are now optional in eureka -->
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
......
......@@ -27,6 +27,10 @@ import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import com.netflix.eureka.EurekaServerContext;
import com.netflix.eureka.EurekaServerContextHolder;
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
import com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
......@@ -39,7 +43,6 @@ import com.netflix.appinfo.InstanceInfo;
import com.netflix.config.ConfigurationManager;
import com.netflix.discovery.shared.Application;
import com.netflix.discovery.shared.Pair;
import com.netflix.eureka.PeerAwareInstanceRegistryImpl;
import com.netflix.eureka.cluster.PeerEurekaNode;
import com.netflix.eureka.resources.StatusResource;
import com.netflix.eureka.util.StatusInfo;
......@@ -78,19 +81,17 @@ public class EurekaController {
@RequestMapping(value = "/lastn", method = RequestMethod.GET)
public String lastn(HttpServletRequest request, Map<String, Object> model) {
populateBase(request, model);
PeerAwareInstanceRegistryImpl registery = PeerAwareInstanceRegistryImpl.getInstance();
PeerAwareInstanceRegistryImpl registry = (PeerAwareInstanceRegistryImpl) getRegistry();
ArrayList<Map<String, Object>> lastNCanceled = new ArrayList<>();
List<Pair<Long, String>> list = registery.getLastNCanceledInstances();
List<Pair<Long, String>> list = registry.getLastNCanceledInstances();
for (Pair<Long, String> entry : list) {
lastNCanceled.add(registeredInstance(entry.second(), entry.first()
.longValue()));
lastNCanceled.add(registeredInstance(entry.second(), entry.first()));
}
model.put("lastNCanceled", lastNCanceled);
list = registery.getLastNRegisteredInstances();
list = registry.getLastNRegisteredInstances();
ArrayList<Map<String, Object>> lastNRegistered = new ArrayList<>();
for (Pair<Long, String> entry : list) {
lastNRegistered.add(registeredInstance(entry.second(), entry.first()
.longValue()));
lastNRegistered.add(registeredInstance(entry.second(), entry.first()));
}
model.put("lastNRegistered", lastNRegistered);
return "eureka/lastn";
......@@ -119,9 +120,9 @@ public class EurekaController {
.getDeploymentEnvironment());
model.put("datacenter", ConfigurationManager.getDeploymentContext()
.getDeploymentDatacenter());
model.put("registry", PeerAwareInstanceRegistryImpl.getInstance());
model.put("isBelowRenewThresold", PeerAwareInstanceRegistryImpl.getInstance()
.isBelowRenewThresold() == 1);
PeerAwareInstanceRegistry registry = getRegistry();
model.put("registry", registry);
model.put("isBelowRenewThresold", registry.isBelowRenewThresold() == 1);
DataCenterInfo info = applicationInfoManager.getInfo().getDataCenterInfo();
if (info.getName() == DataCenterInfo.Name.Amazon) {
AmazonInfo amazonInfo = (AmazonInfo) info;
......@@ -133,10 +134,17 @@ public class EurekaController {
}
}
private PeerAwareInstanceRegistry getRegistry() {
return getServerContext().getRegistry();
}
private EurekaServerContext getServerContext() {
return EurekaServerContextHolder.getInstance().getServerContext();
}
private void populateNavbar(HttpServletRequest request, Map<String, Object> model) {
Map<String, String> replicas = new LinkedHashMap<>();
List<PeerEurekaNode> list = PeerAwareInstanceRegistryImpl.getInstance()
.getReplicaNodes();
List<PeerEurekaNode> list = getServerContext().getPeerEurekaNodes().getPeerNodesView();
for (PeerEurekaNode node : list) {
try {
URI uri = new URI(node.getServiceUrl());
......@@ -151,8 +159,7 @@ public class EurekaController {
}
private void populateApps(Map<String, Object> model) {
List<com.netflix.discovery.shared.Application> sortedApplications = PeerAwareInstanceRegistryImpl
.getInstance().getSortedApplications();
List<Application> sortedApplications = getRegistry().getSortedApplications();
ArrayList<Map<String, Object>> apps = new ArrayList<>();
for (Application app : sortedApplications) {
LinkedHashMap<String, Object> appData = new LinkedHashMap<>();
......@@ -174,17 +181,17 @@ public class EurekaController {
}
Integer count = amiCounts.get(ami);
if (count != null) {
amiCounts.put(ami, Integer.valueOf(count.intValue() + 1));
amiCounts.put(ami, count + 1);
}
else {
amiCounts.put(ami, Integer.valueOf(1));
amiCounts.put(ami, 1);
}
count = zoneCounts.get(zone);
if (count != null) {
zoneCounts.put(zone, Integer.valueOf(count.intValue() + 1));
zoneCounts.put(zone, count + 1);
}
else {
zoneCounts.put(zone, Integer.valueOf(1));
zoneCounts.put(zone, 1);
}
List<Pair<String, String>> list = instancesByStatus.get(status);
if (list == null) {
......
/*
* Copyright 2013-2015 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.eureka.server;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.config.ConfigurationManager;
import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.converters.JsonXStream;
import com.netflix.discovery.converters.XmlXStream;
import com.netflix.eureka.EurekaBootStrap;
import com.netflix.eureka.EurekaServerConfig;
import com.netflix.eureka.EurekaServerContext;
import com.netflix.eureka.EurekaServerContextHolder;
import com.netflix.eureka.V1AwareInstanceInfoConverter;
import com.netflix.eureka.aws.AwsBinderDelegate;
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
import com.netflix.eureka.util.EurekaMonitors;
import com.thoughtworks.xstream.XStream;
import lombok.extern.apachecommons.CommonsLog;
/**
* @author Spencer Gibb
*/
@CommonsLog
public class EurekaServerBootstrap extends EurekaBootStrap {
private static final String TEST = "test";
private static final String ARCHAIUS_DEPLOYMENT_ENVIRONMENT = "archaius.deployment.environment";
private static final String EUREKA_ENVIRONMENT = "eureka.environment";
private static final String DEFAULT = "default";
private static final String ARCHAIUS_DEPLOYMENT_DATACENTER = "archaius.deployment.datacenter";
private static final String EUREKA_DATACENTER = "eureka.datacenter";
private EurekaServerConfig eurekaServerConfig;
private ApplicationInfoManager applicationInfoManager;
private EurekaClientConfig eurekaClientConfig;
private PeerAwareInstanceRegistry registry;
public EurekaServerBootstrap(ApplicationInfoManager applicationInfoManager, EurekaClientConfig eurekaClientConfig, EurekaServerConfig eurekaServerConfig, PeerAwareInstanceRegistry registry, EurekaServerContext serverContext) {
this.applicationInfoManager = applicationInfoManager;
this.eurekaClientConfig = eurekaClientConfig;
this.eurekaServerConfig = eurekaServerConfig;
this.registry = registry;
this.serverContext = serverContext;
}
@Override
public void contextInitialized(ServletContextEvent event) {
//NO-OP so it doesn't get initialzed by servlet container, we want spring to init
}
@Override
public void contextDestroyed(ServletContextEvent event) {
//NO-OP so it doesn't get destroyed by servlet container, we want spring to destroy
}
public void contextInitialized(ServletContext context) {
try {
initEurekaEnvironment();
initEurekaServerContext();
context.setAttribute(EurekaServerContext.class.getName(), serverContext);
} catch (Throwable e) {
log.error("Cannot bootstrap eureka server :", e);
throw new RuntimeException("Cannot bootstrap eureka server :", e);
}
}
public void contextDestroyed(ServletContext context) {
try {
log.info("Shutting down Eureka Server..");
context.removeAttribute(EurekaServerContext.class.getName());
destroyEurekaServerContext();
destroyEurekaEnvironment();
} catch (Throwable e) {
log.error("Error shutting down eureka", e);
}
log.info("Eureka Service is now shutdown...");
}
@Override
protected void initEurekaEnvironment() throws Exception {
log.info("Setting the eureka configuration..");
String dataCenter = ConfigurationManager.getConfigInstance().getString(EUREKA_DATACENTER);
if (dataCenter == null) {
log.info("Eureka data center value eureka.datacenter is not set, defaulting to default");
ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, DEFAULT);
} else {
ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_DATACENTER, dataCenter);
}
String environment = ConfigurationManager.getConfigInstance().getString(EUREKA_ENVIRONMENT);
if (environment == null) {
ConfigurationManager.getConfigInstance().setProperty(ARCHAIUS_DEPLOYMENT_ENVIRONMENT, TEST);
log.info("Eureka environment value eureka.environment is not set, defaulting to test");
}
}
@Override
protected void initEurekaServerContext() throws Exception {
// For backward compatibility
JsonXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);
XmlXStream.getInstance().registerConverter(new V1AwareInstanceInfoConverter(), XStream.PRIORITY_VERY_HIGH);
if (isAws(applicationInfoManager.getInfo())) {
awsBinder = new AwsBinderDelegate(eurekaServerConfig, eurekaClientConfig, registry, applicationInfoManager);
awsBinder.start();
}
EurekaServerContextHolder.initialize(serverContext);
log.info("Initialized server context");
// Copy registry from neighboring eureka node
int registryCount = registry.syncUp();
registry.openForTraffic(applicationInfoManager, registryCount);
// Register all monitoring statistics.
EurekaMonitors.registerAllStats();
}
}
/*
* Copyright 2013-2014 the original author or authors.
* Copyright 2013-2015 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.
......@@ -14,30 +14,38 @@
* limitations under the License.
*/
package org.springframework.cloud.netflix.eureka;
package org.springframework.cloud.netflix.eureka.server;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import com.netflix.eureka.aws.AwsBindingStrategy;
import lombok.Data;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import com.netflix.eureka.EurekaServerConfig;
import org.springframework.cloud.netflix.eureka.EurekaConstants;
import org.springframework.core.env.PropertyResolver;
/**
* @author Dave Syer
*/
@Data
@ConfigurationProperties("eureka.server")
public class EurekaServerConfigBean implements EurekaServerConfig {
@ConfigurationProperties(EurekaServerConfigBean.PREFIX)
public class EurekaServerConfigBean implements EurekaServerConfig, EurekaConstants {
public static final String DEFAULT_PREFIX = "/eureka";
public static final String PREFIX = "eureka.server";
private static final int MINUTES = 60 * 1000;
@Autowired(required = false)
PropertyResolver propertyResolver;
private String aWSAccessId;
private String aWSSecretKey;
......@@ -46,6 +54,8 @@ public class EurekaServerConfigBean implements EurekaServerConfig {
private int eIPBindingRetryIntervalMs = 5 * MINUTES;
private int eIPBindingRetryIntervalMsWhenUnbound = 1 * MINUTES;
private boolean enableSelfPreservation = true;
private double renewalPercentThreshold = 0.85;
......@@ -100,7 +110,10 @@ public class EurekaServerConfigBean implements EurekaServerConfig {
private boolean syncWhenTimestampDiffers = true;
private int registrySyncRetries = 5;
//TODO: what should these defaults be? for single first?
private int registrySyncRetries = 0;
private long registrySyncRetryWaitMs = 30 * 1000;
private int maxElementsInPeerReplicationPool = 10000;
......@@ -128,7 +141,7 @@ public class EurekaServerConfigBean implements EurekaServerConfig {
private boolean gZipContentFromRemoteRegion = true;
private Map<String, String> remoteRegionUrlsWithName = new HashMap<String, String>();
private Map<String, String> remoteRegionUrlsWithName = new HashMap<>();
private String[] remoteRegionUrls;
......@@ -168,6 +181,14 @@ public class EurekaServerConfigBean implements EurekaServerConfig {
private String xmlCodecName;
private int route53BindRebindRetries = 3;
private int route53BindingRetryIntervalMs = 5 * MINUTES;
private long route53DomainTTL = 30;
private AwsBindingStrategy bindingStrategy = AwsBindingStrategy.EIP;
@Override
public boolean shouldEnableSelfPreservation() {
return this.enableSelfPreservation;
......@@ -238,4 +259,13 @@ public class EurekaServerConfigBean implements EurekaServerConfig {
public boolean shouldEnableReplicatedRequestCompression() {
return this.enableReplicatedRequestCompression;
}
@Override
public String getExperimental(String name) {
if (propertyResolver != null) {
return propertyResolver.getProperty(PREFIX + ".experimental." + name,
String.class, null);
}
return null;
}
}
......@@ -28,13 +28,14 @@ import javax.ws.rs.ext.Provider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.web.HttpEncodingProperties;
import org.springframework.boot.context.embedded.FilterRegistrationBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.actuator.HasFeatures;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.EurekaServerConfigBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
......@@ -47,6 +48,15 @@ import org.springframework.util.ClassUtils;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.EurekaClientConfig;
import com.netflix.eureka.DefaultEurekaServerContext;
import com.netflix.eureka.EurekaServerConfig;
import com.netflix.eureka.EurekaServerContext;
import com.netflix.eureka.cluster.PeerEurekaNodes;
import com.netflix.eureka.registry.PeerAwareInstanceRegistry;
import com.netflix.eureka.resources.DefaultServerCodecs;
import com.netflix.eureka.resources.ServerCodecs;
import com.sun.jersey.api.core.DefaultResourceConfig;
import com.sun.jersey.spi.container.servlet.ServletContainer;
......@@ -68,17 +78,82 @@ public class EurekaServerConfiguration extends WebMvcConfigurerAdapter {
@Autowired
private ApplicationInfoManager applicationInfoManager;
@Autowired
private EurekaServerConfig eurekaServerConfig;
@Autowired
private EurekaClientConfig eurekaClientConfig;
@Autowired
private EurekaClient eurekaClient;
/*
* Setting expectedNumberOfRenewsPerMin to non-zero to ensure that even an isolated
* server can adjust its eviction policy to the number of registrations (when it's
* zero, even a successful registration won't reset the rate threshold in
* InstanceRegistry.register()).
*/
@Value("${eureka.server.expectedNumberOfRenewsPerMin:1}")
private int expectedNumberOfRenewsPerMin;
@Value("${eureka.server.defaultOpenForTrafficCount:1}")
private int defaultOpenForTrafficCount;
@Bean
public HasFeatures eurekaServerFeature() {
return HasFeatures.namedFeature("Eureka Server", EurekaServerConfiguration.class);
}
//TODO: is there a better way?
@Bean(name = "spring.http.encoding.CONFIGURATION_PROPERTIES")
public HttpEncodingProperties httpEncodingProperties() {
HttpEncodingProperties properties = new HttpEncodingProperties();
properties.setForce(false);
return properties;
}
@Bean
@ConditionalOnProperty(prefix = "eureka.dashboard", name = "enabled", matchIfMissing = true)
public EurekaController eurekaController() {
return new EurekaController(applicationInfoManager);
}
@Bean
public ServerCodecs serverCodecs() {
return new DefaultServerCodecs(eurekaServerConfig);
}
@Bean
public PeerAwareInstanceRegistry peerAwareInstanceRegistry(ServerCodecs serverCodecs) {
eurekaClient.getApplications(); // force initialization
expectedNumberOfRenewsPerMin = 1;
defaultOpenForTrafficCount = 1;
return new InstanceRegistry(eurekaServerConfig, eurekaClientConfig, serverCodecs,
eurekaClient, expectedNumberOfRenewsPerMin, defaultOpenForTrafficCount);
}
@Bean
public PeerEurekaNodes peerEurekaNodes(PeerAwareInstanceRegistry registry,
ServerCodecs serverCodecs) {
return new PeerEurekaNodes(registry, eurekaServerConfig, eurekaClientConfig,
serverCodecs, applicationInfoManager);
}
@Bean
public EurekaServerContext eurekaServerContext(ServerCodecs serverCodecs,
PeerAwareInstanceRegistry registry,
PeerEurekaNodes peerEurekaNodes) {
return new DefaultEurekaServerContext(eurekaServerConfig, serverCodecs, registry,
peerEurekaNodes, applicationInfoManager);
}
@Bean
public EurekaServerBootstrap eurekaServerBootstrap(PeerAwareInstanceRegistry registry,
EurekaServerContext serverContext) {
return new EurekaServerBootstrap(applicationInfoManager, eurekaClientConfig,
eurekaServerConfig, registry, serverContext);
}
/**
* Register the Jersey filter
*
......
......@@ -16,58 +16,33 @@
package org.springframework.cloud.netflix.eureka.server;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.ProxyFactory;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.logging.log4j.Log4JLoggingSystem;
import org.springframework.cloud.netflix.eureka.EurekaServerConfigBean;
import org.springframework.cloud.netflix.eureka.server.advice.LeaseManagerLite;
import org.springframework.cloud.netflix.eureka.server.advice.PiggybackMethodInterceptor;
import org.springframework.cloud.netflix.eureka.server.event.EurekaRegistryAvailableEvent;
import org.springframework.cloud.netflix.eureka.server.event.EurekaServerStartedEvent;
import org.springframework.cloud.netflix.eureka.server.event.LeaseManagerMessageBroker;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.SmartLifecycle;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.context.ServletContextAware;
import com.netflix.discovery.EurekaClient;
import com.netflix.eureka.AbstractInstanceRegistry;
import com.netflix.eureka.EurekaBootStrap;
import com.netflix.eureka.EurekaServerConfig;
import com.netflix.eureka.EurekaServerConfigurationManager;
import com.netflix.eureka.PeerAwareInstanceRegistry;
import com.netflix.eureka.PeerAwareInstanceRegistryImpl;
/**
* @author Dave Syer
*/
@Configuration
@EnableConfigurationProperties(EurekaServerConfigBean.class)
@CommonsLog
public class EurekaServerInitializerConfiguration
implements ServletContextAware, SmartLifecycle, Ordered {
private static Log logger = LogFactory
.getLog(EurekaServerInitializerConfiguration.class);
@Autowired
private EurekaServerConfig eurekaServerConfig;
......@@ -76,6 +51,9 @@ public class EurekaServerInitializerConfiguration
@Autowired
private ApplicationContext applicationContext;
@Autowired
private EurekaServerBootstrap eurekaServerBootstrap;
private boolean running;
private int order = 1;
......@@ -91,46 +69,34 @@ public class EurekaServerInitializerConfiguration
@Override
public void run() {
try {
new EurekaBootStrap() {
@Override
protected void initEurekaEnvironment() {
try {
if (System.getProperty("log4j.configuration") == null) {
System.setProperty("log4j.configuration",
new ClassPathResource("log4j.properties",
Log4JLoggingSystem.class).getURL()
.toString());
}
}
catch (IOException ex) {
// ignore
}
EurekaServerConfigurationManager.getInstance()
.setConfiguration(
EurekaServerInitializerConfiguration.this.eurekaServerConfig);
EurekaServerInitializerConfiguration.this.applicationContext
.publishEvent(new EurekaRegistryAvailableEvent(
EurekaServerInitializerConfiguration.this.eurekaServerConfig));
}
}.contextInitialized(new ServletContextEvent(
EurekaServerInitializerConfiguration.this.servletContext));
logger.info("Started Eureka Server");
//TODO: is this class even needed now?
eurekaServerBootstrap.contextInitialized(EurekaServerInitializerConfiguration.this.servletContext);
log.info("Started Eureka Server");
publish(new EurekaRegistryAvailableEvent(getEurekaServerConfig()));
EurekaServerInitializerConfiguration.this.running = true;
EurekaServerInitializerConfiguration.this.applicationContext
.publishEvent(new EurekaServerStartedEvent(
EurekaServerInitializerConfiguration.this.eurekaServerConfig));
publish(new EurekaServerStartedEvent(getEurekaServerConfig()));
}
catch (Exception ex) {
// Help!
logger.error("Could not initialize Eureka servlet context", ex);
log.error("Could not initialize Eureka servlet context", ex);
}
}
}).start();
}
private EurekaServerConfig getEurekaServerConfig() {
return this.eurekaServerConfig;
}
private void publish(ApplicationEvent event) {
this.applicationContext.publishEvent(event);
}
@Override
public void stop() {
this.running = false;
eurekaServerBootstrap.contextDestroyed(this.servletContext);
}
@Override
......@@ -158,116 +124,4 @@ public class EurekaServerInitializerConfiguration
return this.order;
}
@Configuration
@ConditionalOnClass(PeerAwareInstanceRegistry.class)
protected static class RegistryInstanceProxyInitializer
implements ApplicationListener<EurekaRegistryAvailableEvent> {
@Autowired(required = false)
private EurekaClient client;
private PeerAwareInstanceRegistryImpl instance;
@Bean
public LeaseManagerMessageBroker leaseManagerMessageBroker() {
return new LeaseManagerMessageBroker();
}
@Override
public void onApplicationEvent(EurekaRegistryAvailableEvent event) {
if (this.client != null) {
this.client.getApplications(); // force initialization
}
if (this.instance == null) {
this.instance = PeerAwareInstanceRegistryImpl.getInstance();
safeInit();
replaceInstance(getProxyForInstance());
expectRegistrations(1);
}
}
private void safeInit() {
Method method = ReflectionUtils.findMethod(AbstractInstanceRegistry.class,
"postInit");
ReflectionUtils.makeAccessible(method);
ReflectionUtils.invokeMethod(method, this.instance);
}
private void replaceInstance(Object proxy) {
Field field = ReflectionUtils.findField(PeerAwareInstanceRegistryImpl.class,
"instance");
try {
// Awful ugly hack to work around lack of DI in eureka
field.setAccessible(true);
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
ReflectionUtils.setField(field, null, proxy);
}
catch (Exception ex) {
throw new IllegalStateException("Cannot modify instance registry", ex);
}
}
private Object getProxyForInstance() {
// Wrap the instance registry...
ProxyFactory factory = new ProxyFactory(this.instance);
// ...with the LeaseManagerMessageBroker
factory.addAdvice(new PiggybackMethodInterceptor(leaseManagerMessageBroker(),
LeaseManagerLite.class));
factory.addAdvice(new TrafficOpener());
factory.setProxyTargetClass(true);
return factory.getProxy();
}
private void expectRegistrations(int count) {
/*
* Setting expectedNumberOfRenewsPerMin to non-zero to ensure that even an
* isolated server can adjust its eviction policy to the number of
* registrations (when it's zero, even a successful registration won't reset
* the rate threshold in InstanceRegistry.register()).
*/
Field field = ReflectionUtils.findField(AbstractInstanceRegistry.class,
"expectedNumberOfRenewsPerMin");
try {
// Awful ugly hack to work around lack of DI in eureka
field.setAccessible(true);
int value = (int) ReflectionUtils.getField(field, this.instance);
if (value == 0 && count > 0) {
ReflectionUtils.setField(field, this.instance, count);
}
}
catch (Exception ex) {
throw new IllegalStateException(
"Cannot modify instance registry expected renews", ex);
}
}
/**
* Additional aspect for intercepting method invocations on
* PeerAwareInstanceRegistry. If
* {@link PeerAwareInstanceRegistryImpl#openForTraffic(int)} is called with a zero
* argument, it means that leases are not automatically cancelled if the instance
* hasn't sent any renewals recently. This happens for a standalone server. It
* seems like a bad default, so we set it to the smallest non-zero value we can,
* so that any instances that subsequently register can bump up the threshold.
*/
private class TrafficOpener implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
if ("openForTraffic".equals(invocation.getMethod().getName())) {
int count = (int) invocation.getArguments()[0];
ReflectionUtils.invokeMethod(invocation.getMethod(),
invocation.getThis(), count == 0 ? 1 : count);
return null;
}
return invocation.proceed();
}
}
}
}
......@@ -14,29 +14,65 @@
* limitations under the License.
*/
package org.springframework.cloud.netflix.eureka.server.event;
package org.springframework.cloud.netflix.eureka.server;
import java.util.List;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.netflix.eureka.server.advice.LeaseManagerLite;
import org.springframework.beans.BeansException;
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceCanceledEvent;
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRegisteredEvent;
import org.springframework.cloud.netflix.eureka.server.event.EurekaInstanceRenewedEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import com.netflix.appinfo.ApplicationInfoManager;
import com.netflix.appinfo.InstanceInfo;
import com.netflix.discovery.EurekaClient;
import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.shared.Application;
import com.netflix.eureka.PeerAwareInstanceRegistryImpl;
import com.netflix.eureka.EurekaServerConfig;
import com.netflix.eureka.lease.Lease;
import com.netflix.eureka.registry.PeerAwareInstanceRegistryImpl;
import com.netflix.eureka.resources.ServerCodecs;
/**
* @author Spencer Gibb
*/
@CommonsLog
public class LeaseManagerMessageBroker implements LeaseManagerLite<InstanceInfo> {
public class InstanceRegistry extends PeerAwareInstanceRegistryImpl implements ApplicationContextAware {
@Autowired
private ApplicationContext ctxt;
private int defaultOpenForTrafficCount;
public InstanceRegistry(EurekaServerConfig serverConfig,
EurekaClientConfig clientConfig, ServerCodecs serverCodecs,
EurekaClient eurekaClient, int expectedNumberOfRenewsPerMin, int defaultOpenForTrafficCount) {
super(serverConfig, clientConfig, serverCodecs, eurekaClient);
this.expectedNumberOfRenewsPerMin = expectedNumberOfRenewsPerMin;
this.defaultOpenForTrafficCount = defaultOpenForTrafficCount;
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.ctxt = context;
}
/**
* If {@link PeerAwareInstanceRegistryImpl#openForTraffic(ApplicationInfoManager, int)}
* is called with a zero * argument, it means that leases are not
* automatically * cancelled if the instance * hasn't sent any renewals
* recently. This happens for a standalone server. It seems like a bad
* default, so we set it to the smallest non-zero value we can, so that any
* instances that subsequently register can bump up the threshold.
*/
@Override
public void openForTraffic(ApplicationInfoManager applicationInfoManager, int count) {
super.openForTraffic(applicationInfoManager, count == 0 ? defaultOpenForTrafficCount : count);
}
@Override
public void register(InstanceInfo info, boolean isReplication) {
......@@ -45,35 +81,31 @@ public class LeaseManagerMessageBroker implements LeaseManagerLite<InstanceInfo>
@Override
public void register(InstanceInfo info, int leaseDuration, boolean isReplication) {
if (log.isDebugEnabled()) {
log.debug("register " + info.getAppName() + ", vip " + info.getVIPAddress()
+ ", leaseDuration " + leaseDuration + ", isReplication " + isReplication);
}
// TODO: what to publish from info (whole object?)
this.ctxt.publishEvent(new EurekaInstanceRegisteredEvent(this, info,
leaseDuration, isReplication));
super.register(info, leaseDuration, isReplication);
}
@Override
public boolean cancel(String appName, String serverId, boolean isReplication) {
if (log.isDebugEnabled()) {
log.debug("cancel " + appName + " serverId " + serverId + ", isReplication {}"
+ isReplication);
}
this.ctxt.publishEvent(new EurekaInstanceCanceledEvent(this, appName, serverId,
isReplication));
return false;
return super.cancel(appName, serverId, isReplication);
}
@Override
public boolean renew(final String appName, final String serverId,
boolean isReplication) {
if (log.isDebugEnabled()) {
log.debug("renew " + appName + " serverId " + serverId + ", isReplication {}"
+ isReplication);
}
List<Application> applications = PeerAwareInstanceRegistryImpl.getInstance()
.getSortedApplications();
List<Application> applications = getSortedApplications();
for (Application input : applications) {
if (input.getName().equals(appName)) {
InstanceInfo instance = null;
......@@ -88,11 +120,6 @@ public class LeaseManagerMessageBroker implements LeaseManagerLite<InstanceInfo>
break;
}
}
return false;
return super.renew(appName, serverId, isReplication);
}
@Override
public void evict() {
}
}
/*
* 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.eureka.server.advice;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.util.ReflectionUtils;
/**
* @author Dave Syer
*/
public class PiggybackMethodInterceptor implements MethodInterceptor {
private Object delegate;
private Class<?>[] types;
public PiggybackMethodInterceptor(Object delegate, Class<?>... types) {
this.delegate = delegate;
this.types = types;
}
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object result = invocation.proceed();
invokeAfter(invocation.getMethod(), invocation.getArguments());
return result;
}
private void invokeAfter(Method method, Object[] arguments) throws Exception {
for (Class<?> type : this.types) {
Method target = getTarget(type, method);
if (target != null) {
target.invoke(this.delegate, arguments);
return;
}
}
}
private Method getTarget(Class<?> type, Method method) {
Method target = ReflectionUtils.findMethod(type, method.getName(),
method.getParameterTypes());
return target;
}
}
/*
* Copyright 2012-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.eureka.server;
import java.io.IOException;
import org.apache.log4j.Logger;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.springframework.boot.logging.LogLevel;
import org.springframework.boot.logging.LoggingInitializationContext;
import org.springframework.boot.logging.log4j.Log4JLoggingSystem;
import org.springframework.boot.test.OutputCapture;
import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.StringUtils;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
/**
* Tests for {@link Log4JLoggingSystem}.
*
* @author Phillip Webb
*/
public class Log4JLoggingSystemTests {
@Rule
public OutputCapture output = new OutputCapture();
private final Log4JLoggingSystem loggingSystem = new Log4JLoggingSystem(getClass()
.getClassLoader());
private Logger logger;
@Before
public void setup() throws IOException {
System.setProperty("log4j.configuration", new ClassPathResource(
"log4j.properties", Log4JLoggingSystem.class).getURL().toString());
this.logger = Logger.getLogger(getClass());
}
@Test
@Ignore("gh-48")
public void setLevel() throws Exception {
this.loggingSystem.beforeInitialize();
this.loggingSystem.initialize(new LoggingInitializationContext(
new StandardEnvironment()), null, null);
this.logger.debug("Hello");
this.loggingSystem.setLogLevel("org.springframework.cloud", LogLevel.DEBUG);
this.logger.debug("Hello");
assertThat(StringUtils.countOccurrencesOf(this.output.toString(), "Hello"),
equalTo(1));
}
}
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