server:
port: 8100
ssl:
clientAuth: want
protocol: TLS
key-store: classpath:keystore/keystore.jks
key-store-password: some
key-password: some
eureka:
instance:
prefer-ip-address: true
non-secure-port-enabled: false
secure-port-enabled: true
secure-port: ${server.port}
healthCheckUrl: https://${eureka.hostname}:${secure-port}/health
statusPageUrl: https://${eureka.hostname}:${secure-port}/info
homePageUrl: https://${eureka.hostname}:${secure-port}/
security:
basic:
enabled: true
SSLContext.setDefault(sslContext);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
当它调用其他eureka客户机时使用feign。然而,当注册到eureka服务器时,它并不费力。我检查了源代码,发现eureka discovery客户端使用了jersey,jersey调用了http apache客户端。问题是,它使用了SchemeRegistryFactory.createDefault(),它将最终调用SSLContexts.createDefault(),后者不会考虑系统属性。换句话说,这个http客户端不会标记我的自定义SSLContexts。所以我的问题是,在eureka discovery client中是否有一种方法来添加/resigter/替换默认的http client?
最后我在多次挖掘源代码后找到了一个解决方案。我使用的是camden.sr5版本,它将调用eureka-client-1.4.12。
如果您在DiscoveryClientOptionalArgs中提供了一个EurekaJerseyClient,那么DiscoveryClient将不会启动默认的客户端。类DiscoveryClient的部分代码。
private void scheduleServerEndpointTask(EurekaTransport eurekaTransport,
DiscoveryClientOptionalArgs args) {
...
EurekaJerseyClient providedJerseyClient = args == null
? null
: args.eurekaJerseyClient;
eurekaTransport.transportClientFactory = providedJerseyClient == null
? TransportClientFactories.newTransportClientFactory(clientConfig, additionalFilters, applicationInfoManager.getInfo())
: TransportClientFactories.newTransportClientFactory(additionalFilters, providedJerseyClient);
...
}
然后添加一个类来生成DiscoveryClientOptionalArgs bean。
import com.netflix.discovery.DiscoveryClient;
import com.netflix.discovery.EurekaClientConfig;
import com.netflix.discovery.converters.wrappers.CodecWrappers;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient;
import com.qy.insurance.cloud.core.eureka.CustomEurekaJerseyClientBuilder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class EurekaSslConfig {
@Value("${eureka.client.service-url.defaultZone}")
private String defaultZone;
@Autowired
private EurekaClientConfig config;
@Autowired
private DefaultSslConfig defaultSslConfig;
@Bean
public DiscoveryClient.DiscoveryClientOptionalArgs discoveryClientOptionalArgs(){
if(!defaultSslConfig.isFinish()){
log.warn("Default SSLContext might not have been updated! Please check!");
}
DiscoveryClient.DiscoveryClientOptionalArgs args = new DiscoveryClient.DiscoveryClientOptionalArgs();
CustomEurekaJerseyClientBuilder clientBuilder = new CustomEurekaJerseyClientBuilder()
.withClientName("DiscoveryClient-HTTPClient-Custom")
.withUserAgent("Java-EurekaClient")
.withConnectionTimeout(config.getEurekaServerConnectTimeoutSeconds() * 1000)
.withReadTimeout(config.getEurekaServerReadTimeoutSeconds() * 1000)
.withMaxConnectionsPerHost(config.getEurekaServerTotalConnectionsPerHost())
.withMaxTotalConnections(config.getEurekaServerTotalConnections())
.withConnectionIdleTimeout(config.getEurekaConnectionIdleTimeoutSeconds() * 1000)
.withEncoderWrapper(CodecWrappers.getEncoder(config.getEncoderName()))
.withDecoderWrapper(CodecWrappers.resolveDecoder(config.getDecoderName(), config.getClientDataAccept()));
if (defaultZone.startsWith("https://")) {
clientBuilder.withSystemSSLConfiguration();
}
EurekaJerseyClient jerseyClient = clientBuilder.build();
args.setEurekaJerseyClient(jerseyClient);//Provide custom EurekaJerseyClient to override default one
return args;
}
import com.netflix.discovery.converters.wrappers.CodecWrappers;
import com.netflix.discovery.converters.wrappers.DecoderWrapper;
import com.netflix.discovery.converters.wrappers.EncoderWrapper;
import com.netflix.discovery.provider.DiscoveryJerseyProvider;
import com.netflix.discovery.shared.MonitoredConnectionManager;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClient;
import com.netflix.discovery.shared.transport.jersey.EurekaJerseyClientImpl;
import com.netflix.discovery.shared.transport.jersey.SSLSocketFactoryAdapter;
import com.netflix.discovery.util.DiscoveryBuildInfo;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.client.apache4.config.ApacheHttpClient4Config;
import com.sun.jersey.client.apache4.config.DefaultApacheHttpClient4Config;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.TextUtils;
public class CustomEurekaJerseyClientBuilder {
private boolean systemSSL;
private String clientName;
private int maxConnectionsPerHost;
private int maxTotalConnections;
private String trustStoreFileName;
private String trustStorePassword;
private String userAgent;
private String proxyUserName;
private String proxyPassword;
private String proxyHost;
private String proxyPort;
private int connectionTimeout;
private int readTimeout;
private int connectionIdleTimeout;
private EncoderWrapper encoderWrapper;
private DecoderWrapper decoderWrapper;
public CustomEurekaJerseyClientBuilder withClientName(String clientName) {
this.clientName = clientName;
return this;
}
public CustomEurekaJerseyClientBuilder withUserAgent(String userAgent) {
this.userAgent = userAgent;
return this;
}
public CustomEurekaJerseyClientBuilder withConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
return this;
}
public CustomEurekaJerseyClientBuilder withReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
return this;
}
public CustomEurekaJerseyClientBuilder withConnectionIdleTimeout(int connectionIdleTimeout) {
this.connectionIdleTimeout = connectionIdleTimeout;
return this;
}
public CustomEurekaJerseyClientBuilder withMaxConnectionsPerHost(int maxConnectionsPerHost) {
this.maxConnectionsPerHost = maxConnectionsPerHost;
return this;
}
public CustomEurekaJerseyClientBuilder withMaxTotalConnections(int maxTotalConnections) {
this.maxTotalConnections = maxTotalConnections;
return this;
}
public CustomEurekaJerseyClientBuilder withProxy(String proxyHost, String proxyPort, String user, String password) {
this.proxyHost = proxyHost;
this.proxyPort = proxyPort;
this.proxyUserName = user;
this.proxyPassword = password;
return this;
}
public CustomEurekaJerseyClientBuilder withSystemSSLConfiguration() {
this.systemSSL = true;
return this;
}
public CustomEurekaJerseyClientBuilder withTrustStoreFile(String trustStoreFileName, String trustStorePassword) {
this.trustStoreFileName = trustStoreFileName;
this.trustStorePassword = trustStorePassword;
return this;
}
public CustomEurekaJerseyClientBuilder withEncoder(String encoderName) {
return this.withEncoderWrapper(CodecWrappers.getEncoder(encoderName));
}
public CustomEurekaJerseyClientBuilder withEncoderWrapper(EncoderWrapper encoderWrapper) {
this.encoderWrapper = encoderWrapper;
return this;
}
public CustomEurekaJerseyClientBuilder withDecoder(String decoderName, String clientDataAccept) {
return this.withDecoderWrapper(CodecWrappers.resolveDecoder(decoderName, clientDataAccept));
}
public CustomEurekaJerseyClientBuilder withDecoderWrapper(DecoderWrapper decoderWrapper) {
this.decoderWrapper = decoderWrapper;
return this;
}
public EurekaJerseyClient build() {
MyDefaultApacheHttpClient4Config config = new MyDefaultApacheHttpClient4Config();
try {
return new EurekaJerseyClientImpl(connectionTimeout, readTimeout, connectionIdleTimeout, config);
} catch (Throwable e) {
throw new RuntimeException("Cannot create Jersey client ", e);
}
}
class MyDefaultApacheHttpClient4Config extends DefaultApacheHttpClient4Config {
private static final String PROTOCOL = "https";
private static final String PROTOCOL_SCHEME = "SSL";
private static final int HTTPS_PORT = 443;
private static final String KEYSTORE_TYPE = "JKS";
MyDefaultApacheHttpClient4Config() {
MonitoredConnectionManager cm;
if (systemSSL) {
cm = createSystemSslCM();
} else {
cm = createDefaultSslCM();
}
if (proxyHost != null) {
addProxyConfiguration(cm);
}
DiscoveryJerseyProvider discoveryJerseyProvider = new DiscoveryJerseyProvider(encoderWrapper, decoderWrapper);
getSingletons().add(discoveryJerseyProvider);
// Common properties to all clients
cm.setDefaultMaxPerRoute(maxConnectionsPerHost);
cm.setMaxTotal(maxTotalConnections);
getProperties().put(ApacheHttpClient4Config.PROPERTY_CONNECTION_MANAGER, cm);
String fullUserAgentName = (userAgent == null ? clientName : userAgent) + "/v" + DiscoveryBuildInfo.buildVersion();
getProperties().put(CoreProtocolPNames.USER_AGENT, fullUserAgentName);
// To pin a client to specific server in case redirect happens, we handle redirects directly
// (see DiscoveryClient.makeRemoteCall methods).
getProperties().put(ClientConfig.PROPERTY_FOLLOW_REDIRECTS, Boolean.FALSE);
getProperties().put(ClientPNames.HANDLE_REDIRECTS, Boolean.FALSE);
}
private void addProxyConfiguration(MonitoredConnectionManager cm) {
if (proxyUserName != null && proxyPassword != null) {
getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_USERNAME, proxyUserName);
getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_PASSWORD, proxyPassword);
} else {
// Due to bug in apache client, user name/password must always be set.
// Otherwise proxy configuration is ignored.
getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_USERNAME, "guest");
getProperties().put(ApacheHttpClient4Config.PROPERTY_PROXY_PASSWORD, "guest");
}
getProperties().put(DefaultApacheHttpClient4Config.PROPERTY_PROXY_URI, "http://" + proxyHost + ":" + proxyPort);
}
private MonitoredConnectionManager createSystemSslCM() {
MonitoredConnectionManager cm;
X509HostnameVerifier hostnameVerifier = SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
SSLConnectionSocketFactory systemSocketFactory = new SSLConnectionSocketFactory(
(javax.net.ssl.SSLSocketFactory) javax.net.ssl.SSLSocketFactory.getDefault(),
split(System.getProperty("https.protocols")),
split(System.getProperty("https.cipherSuites")),
hostnameVerifier);
SSLSocketFactory sslSocketFactory = new SSLSocketFactoryAdapter(systemSocketFactory);
SchemeRegistry sslSchemeRegistry = new SchemeRegistry();
sslSchemeRegistry.register(new Scheme(PROTOCOL, HTTPS_PORT, sslSocketFactory));
cm = new MonitoredConnectionManager(clientName, sslSchemeRegistry);
return cm;
}
/**
* @see SchemeRegistryFactory#createDefault()
*/
private MonitoredConnectionManager createDefaultSslCM() {
final SchemeRegistry registry = new SchemeRegistry();
registry.register(
new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));
registry.register(
new Scheme("https", 443, new SSLSocketFactoryAdapter(SSLConnectionSocketFactory.getSocketFactory())));
return new MonitoredConnectionManager(clientName, registry);
}
private String[] split(final String s) {
if (TextUtils.isBlank(s)) {
return null;
}
return s.split(" *, *");
}
}
}
我有一个RESTAPI,我不想强迫客户端发送请求参数。我有将近400个api方法,我不想将所有参数设置为“required=false” 我想覆盖Spring RequestParam的默认行为。我想将RequestParam接口的“required”属性的默认值设置为“false”。 有什么方法可以覆盖它吗?如果我不能或这不是最佳实践,有什么方法可以解决上述问题。
问题内容: 我有一个静态html,imgs,flash内容文件夹,它位于webapp文件夹之外。现在,我正在使用符号链接将该文件夹映射到我的webapp目录中。我的问题是,当我取消部署应用程序时,它会遵循符号链接并删除所有这些文件。 我尝试实现的解决方案之一是特殊的servlet,它包装了默认的servlet,但是使用了不同的相对路径。我在找出如何以覆盖默认servlet路径的方式包装默认serv
我有以下代码: 我的意图是所有对mocked的调用都应该以标准方式应答。但是对(这是公共的)的调用应该以特定的方式应答。 我发现,当我添加对< code>mobileMethod调用的应答时,不是附加< code>MobileServiceAnswer,Java实际上是调用< code > my service . mobile method ,这导致了NPE。 这可能吗?似乎应该可以覆盖默认答案
问题内容: 我已经能够覆盖所有名称以“ android:”为前缀的主题,但是Android themes.xml还定义了似乎无法被覆盖的属性。例如: colorTheground是在Theme.Light xml中定义的,但是在此处添加它可以使我 错误。如何为整个应用程序覆盖该样式? 问题答案: 您可以用修改属性(如)的方式覆盖标准属性,只是不要忘记添加如下前缀:
问题内容: 我想覆盖Java外观。我只想显示不同的按钮。 我想要Windows Look and Feel的所有功能,但仅按钮有所不同。希望你明白我的意思。 还告诉我如何制作圆形的JtabbedPane ??? 问题答案: 自定义GUI类 调用您的自定义GUI类
问题内容: 我有一个模板与此: Django自动将此翻译为Terminarsesión西班牙语。但是,我想将其翻译为Cerrarsesión。 我试图将此文字添加到.po文件中,但是在编译消息时出现错误,指出该文字重复。 有没有一种方法可以更改/覆盖默认的Django翻译? 谢谢。 问题答案: 最简单的方法是收集在django.contrib.admin语言环境文件夹中找到的.po文件,然后重新编