Add EnvironmentPostProcessorsFactory
Update `EnvironmentPostProcessorApplicationListener` so that it can either use values from `spring.factories` or use a factory interface. Closes gh-22529pull/22535/head
parent
5800f1596c
commit
36a6ca6e6e
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.env;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.springframework.boot.logging.DeferredLogFactory;
|
||||
import org.springframework.core.io.support.SpringFactoriesLoader;
|
||||
|
||||
/**
|
||||
* Factory interface used by the {@link EnvironmentPostProcessorApplicationListener} to
|
||||
* create the {@link EnvironmentPostProcessor} instances.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @since 2.4.0
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface EnvironmentPostProcessorsFactory {
|
||||
|
||||
/**
|
||||
* Create all requested {@link EnvironmentPostProcessor} instances.
|
||||
* @param logFactory a deferred log factory
|
||||
* @return the post processor instances
|
||||
*/
|
||||
List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory);
|
||||
|
||||
/**
|
||||
* Return a {@link EnvironmentPostProcessorsFactory} backed by
|
||||
* {@code spring.factories}.
|
||||
* @param classLoader the source class loader
|
||||
* @return an {@link EnvironmentPostProcessorsFactory} instance
|
||||
*/
|
||||
static EnvironmentPostProcessorsFactory fromSpringFactories(ClassLoader classLoader) {
|
||||
return new ReflectionEnvironmentPostProcessorsFactory(
|
||||
SpringFactoriesLoader.loadFactoryNames(EnvironmentPostProcessor.class, classLoader));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link EnvironmentPostProcessorsFactory} that reflectively creates post
|
||||
* processors from the given classes.
|
||||
* @param classes the post processor classes
|
||||
* @return an {@link EnvironmentPostProcessorsFactory} instance
|
||||
*/
|
||||
static EnvironmentPostProcessorsFactory of(Class<?>... classes) {
|
||||
return new ReflectionEnvironmentPostProcessorsFactory(classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link EnvironmentPostProcessorsFactory} that reflectively creates post
|
||||
* processors from the given class names.
|
||||
* @param classNames the post processor class names
|
||||
* @return an {@link EnvironmentPostProcessorsFactory} instance
|
||||
*/
|
||||
static EnvironmentPostProcessorsFactory of(String... classNames) {
|
||||
return new ReflectionEnvironmentPostProcessorsFactory(classNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link EnvironmentPostProcessorsFactory} containing only a single post
|
||||
* processor.
|
||||
* @param factory the factory used to create the post processor
|
||||
* @return an {@link EnvironmentPostProcessorsFactory} instance
|
||||
*/
|
||||
static EnvironmentPostProcessorsFactory singleton(Function<DeferredLogFactory, EnvironmentPostProcessor> factory) {
|
||||
return (logFactory) -> Collections.singletonList(factory.apply(logFactory));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,94 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.env;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import org.springframework.boot.logging.DeferredLogFactory;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* {@link EnvironmentPostProcessorsFactory} implementation that uses reflection to create
|
||||
* instances.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ReflectionEnvironmentPostProcessorsFactory implements EnvironmentPostProcessorsFactory {
|
||||
|
||||
private final List<String> classNames;
|
||||
|
||||
ReflectionEnvironmentPostProcessorsFactory(Class<?>... classes) {
|
||||
this(Arrays.stream(classes).map(Class::getName).toArray(String[]::new));
|
||||
}
|
||||
|
||||
ReflectionEnvironmentPostProcessorsFactory(String... classNames) {
|
||||
this(Arrays.asList(classNames));
|
||||
}
|
||||
|
||||
ReflectionEnvironmentPostProcessorsFactory(List<String> classNames) {
|
||||
this.classNames = classNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<EnvironmentPostProcessor> getEnvironmentPostProcessors(DeferredLogFactory logFactory) {
|
||||
List<EnvironmentPostProcessor> postProcessors = new ArrayList<>(this.classNames.size());
|
||||
for (String className : this.classNames) {
|
||||
try {
|
||||
postProcessors.add(getEnvironmentPostProcessor(className, logFactory));
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new IllegalArgumentException("Unable to instantiate factory class [" + className
|
||||
+ "] for factory type [" + EnvironmentPostProcessor.class.getName() + "]", ex);
|
||||
}
|
||||
}
|
||||
AnnotationAwareOrderComparator.sort(postProcessors);
|
||||
return postProcessors;
|
||||
}
|
||||
|
||||
private EnvironmentPostProcessor getEnvironmentPostProcessor(String className, DeferredLogFactory logFactory)
|
||||
throws Exception {
|
||||
Class<?> type = ClassUtils.forName(className, getClass().getClassLoader());
|
||||
Assert.isAssignable(EnvironmentPostProcessor.class, type);
|
||||
Constructor<?>[] constructors = type.getDeclaredConstructors();
|
||||
for (Constructor<?> constructor : constructors) {
|
||||
if (constructor.getParameterCount() == 1) {
|
||||
Class<?> cls = constructor.getParameterTypes()[0];
|
||||
if (DeferredLogFactory.class.isAssignableFrom(cls)) {
|
||||
return newInstance(constructor, logFactory);
|
||||
}
|
||||
if (Log.class.isAssignableFrom(cls)) {
|
||||
return newInstance(constructor, logFactory.getLog(type));
|
||||
}
|
||||
}
|
||||
}
|
||||
return (EnvironmentPostProcessor) ReflectionUtils.accessibleConstructor(type).newInstance();
|
||||
}
|
||||
|
||||
private EnvironmentPostProcessor newInstance(Constructor<?> constructor, Object... initargs) throws Exception {
|
||||
ReflectionUtils.makeAccessible(constructor);
|
||||
return (EnvironmentPostProcessor) constructor.newInstance(initargs);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.env;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.logging.DeferredLogFactory;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Tests for {@link EnvironmentPostProcessorsFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class EnvironmentPostProcessorsFactoryTests {
|
||||
|
||||
private final DeferredLogFactory logFactory = Supplier::get;
|
||||
|
||||
@Test
|
||||
void fromSpringFactoriesReturnsFactory() {
|
||||
EnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory.fromSpringFactories(null);
|
||||
List<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory);
|
||||
assertThat(processors).hasSizeGreaterThan(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofClassesReturnsFactory() {
|
||||
EnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory
|
||||
.of(TestEnvironmentPostProcessor.class);
|
||||
List<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory);
|
||||
assertThat(processors).hasSize(1);
|
||||
assertThat(processors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofClassNamesReturnsFactory() {
|
||||
EnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory
|
||||
.of(TestEnvironmentPostProcessor.class.getName());
|
||||
List<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory);
|
||||
assertThat(processors).hasSize(1);
|
||||
assertThat(processors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void singletonReturnsFactory() {
|
||||
EnvironmentPostProcessorsFactory factory = EnvironmentPostProcessorsFactory
|
||||
.singleton(TestEnvironmentPostProcessor::new);
|
||||
List<EnvironmentPostProcessor> processors = factory.getEnvironmentPostProcessors(this.logFactory);
|
||||
assertThat(processors).hasSize(1);
|
||||
assertThat(processors.get(0)).isInstanceOf(TestEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
static class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
TestEnvironmentPostProcessor(DeferredLogFactory logFactory) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,157 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.env;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.logging.DeferredLogFactory;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Tests for {@link ReflectionEnvironmentPostProcessorsFactory}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
*/
|
||||
class ReflectionEnvironmentPostProcessorsFactoryTests {
|
||||
|
||||
private final DeferredLogFactory logFactory = Supplier::get;
|
||||
|
||||
@Test
|
||||
void createWithClassesCreatesFactory() {
|
||||
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
|
||||
TestEnvironmentPostProcessor.class);
|
||||
assertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithClassNamesArrayCreatesFactory() {
|
||||
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
|
||||
TestEnvironmentPostProcessor.class.getName());
|
||||
assertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void createWithClassNamesListCreatesFactory() {
|
||||
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
|
||||
Arrays.asList(TestEnvironmentPostProcessor.class.getName()));
|
||||
assertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEnvironmentPostProcessorsWhenHasDefaultConstructorCreatesPostProcessors() {
|
||||
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
|
||||
TestEnvironmentPostProcessor.class.getName());
|
||||
assertThatFactory(factory).createsSinglePostProcessor(TestEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEnvironmentPostProcessorsWhenHasLogFactoryConstructorCreatesPostProcessors() {
|
||||
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
|
||||
TestLogFactoryEnvironmentPostProcessor.class.getName());
|
||||
assertThatFactory(factory).createsSinglePostProcessor(TestLogFactoryEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEnvironmentPostProcessorsWhenHasLogConstructorCreatesPostProcessors() {
|
||||
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
|
||||
TestLogEnvironmentPostProcessor.class.getName());
|
||||
assertThatFactory(factory).createsSinglePostProcessor(TestLogEnvironmentPostProcessor.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void getEnvironmentPostProcessorsWhenHasNoSuitableConstructorThrowsException() {
|
||||
ReflectionEnvironmentPostProcessorsFactory factory = new ReflectionEnvironmentPostProcessorsFactory(
|
||||
BadEnvironmentPostProcessor.class.getName());
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> factory.getEnvironmentPostProcessors(this.logFactory))
|
||||
.withMessageContaining("Unable to instantiate");
|
||||
}
|
||||
|
||||
private EnvironmentPostProcessorsFactoryAssert assertThatFactory(EnvironmentPostProcessorsFactory factory) {
|
||||
return new EnvironmentPostProcessorsFactoryAssert(factory);
|
||||
}
|
||||
|
||||
class EnvironmentPostProcessorsFactoryAssert {
|
||||
|
||||
private EnvironmentPostProcessorsFactory factory;
|
||||
|
||||
EnvironmentPostProcessorsFactoryAssert(EnvironmentPostProcessorsFactory factory) {
|
||||
this.factory = factory;
|
||||
}
|
||||
|
||||
void createsSinglePostProcessor(Class<?> expectedType) {
|
||||
List<EnvironmentPostProcessor> processors = this.factory
|
||||
.getEnvironmentPostProcessors(ReflectionEnvironmentPostProcessorsFactoryTests.this.logFactory);
|
||||
assertThat(processors).hasSize(1);
|
||||
assertThat(processors.get(0)).isInstanceOf(expectedType);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestLogFactoryEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
TestLogFactoryEnvironmentPostProcessor(DeferredLogFactory logFactory) {
|
||||
assertThat(logFactory).isNotNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class TestLogEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
TestLogEnvironmentPostProcessor(Log log) {
|
||||
assertThat(log).isNotNull();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class BadEnvironmentPostProcessor implements EnvironmentPostProcessor {
|
||||
|
||||
BadEnvironmentPostProcessor(InputStream inputStream) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue