Spring Cloud实战小贴士:Zuul处理Cookie和重定向

所以解决该问题的思路也很简单,我们只需要通过设置sensitiveHeaders即可,设置方法分为两种:

  • 全局设置:

    • zuul.sensitive-headers=
  • 指定路由设置:
    • zuul.routes.<routeName>.sensitive-headers=
    • zuul.routes.<routeName>.custom-sensitive-headers=true

重定向问题

在使用Spring Cloud Zuul对接Web网站的时候,处理完了会话控制问题之后。往往我们还会碰到如下图所示的问题,我们在浏览器中通过Zuul发起了登录请求,该请求会被路由到某WebSite服务,该服务在完成了登录处理之后,会进行重定向到某个主页或欢迎页面。此时,仔细的开发者会发现,在登录完成之后,我们浏览器中URL的HOST部分发生的改变,该地址变成了具体WebSite服务的地址了。这就是在这一节,我们将分析和解决的重定向问题!

出现该问题的根源是Spring Cloud Zuul没有正确的处理HTTP请求头信息中的Host导致。在Brixton版本中,Spring Cloud Zuul的PreDecorationFilter过滤器实现时完全没有考虑这一问题,它更多的定位于REST API的网关。所以如果要在Brixton版本中增加这一特性就相对较为复杂,不过好在Camden版本之后,Spring Cloud Netflix 1.2.x版本的Zuul增强了该功能,我们只需要通过配置属性zuul.add-host-header=true就能让原本有问题的重定向操作得到正确的处理。关于更多Host头信息的处理,读者可以参考本文之前的分析思路,可以通过查看PreDecorationFilter过滤器的源码来详细更多实现细节。

http://blog.didispace.com/spring-cloud-zuul-cookie-redirect/

Spring cloud使用/refresh端点手动刷新配置

一 介绍
很多场景下,需要在运行期间动态调整配置。如果配置发生了修改,微服务也应该实现配置的刷新。
下面实现配置的手动刷新。
二 新建项目microservice-config-client-refresh
三 为项目添加spring-boot-starter-actuator依赖,该依赖包含了/refresh端点,用于配置的刷新。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>
四 在Controller上添加注解@RefreshScope。添加@RefreshScope的类会在配置更改时得到特殊处理。
package com.itmuch.cloud.study.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RefreshScope
public class ConfigClientController {
@Value("${profile}")
private String profile;
@GetMapping("/profile")
public String hello() {
return this.profile;
}
}
五 测试
1 启动microservice-config-server
2 启动microservice-config-client-refresh
3 访问http://localhost:8081/profile,获得结果
dev-1.0
4 修改Git仓库中microservice-foo-dev.properties的文件内容为:
profile=dev-1.0-change
5 重新访问http://localhost:8081/profile,获得结果依然是:
dev-1.0
6 发送post请求到http://localhost:8081/refresh,结果返回
[
"config.client.version",
"profile"
]
7 再次访问http://localhost:8081/profile,返回结果为:
dev-1.0-change
说明配置已经刷新
---------------------
作者:chengqiuming
来源:CSDN
原文:https://blog.csdn.net/chengqiuming/article/details/80872615
版权声明:本文为博主原创文章,转载请附上博文链接!

 
 

https://tech.asimio.net/2017/10/10/Routing-requests-and-dynamically-refreshing-routes-using-Spring-Cloud-Zuul-Server.html

https://www.cnblogs.com/flying607/p/8459397.html

spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情

服务网关zuul之七:zuul中的动态刷新路由配置

ApplicationEvent事件机制源码分析

在spring-cloud-netflix-core-1.4.4.RELEASE.jar中org.springframework.cloud.netflix.zuul.RoutesRefreshedEvent.java

@SuppressWarnings("serial")
public class RoutesRefreshedEvent extends ApplicationEvent {
private RouteLocator locator;

public RoutesRefreshedEvent(RouteLocator locator) {
super(locator);
this.locator = locator;
} public RouteLocator getLocator() {
return this.locator;
}

}

在spring-cloud-netflix-core-1.4.4.RELEASE-sources.jar中的org.springframework.cloud.netflix.zuul.zuulZuulServerAutoConfiguration.java配置了监听事件。

    private static class ZuulRefreshListener
