privatestaticfinal String[] DEFAULT_PROPERTY_SOURCES = new String[]{ // order matters, if cli args aren't first, things get messy CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME, "defaultProperties"};
private ConfigurableApplicationContext addConfigFilesToEnvironment(){ ConfigurableApplicationContext capture = null; try { StandardEnvironment environment = copyEnvironment(this.environment); SpringApplicationBuilder builder = new SpringApplicationBuilder(Empty.class) .bannerMode(Banner.Mode.OFF).web(WebApplicationType.NONE) .environment(environment); capture = builder.run(); if (environment.getPropertySources().contains(REFRESH_ARGS_PROPERTY_SOURCE)) { environment.getPropertySources().remove(REFRESH_ARGS_PROPERTY_SOURCE); } MutablePropertySources target = this.environment.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); // update targetName to preserve ordering targetName = name; } 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; }
private StandardEnvironment copyEnvironment(ConfigurableEnvironment input){ StandardEnvironment environment = new StandardEnvironment(); MutablePropertySources capturedPropertySources = environment.getPropertySources(); // Only copy the default property source(s) and the profiles over from the main // environment (everything else should be pristine, just like it was on startup). for (String name : DEFAULT_PROPERTY_SOURCES) { if (input.getPropertySources().contains(name)) { if (capturedPropertySources.contains(name)) { capturedPropertySources.replace(name, input.getPropertySources().get(name)); } else { capturedPropertySources.addLast(input.getPropertySources().get(name)); } } } environment.setActiveProfiles(input.getActiveProfiles()); environment.setDefaultProfiles(input.getDefaultProfiles()); Map<String, Object> map = new HashMap<String, Object>(); map.put("spring.jmx.enabled", false); map.put("spring.main.sources", ""); // gh-678 without this apps with this property set to REACTIVE or SERVLET fail map.put("spring.main.web-application-type", "NONE"); capturedPropertySources .addFirst(new MapPropertySource(REFRESH_ARGS_PROPERTY_SOURCE, map)); return environment; }
private Map<String, Object> changes(Map<String, Object> before, Map<String, Object> after){ Map<String, Object> result = new HashMap<String, Object>(); for (String key : before.keySet()) { if (!after.containsKey(key)) { result.put(key, null); } elseif (!equal(before.get(key), after.get(key))) { result.put(key, after.get(key)); } } for (String key : after.keySet()) { if (!before.containsKey(key)) { result.put(key, after.get(key)); } } return result; }
privatebooleanequal(Object one, Object two){ if (one == null && two == null) { returntrue; } if (one == null || two == null) { returnfalse; } return one.equals(two); }
private Map<String, Object> extract(MutablePropertySources propertySources){ Map<String, Object> result = new HashMap<String, Object>(); List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>(); for (PropertySource<?> source : propertySources) { sources.add(0, source); } for (PropertySource<?> source : sources) { if (!this.standardSources.contains(source.getName())) { extract(source, result); } } return result; }
/** * Event published to signal a change in the {@link Environment}. * * @author Dave Syer */ @SuppressWarnings("serial") publicclassEnvironmentChangeEventextendsApplicationEvent{
private Set<String> keys;
publicEnvironmentChangeEvent(Set<String> keys){ // Backwards compatible constructor with less utility (practically no use at all) this(keys, keys); }
/* * Copyright 2012-2020 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 * * https://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. */
/** * Listens for {@link EnvironmentChangeEvent} and rebinds beans that were bound to the * {@link Environment} using {@link ConfigurationProperties * <code>@ConfigurationProperties</code>}. When these beans are re-bound and * re-initialized, the changes are available immediately to any component that is using * the <code>@ConfigurationProperties</code> bean. * * @author Dave Syer */ @Component @ManagedResource publicclassConfigurationPropertiesRebinderimplementsApplicationContextAware, ApplicationListener<EnvironmentChangeEvent> {
private ConfigurationPropertiesBeans beans;
private ApplicationContext applicationContext;
private Map<String, Exception> errors = new ConcurrentHashMap<>();
/** * A map of bean name to errors when instantiating the bean. * * @return The errors accumulated since the latest destroy. */ public Map<String, Exception> getErrors(){ returnthis.errors; }
@ManagedOperation publicvoidrebind(){ this.errors.clear(); for (String name : this.beans.getBeanNames()) { rebind(name); } }
@ManagedOperation publicbooleanrebind(String name){ if (!this.beans.getBeanNames().contains(name)) { returnfalse; } if (this.applicationContext != null) { try { Object bean = this.applicationContext.getBean(name); if (AopUtils.isAopProxy(bean)) { bean = ProxyUtils.getTargetObject(bean); } if (bean != null) { // TODO: determine a more general approach to fix this. // see https://github.com/spring-cloud/spring-cloud-commons/issues/571 if (getNeverRefreshable().contains(bean.getClass().getName())) { returnfalse; // ignore } this.applicationContext.getAutowireCapableBeanFactory() .destroyBean(bean); this.applicationContext.getAutowireCapableBeanFactory() .initializeBean(bean, name); returntrue; } } catch (RuntimeException e) { this.errors.put(name, e); throw e; } catch (Exception e) { this.errors.put(name, e); thrownew IllegalStateException("Cannot rebind to " + name, e); } } returnfalse; }
/* * Copyright 2012-2020 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 * * https://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. */
/** * Collects references to <code>@ConfigurationProperties</code> beans in the context and * its parent. * * @author Dave Syer */ @Component publicclassConfigurationPropertiesBeansimplementsBeanPostProcessor, ApplicationContextAware{
private Map<String, ConfigurationPropertiesBean> beans = new HashMap<>();
2023-02-0110:19:47.814 INFO 8772 --- [ Thread-10] .ApplicationConfigFileAlterationListener : File Changed: E:\git\gitee\gxing-demo\.\config\application.properties Profile{name='gxing', nickName='xing'} 2023-02-0110:19:47.843 INFO 8772 --- [ Thread-10] o.s.boot.SpringApplication : Starting application using Java 1.8.0_241 on DESKTOP-NAPJLIF with PID 8772 (started by Administrator in E:\git\gitee\gxing-demo) 2023-02-0110:19:47.844 INFO 8772 --- [ Thread-10] o.s.boot.SpringApplication : No active profile set, falling back to 1default profile: "default" 2023-02-0110:19:47.847 INFO 8772 --- [ Thread-10] o.s.boot.SpringApplication : Started application in 0.029 seconds (JVM running for17.878) 2023-02-0110:19:47.848 INFO 8772 --- [ Thread-10] c.g.r.env.content.EnvironmentRefresher : Environment properties be changed, keys:["nickName","com.gxitsky.name"] Profile{name='gxing1', nickName='xing'}