implements ApplicationListener<ApplicationEvent> {
    @Autowired
private ZuulHandlerMapping zuulHandlerMapping; private HeartbeatMonitor heartbeatMonitor = new HeartbeatMonitor(); @Override
public void onApplicationEvent(ApplicationEvent event) {
if (event instanceof ContextRefreshedEvent
|| event instanceof RefreshScopeRefreshedEvent
|| event instanceof RoutesRefreshedEvent) {
this.zuulHandlerMapping.setDirty(true);
}
else if (event instanceof HeartbeatEvent) {
if (this.heartbeatMonitor.update(((HeartbeatEvent) event).getValue())) {
this.zuulHandlerMapping.setDirty(true);
}
}
} }</pre>

关于spring的ApplicationEvent见《spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情

https://blog.csdn.net/weixin_34267123/article/details/86021770

java配置

@Configuration
public class ZuulConfig {
<span class="hljs-meta"><span class="hljs-meta">@Bean</span>(name=<span class="hljs-string"><span class="hljs-string">"zuul.CONFIGURATION_PROPERTIES"</span>)
<span class="hljs-meta"><span class="hljs-meta">@RefreshScope</span>
<span class="hljs-meta"><span class="hljs-meta">@ConfigurationProperties</span>(<span class="hljs-string"><span class="hljs-string">"zuul"</span>)
<span class="hljs-meta"><span class="hljs-meta">@Primary</span>
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span> ZuulProperties </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">zuulProperties</span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</span> </span>{
<span class="hljs-keyword"><span class="hljs-keyword">return</span> <span class="hljs-keyword"><span class="hljs-keyword">new</span> ZuulProperties();
}

}

修改路由

到git config server,修改zuul的路由,比如

zuul:
host:
socket-timeout-millis: 60000
connect-timeout-millis: 30000
proxy:
addProxyHeaders: true
routes:
baidu:
path: /baidu
url: http://baidu.com

刷新

curl -i -X POST localhost:10000/refresh

验证

curl -i localhost:10000/routes

作者:go4it
链接:https://www.jianshu.com/p/a9332b111002
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 
 

  我们知道在SpringCloud中,当配置变更时,我们通过访问http://xxxx/refresh,可以在不启动服务的情况下获取最新的配置,那么它是如何做到的呢,当我们更改数据库配置并刷新后,如何能获取最新的数据源对象呢?下面我们看SpringCloud如何做到的。

一、环境变化

1.1、关于ContextRefresher

  当我们访问/refresh时,会被RefreshEndpoint类所处理。我们来看源代码:

/*
* 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.endpoint; import java.util.Arrays;

import java.util.Collection;

import java.util.Set; import org.springframework.boot.actuate.endpoint.AbstractEndpoint;

import org.springframework.boot.context.properties.ConfigurationProperties;

import org.springframework.cloud.context.refresh.ContextRefresher;

import org.springframework.jmx.export.annotation.ManagedOperation;

import org.springframework.jmx.export.annotation.ManagedResource; /**
  • @author Dave Syer
  • @author Venil Noronha

    */

    @ConfigurationProperties(prefix = "endpoints.refresh", ignoreUnknownFields = false)

    @ManagedResource

    public class RefreshEndpoint extends AbstractEndpoint<Collection<String>> { private ContextRefresher contextRefresher; public RefreshEndpoint(ContextRefresher contextRefresher) {

    super("refresh");

    this.contextRefresher = contextRefresher;

    } @ManagedOperation

    public String[] refresh() {

    Set<String> keys = contextRefresher.refresh();

    return keys.toArray(new String[keys.size()]);

    } @Override

    public Collection<String> invoke() {

    return Arrays.asList(refresh());

    }
}

  通过源代码我们了解到:当访问refresh端点时,实际上执行的是ContextRefresher的refresh方法,那么我们继续追踪源代码,找到其refresh方法:

public synchronized Set<String> refresh() {
Map<String, Object> before = extract(
this.context.getEnvironment().getPropertySources());
addConfigFilesToEnvironment();
Set<String> keys = changes(before,
extract(this.context.getEnvironment().getPropertySources())).keySet();
this.context.publishEvent(new EnvironmentChangeEvent(context, keys));
this.scope.refreshAll();
return keys;
}

  我们可以看到refresh方法做了如下几件事情:

  1)获取刷新之前的所有PropertySource

  2) 调用addConfigFilesToEnvironment方法获取最新的配置

  3) 调用changes方法更新配置信息

  4) 发布EnvironmentChangeEnvent事件

  5)调用refreshScope的refreshAll方法刷新范围

  我们重点关注一下2,3,4步骤

1.2、addConfigFilesToEnvironment方法

  我们先来看看这个方法是怎么实现的:

/* for testing */ ConfigurableApplicationContext addConfigFilesToEnvironment() {
ConfigurableApplicationContext capture = null;
try {
StandardEnvironment environment = copyEnvironment(
this.context.getEnvironment());
SpringApplicationBuilder builder = new SpringApplicationBuilder(Empty.class)
.bannerMode(Mode.OFF).web(false).environment(environment);
// Just the listeners that affect the environment (e.g. excluding logging
// listener because it has side effects)
builder.application()
.setListeners(Arrays.asList(new BootstrapApplicationListener(),
new ConfigFileApplicationListener()));
capture = builder.run();
if (environment.getPropertySources().contains(REFRESH_ARGS_PROPERTY_SOURCE)) {
environment.getPropertySources().remove(REFRESH_ARGS_PROPERTY_SOURCE);
}
MutablePropertySources target = this.context.getEnvironment()
.getPropertySources();
String targetName = null;
for (PropertySource<?> source : environment.getPropertySources()) {
String name = source.getName();
if (target.contains(name)) {
targetName = name;
}
if (!this.standardSources.contains(name)) {
if (target.contains(name)) {
target.replace(name, source);
}
else {
if (targetName != null) {
target.addAfter(targetName, source);
}
else {
// targetName was null so we are at the start of the list
target.addFirst(source);
targetName = name;
}
}
}
}
}
finally {
ConfigurableApplicationContext closeable = capture;
while (closeable != null) {
try {
closeable.close();
}
catch (Exception e) {
// Ignore;
}
if (closeable.getParent() instanceof ConfigurableApplicationContext) {
closeable = (ConfigurableApplicationContext) closeable.getParent();
}
else {
break;
}
}
}
return capture;
}

  1) 该方法首先拷贝当前的Environment

  2) 通过SpringApplicationBuilder构建了一个简单的SpringBoot启动程序并启动

builder.application().setListeners(Arrays.asList(new BootstrapApplicationListener(),
new ConfigFileApplicationListener()));

  这里面会添加两个监听器分别为:BootstrapApplicationListener与ConfigFileApplicationListener,通过先前的学习,我们知道BootstrapApplicationListener是引导程序的核心监听器,而ConfigFileApplicationListener也是非常重要的类:

/*
* Copyright 2012-2017 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.boot.context.config; import java.io.IOException;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.Collection;

import java.util.Collections;

import java.util.Iterator;

import java.util.LinkedHashSet;

import java.util.LinkedList;

import java.util.List;

import java.util.Queue;

import java.util.Set; import org.apache.commons.logging.Log; import org.springframework.beans.BeansException;

import org.springframework.beans.CachedIntrospectionResults;

import org.springframework.beans.factory.config.BeanFactoryPostProcessor;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.bind.PropertiesConfigurationFactory;

import org.springframework.boot.bind.PropertySourcesPropertyValues;

import org.springframework.boot.bind.RelaxedDataBinder;

import org.springframework.boot.bind.RelaxedPropertyResolver;

import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;

import org.springframework.boot.context.event.ApplicationPreparedEvent;

import org.springframework.boot.env.EnumerableCompositePropertySource;

import org.springframework.boot.env.EnvironmentPostProcessor;

import org.springframework.boot.env.PropertySourcesLoader;

import org.springframework.boot.logging.DeferredLog;

import org.springframework.context.ApplicationEvent;

import org.springframework.context.ConfigurableApplicationContext;

import org.springframework.context.annotation.ConfigurationClassPostProcessor;

import org.springframework.context.event.SmartApplicationListener;

import org.springframework.core.Ordered;

import org.springframework.core.annotation.AnnotationAwareOrderComparator;

import org.springframework.core.convert.ConversionService;

import org.springframework.core.convert.support.DefaultConversionService;

import org.springframework.core.env.ConfigurableEnvironment;

import org.springframework.core.env.EnumerablePropertySource;

import org.springframework.core.env.MutablePropertySources;

import org.springframework.core.env.PropertySource;

import org.springframework.core.env.PropertySources;

import org.springframework.core.io.DefaultResourceLoader;

import org.springframework.core.io.Resource;

import org.springframework.core.io.ResourceLoader;

import org.springframework.core.io.support.SpringFactoriesLoader;

import org.springframework.util.Assert;

import org.springframework.util.ResourceUtils;

import org.springframework.util.StringUtils;

import org.springframework.validation.BindException; /**
  • {@link EnvironmentPostProcessor} that configures the context environment by loading
  • properties from well known file locations. By default properties will be loaded from
  • 'application.properties' and/or 'application.yml' files in the following locations:
  • <ul>
  • <li>classpath:</li>
  • <li>file:./</li>
  • <li>classpath:config/</li>
  • <li>file:./config/:</li>
  • </ul>
  • <p>
  • Alternative search locations and names can be specified using
  • {@link #setSearchLocations(String)} and {@link #setSearchNames(String)}.
  • <p>
  • Additional files will also be loaded based on active profiles. For example if a 'web'
  • profile is active 'application-web.properties' and 'application-web.yml' will be
  • considered.
  • <p>
  • The 'spring.config.name' property can be used to specify an alternative name to load
  • and the 'spring.config.location' property can be used to specify alternative search
  • locations or specific files.
  • <p>
  • Configuration properties are also bound to the {@link SpringApplication}. This makes it
  • possible to set {@link SpringApplication} properties dynamically, like the sources
  • ("spring.main.sources" - a CSV list) the flag to indicate a web environment
  • ("spring.main.web_environment=true") or the flag to switch off the banner
  • ("spring.main.show_banner=false").
  • @author Dave Syer
  • @author Phillip Webb
  • @author Stephane Nicoll
  • @author Andy Wilkinson
  • @author Eddú Meléndez

    */

    public class ConfigFileApplicationListener

    implements EnvironmentPostProcessor, SmartApplicationListener, Ordered { private static final String DEFAULT_PROPERTIES = "defaultProperties"; // Note the order is from least to most specific (last one wins)

    private static final String DEFAULT_SEARCH_LOCATIONS = "classpath:/,classpath:/config/,file:./,file:./config/"; private static final String DEFAULT_NAMES = "application"; /**
    • The "active profiles" property name.

      */

      public static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
    /**
    • The "includes profiles" property name.

      */

      public static final String INCLUDE_PROFILES_PROPERTY = "spring.profiles.include";
    /**
    • The "config name" property name.

      */

      public static final String CONFIG_NAME_PROPERTY = "spring.config.name";
    /**
    • The "config location" property name.

      */

      public static final String CONFIG_LOCATION_PROPERTY = "spring.config.location";
    /**
    • The default order for the processor.

      */

      public static final int DEFAULT_ORDER = Ordered.HIGHEST_PRECEDENCE + 10;
    /**
    • Name of the application configuration {@link PropertySource}.

      */

      public static final String APPLICATION_CONFIGURATION_PROPERTY_SOURCE_NAME = "applicationConfigurationProperties";
    private final DeferredLog logger = new DeferredLog(); private String searchLocations; private String names; private int order = DEFAULT_ORDER; private final ConversionService conversionService = new DefaultConversionService(); @Override

    public boolean supportsEventType(Class<? extends ApplicationEvent> eventType) {

    return ApplicationEnvironmentPreparedEvent.class.isAssignableFrom(eventType)

    || ApplicationPreparedEvent.class.isAssignableFrom(eventType);

    } @Override

    public boolean supportsSourceType(Class<?> aClass) {

    return true;

    } @Override

    public void onApplicationEvent(ApplicationEvent event) {

    if (event instanceof ApplicationEnvironmentPreparedEvent) {

    onApplicationEnvironmentPreparedEvent(

    (ApplicationEnvironmentPreparedEvent) event);

    }

    if (event instanceof ApplicationPreparedEvent) {

    onApplicationPreparedEvent(event);

    }

    } private void onApplicationEnvironmentPreparedEvent(

    ApplicationEnvironmentPreparedEvent event) {

    List<EnvironmentPostProcessor> postProcessors = loadPostProcessors();

    postProcessors.add(this);

    AnnotationAwareOrderComparator.sort(postProcessors);

    for (EnvironmentPostProcessor postProcessor : postProcessors) {

    postProcessor.postProcessEnvironment(event.getEnvironment(),

    event.getSpringApplication());

    }

    } List<EnvironmentPostProcessor> loadPostProcessors() {

    return SpringFactoriesLoader.loadFactories(EnvironmentPostProcessor.class,

    getClass().getClassLoader());

    } @Override

    public void postProcessEnvironment(ConfigurableEnvironment environment,

    SpringApplication application) {

    addPropertySources(environment, application.getResourceLoader());

    configureIgnoreBeanInfo(environment);

    bindToSpringApplication(environment, application);

    } private void configureIgnoreBeanInfo(ConfigurableEnvironment environment) {

    if (System.getProperty(

    CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME) == null) {

    RelaxedPropertyResolver resolver = new RelaxedPropertyResolver(environment,

    "spring.beaninfo.");

    Boolean ignore = resolver.getProperty("ignore", Boolean.class, Boolean.TRUE);

    System.setProperty(CachedIntrospectionResults.IGNORE_BEANINFO_PROPERTY_NAME,

    ignore.toString());

    }

    } private void onApplicationPreparedEvent(ApplicationEvent event) {

    this.logger.replayTo(ConfigFileApplicationListener.class);

    addPostProcessors(((ApplicationPreparedEvent) event).getApplicationContext());

    } /**
    • Add config file property sources to the specified environment.
    • @param environment the environment to add source to
    • @param resourceLoader the resource loader
    • @see #addPostProcessors(ConfigurableApplicationContext)

      */

      protected void addPropertySources(ConfigurableEnvironment environment,

      ResourceLoader resourceLoader) {

      RandomValuePropertySource.addToEnvironment(environment);

      new Loader(environment, resourceLoader).load();

      }
    /**
    • Bind the environment to the {@link SpringApplication}.
    • @param environment the environment to bind
    • @param application the application to bind to

      */

      protected void bindToSpringApplication(ConfigurableEnvironment environment,

      SpringApplication application) {

      PropertiesConfigurationFactory<SpringApplication> binder = new PropertiesConfigurationFactory<SpringApplication>(

      application);

      binder.setTargetName("spring.main");

      binder.setConversionService(this.conversionService);

      binder.setPropertySources(environment.getPropertySources());

      try {

      binder.bindPropertiesToTarget();

      }

      catch (BindException ex) {

      throw new IllegalStateException("Cannot bind to SpringApplication", ex);

      }

      }
    /**
    • Add appropriate post-processors to post-configure the property-sources.
    • @param context the context to configure

      */

      protected void addPostProcessors(ConfigurableApplicationContext context) {

      context.addBeanFactoryPostProcessor(

      new PropertySourceOrderingPostProcessor(context));

      }
    public void setOrder(int order) {

    this.order = order;

    } @Override

    public int getOrder() {

    return this.order;

    } /**
    • Set the search locations that will be considered as a comma-separated list. Each
    • search location should be a directory path (ending in "/") and it will be prefixed
    • by the file names constructed from {@link #setSearchNames(String) search names} and
    • profiles (if any) plus file extensions supported by the properties loaders.
    • Locations are considered in the order specified, with later items taking precedence
    • (like a map merge).
    • @param locations the search locations

      */

      public void setSearchLocations(String locations) {

      Assert.hasLength(locations, "Locations must not be empty");

      this.searchLocations = locations;

      }
    /**
    • Sets the names of the files that should be loaded (excluding file extension) as a
    • comma-separated list.
    • @param names the names to load

      */

      public void setSearchNames(String names) {

      Assert.hasLength(names, "Names must not be empty");

      this.names = names;

      }
    /**
    • {@link BeanFactoryPostProcessor} to re-order our property sources below any
    • {@code @PropertySource} items added by the {@link ConfigurationClassPostProcessor}.

      */

      private class PropertySourceOrderingPostProcessor

      implements BeanFactoryPostProcessor, Ordered { private ConfigurableApplicationContext context; PropertySourceOrderingPostProcessor(ConfigurableApplicationContext context) {

      this.context = context;

      } @Override

      public int getOrder() {

      return Ordered.HIGHEST_PRECEDENCE;

      } @Override

      public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)

      throws BeansException {

      reorderSources(this.context.getEnvironment());

      } private void reorderSources(ConfigurableEnvironment environment) {

      ConfigurationPropertySources

      .finishAndRelocate(environment.getPropertySources());

      PropertySource<?> defaultProperties = environment.getPropertySources()

      .remove(DEFAULT_PROPERTIES);

      if (defaultProperties != null) {

      environment.getPropertySources().addLast(defaultProperties);

      }

      }
    } /**
    • Loads candidate property sources and configures the active profiles.

      */

      private class Loader { private final Log logger = ConfigFileApplicationListener.this.logger; private final ConfigurableEnvironment environment; private final ResourceLoader resourceLoader; private PropertySourcesLoader propertiesLoader; private Queue<Profile> profiles; private List<Profile> processedProfiles; private boolean activatedProfiles; Loader(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {

      this.environment = environment;

      this.resourceLoader = resourceLoader == null ? new DefaultResourceLoader()

      : resourceLoader;

      } public void load() {

      this.propertiesLoader = new PropertySourcesLoader();

      this.activatedProfiles = false;

      this.profiles = Collections.asLifoQueue(new LinkedList<Profile>());

      this.processedProfiles = new LinkedList<Profile>();
       // Pre-existing active profiles set via Environment.setActiveProfiles()
      // are additional profiles and config files are allowed to add more if
      // they want to, so don't call addActiveProfiles() here.
      Set&lt;Profile&gt; initialActiveProfiles = initializeActiveProfiles();
      this.profiles.addAll(getUnprocessedActiveProfiles(initialActiveProfiles));
      if (this.profiles.isEmpty()) {
      for (String defaultProfileName : this.environment.getDefaultProfiles()) {
      Profile defaultProfile = new Profile(defaultProfileName, true);
      if (!this.profiles.contains(defaultProfile)) {
      this.profiles.add(defaultProfile);
      }
      }
      } // The default profile for these purposes is represented as null. We add it
      // last so that it is first out of the queue (active profiles will then
      // override any settings in the defaults when the list is reversed later).
      this.profiles.add(null); while (!this.profiles.isEmpty()) {
      Profile profile = this.profiles.poll();
      for (String location : getSearchLocations()) {
      if (!location.endsWith("/")) {
      // location is a filename already, so don't search for more
      // filenames
      load(location, null, profile);
      }
      else {
      for (String name : getSearchNames()) {
      load(location, name, profile);
      }
      }
      }
      this.processedProfiles.add(profile);
      } addConfigurationProperties(this.propertiesLoader.getPropertySources());

      }

      private Set<Profile> initializeActiveProfiles() {

      if (!this.environment.containsProperty(ACTIVE_PROFILES_PROPERTY)

      && !this.environment.containsProperty(INCLUDE_PROFILES_PROPERTY)) {

      return Collections.emptySet();

      }

      // Any pre-existing active profiles set via property sources (e.g. System

      // properties) take precedence over those added in config files.

      SpringProfiles springProfiles = bindSpringProfiles(

      this.environment.getPropertySources());

      Set<Profile> activeProfiles = new LinkedHashSet<Profile>(

      springProfiles.getActiveProfiles());

      activeProfiles.addAll(springProfiles.getIncludeProfiles());

      maybeActivateProfiles(activeProfiles);

      return activeProfiles;

      }

      /**

      • Return the active profiles that have not been processed yet. If a profile is
      • enabled via both {@link #ACTIVE_PROFILES_PROPERTY} and
      • {@link ConfigurableEnvironment#addActiveProfile(String)} it needs to be
      • filtered so that the {@link #ACTIVE_PROFILES_PROPERTY} value takes precedence.
      • <p>
      • Concretely, if the "cloud" profile is enabled via the environment, it will take
      • less precedence that any profile set via the {@link #ACTIVE_PROFILES_PROPERTY}.
      • @param initialActiveProfiles the profiles that have been enabled via
      • {@link #ACTIVE_PROFILES_PROPERTY}
      • @return the unprocessed active profiles from the environment to enable

        */

        private List<Profile> getUnprocessedActiveProfiles(

        Set<Profile> initialActiveProfiles) {

        List<Profile> unprocessedActiveProfiles = new ArrayList<Profile>();

        for (String profileName : this.environment.getActiveProfiles()) {

        Profile profile = new Profile(profileName);

        if (!initialActiveProfiles.contains(profile)) {

        unprocessedActiveProfiles.add(profile);

        }

        }

        // Reverse them so the order is the same as from getProfilesForValue()

        // (last one wins when properties are eventually resolved)

        Collections.reverse(unprocessedActiveProfiles);

        return unprocessedActiveProfiles;

        }

      private void load(String location, String name, Profile profile) {

      String group = "profile=" + (profile == null ? "" : profile);

      if (!StringUtils.hasText(name)) {

      // Try to load directly from the location

      loadIntoGroup(group, location, profile);

      }

      else {

      // Search for a file with the given name

      for (String ext : this.propertiesLoader.getAllFileExtensions()) {

      if (profile != null) {

      // Try the profile-specific file

      loadIntoGroup(group, location + name + "-" + profile + "." + ext,

      null);

      for (Profile processedProfile : this.processedProfiles) {

      if (processedProfile != null) {

      loadIntoGroup(group, location + name + "-"

      + processedProfile + "." + ext, profile);

      }

      }

      // Sometimes people put "spring.profiles: dev" in

      // application-dev.yml (gh-340). Arguably we should try and error

      // out on that, but we can be kind and load it anyway.

      loadIntoGroup(group, location + name + "-" + profile + "." + ext,

      profile);

      }

      // Also try the profile-specific section (if any) of the normal file

      loadIntoGroup(group, location + name + "." + ext, profile);

      }

      }

      }

      private PropertySource<?> loadIntoGroup(String identifier, String location,

      Profile profile) {

      try {

      return doLoadIntoGroup(identifier, location, profile);

      }

      catch (Exception ex) {

      throw new IllegalStateException(

      "Failed to load property source from location '" + location + "'",

      ex);

      }

      }

      private PropertySource<?> doLoadIntoGroup(String identifier, String location,

      Profile profile) throws IOException {

      Resource resource = this.resourceLoader.getResource(location);

      PropertySource<?> propertySource = null;

      StringBuilder msg = new StringBuilder();

      if (resource != null && resource.exists()) {

      String name = "applicationConfig: [" + location + "]";

      String group = "applicationConfig: [" + identifier + "]";

      propertySource = this.propertiesLoader.load(resource, group, name,

      (profile == null ? null : profile.getName()));

      if (propertySource != null) {

      msg.append("Loaded ");

      handleProfileProperties(propertySource);

      }

      else {

      msg.append("Skipped (empty) ");

      }

      }

      else {

      msg.append("Skipped ");

      }

      msg.append("config file ");

      msg.append(getResourceDescription(location, resource));

      if (profile != null) {

      msg.append(" for profile ").append(profile);

      }

      if (resource == null || !resource.exists()) {

      msg.append(" resource not found");

      this.logger.trace(msg);

      }

      else {

      this.logger.debug(msg);

      }

      return propertySource;

      }

      private String getResourceDescription(String location, Resource resource) {

      String resourceDescription = "'" + location + "'";

      if (resource != null) {

      try {

      resourceDescription = String.format("'%s' (%s)",

      resource.getURI().toASCIIString(), location);

      }

      catch (IOException ex) {

      // Use the location as the description

      }

      }

      return resourceDescription;

      }

      private void handleProfileProperties(PropertySource<?> propertySource) {

      SpringProfiles springProfiles = bindSpringProfiles(propertySource);

      maybeActivateProfiles(springProfiles.getActiveProfiles());

      addProfiles(springProfiles.getIncludeProfiles());

      }

      private SpringProfiles bindSpringProfiles(PropertySource<?> propertySource) {

      MutablePropertySources propertySources = new MutablePropertySources();

      propertySources.addFirst(propertySource);

      return bindSpringProfiles(propertySources);

      }

      private SpringProfiles bindSpringProfiles(PropertySources propertySources) {

      SpringProfiles springProfiles = new SpringProfiles();

      RelaxedDataBinder dataBinder = new RelaxedDataBinder(springProfiles,

      "spring.profiles");

      dataBinder.bind(new PropertySourcesPropertyValues(propertySources, false));

      springProfiles.setActive(resolvePlaceholders(springProfiles.getActive()));

      springProfiles.setInclude(resolvePlaceholders(springProfiles.getInclude()));

      return springProfiles;

      }

      private List<String> resolvePlaceholders(List<String> values) {

      List<String> resolved = new ArrayList<String>();

      for (String value : values) {

      resolved.add(this.environment.resolvePlaceholders(value));

      }

      return resolved;

      }

      private void maybeActivateProfiles(Set<Profile> profiles) {

      if (this.activatedProfiles) {

      if (!profiles.isEmpty()) {

      this.logger.debug("Profiles already activated, '" + profiles

      + "' will not be applied");

      }

      return;

      }

      if (!profiles.isEmpty()) {

      addProfiles(profiles);

      this.logger.debug("Activated profiles "

      + StringUtils.collectionToCommaDelimitedString(profiles));

      this.activatedProfiles = true;

      removeUnprocessedDefaultProfiles();

      }

      }

      private void removeUnprocessedDefaultProfiles() {

      for (Iterator<Profile> iterator = this.profiles.iterator(); iterator

      .hasNext()

      服务网关zuul----zuul中的动态刷新路由配置的更多相关文章

      1. 服务网关zuul之七:zuul中的动态刷新路由配置

        <spring扩展点之三:Spring 的监听事件 ApplicationListener 和 ApplicationEvent 用法,在spring启动后做些事情> <服务网关zu ...

      2. SpringCloud的微服务网关:zuul(实践)

        Zuul的主要功能是路由和过滤器.路由功能是微服务的一部分,比如/api/user映射到user服务,/api/shop映射到shop服务.zuul实现了负载均衡. zuul有以下功能: Authen ...

      3. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十一):服务网关(Zuul)

        在线演示 演示地址:http://139.196.87.48:9002/kitty 用户名:admin 密码:admin 技术背景 前面我们通过Ribbon或Feign实现了微服务之间的调用和负载均衡 ...

      4. Spring Boot + Spring Cloud 构建微服务系统(七):API服务网关(Zuul)

        技术背景 前面我们通过Ribbon或Feign实现了微服务之间的调用和负载均衡,那我们的各种微服务又要如何提供给外部应用调用呢. 当然,因为是REST API接口,外部客户端直接调用各个微服务是没有问 ...

      5. API服务网关(Zuul)

        技术背景 前面我们通过Ribbon或Feign实现了微服务之间的调用和负载均衡,那我们的各种微服务又要如何提供给外部应用调用呢. 当然,因为是REST API接口,外部客户端直接调用各个微服务是没有问 ...

      6. SPRING CLOUD服务网关之ZUUL

        服务网关是微服务架构中一个不可或缺的部分.通过服务网关统一向外系统提供REST API的过程中,除了具备服务路由.均衡负载功能之外,它还具备了权限控制等功能.Spring Cloud Netflix中 ...

      7. SpringCloud的微服务网关:zuul(理论)

        参考链接:https://springcloud.cc/spring-cloud-dalston.html 一.概念与定义 1.为什么要引入API网关 后期维护:路由规则和服务实例列表困难 系统架构: ...

      8. springcloud使用Zuul构建微服务网关入门

        为什么要使用微服务网关 不同的微服务一般会经过不同的网络地址,而外部客户端可能需要调用多个服务的接口才能完成一个业务需求. 如果让客户端直接与各个微服务通信,会有以下的问题: 客户端会多次请求不同的微 ...

      9. 八、springcloud之服务网关zuul(一)

        一.Zuul简介 zuul 是netflix开源的一个API Gateway 服务器, 本质上是一个web servlet应用. Zuul是Netflix出品的一个基于JVM路由和服务端的负载均衡器. ...

      随机推荐

      1. js之简单工厂模式

        简单工厂模式是由一个方法来决定到底要创建哪个类的实例, 而这些实例经常都拥有相同的接口. 这种模式主要用在所实例化的类型在编译期并不能确定, 而是在执行期决定的情况. 说的通俗点,就像公司茶水间的饮料 ...

      2. Coreutils - GNU core utilities

        coreutils 是GNU下的一个软件包,包含linux下的 ls等常用命令.这些命令的实现要依赖于shell程序.一般在系统中都默认安装,也可自己安装或更新.例如,安装coreutils-6.7. ...

      3. pytorch 多GPU训练过程中出现ap=0情况

        原因可能是pytorch 自带的BN bug:安装nvidia apex 可以解决: $ git clone https://github.com/NVIDIA/apex $ cd apex $ pi ...

      4. Odoo 在 Ubuntu 环境下性能调优

        一.首先我们要分析影响odoo 服务器 性能的因素 CPU 目前大部分CPU在同一时间只能运行一个线程,超线程的处理器可以在同一时间处理多个线程,因此可以利用超线程特性提高系统性能. 在linux系统 ...

      5. LC327 Count of Range Number

        这一题,我们使用了分治法. 首先看时间复杂度为o(n^2),比较naïve的方法: 使用一个数组sum[],长度为原数组长度+1,每一个元素sum[i]为原数组中index0~i-1之和,显然当sum ...

      6. Javascript-循环输出菱形,并可菱形自定义大小

        var Cen = 6;//定义菱形中部为第几行(起始值为0) //for循环输出菱形 document.write("<button onclick='xh()'>点我for循 ...

      7. linux下文件操作之cp和mv

        Linux CP文件夹略过目录的解决 root@QGY:/home/qgy# cp image/newimage_raw /mnt/4T/qin/cp: 略过目录'image/newimage_raw ...

      8. apache https 双向认证

        Https分单向认证和双向认证 单向认证表现形式:网站URL链接为https://xxx.com格式 双向认证表现心事:网站URL链接为https://xxx.com格式,并且需要客户端浏览器安装一个 ...

      9. 直接删除mysql的日志导致mysql无法启动

        --02T08::.750000Z [Warning] [MY-] [Server] 'NO_ZERO_DATE', 'NO_ZERO_IN_DATE' and 'ERROR_FOR_DIVISION ...

      10. Ubuntu 服务器默认的root账号是没有激活的,需要用初装的用户账号给root设置管理密码

        user@ubuntu12:~$ sudo password root //用sudo修改账户 1.根据提示输入当前用户的密码: 2.修改成功之后你就可以使用root账号了,可以使用su root 命 ...