Merge remote-tracking branch 'origin/3.1.x'

This commit is contained in:
Olga Maciaszek-Sharma
2022-04-21 16:23:10 +02:00
2 changed files with 69 additions and 4 deletions

View File

@@ -29,9 +29,11 @@ import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.MapPropertySource;
@@ -45,6 +47,7 @@ import org.springframework.core.env.MapPropertySource;
* @param <C> specification
* @author Spencer Gibb
* @author Dave Syer
* @author Tommy Karlsson
*/
// TODO: add javadoc
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
@@ -110,7 +113,25 @@ public abstract class NamedContextFactory<C extends NamedContextFactory.Specific
}
protected AnnotationConfigApplicationContext createContext(String name) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
AnnotationConfigApplicationContext context;
if (this.parent != null) {
// jdk11 issue
// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
// https://github.com/spring-cloud/spring-cloud-openfeign/issues/475
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
if (parent instanceof ConfigurableApplicationContext) {
beanFactory.setBeanClassLoader(
((ConfigurableApplicationContext) parent).getBeanFactory().getBeanClassLoader());
}
else {
beanFactory.setBeanClassLoader(parent.getClassLoader());
}
context = new AnnotationConfigApplicationContext(beanFactory);
context.setClassLoader(this.parent.getClassLoader());
}
else {
context = new AnnotationConfigApplicationContext();
}
if (this.configurations.containsKey(name)) {
for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
context.register(configuration);
@@ -129,9 +150,6 @@ public abstract class NamedContextFactory<C extends NamedContextFactory.Specific
if (this.parent != null) {
// Uses Environment from parent as well as beans
context.setParent(this.parent);
// jdk11 issue
// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
context.setClassLoader(this.parent.getClassLoader());
}
context.setDisplayName(generateDisplayName(name));
context.refresh();

View File

@@ -18,17 +18,26 @@ package org.springframework.cloud.context.named;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.util.ClassUtils;
import static org.assertj.core.api.BDDAssertions.then;
/**
* @author Spencer Gibb
* @author Tommy Karlsson
*/
public class NamedContextFactoryTests {
@@ -37,6 +46,10 @@ public class NamedContextFactoryTests {
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
parent.register(BaseConfig.class);
parent.refresh();
testChildContexts(parent);
}
private void testChildContexts(GenericApplicationContext parent) {
TestClientFactory factory = new TestClientFactory();
factory.setApplicationContext(parent);
factory.setConfigurations(Arrays.asList(getSpec("foo", FooConfig.class), getSpec("bar", BarConfig.class)));
@@ -79,6 +92,10 @@ public class NamedContextFactoryTests {
then(fooContext.getClassLoader()).as("foo context classloader does not match parent")
.isSameAs(parent.getClassLoader());
then(fooContext.getBeanFactory().getBeanClassLoader())
.as("foo context bean factory classloader does not match parent")
.isSameAs(parent.getBeanFactory().getBeanClassLoader());
Assertions.assertThat(fooContext).hasFieldOrPropertyWithValue("customClassLoader", true);
factory.destroy();
@@ -88,10 +105,39 @@ public class NamedContextFactoryTests {
then(barContext.isActive()).as("bar context wasn't closed").isFalse();
}
@Test
void testBadThreadContextClassLoader() throws InterruptedException, ExecutionException, TimeoutException {
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
parent.setClassLoader(ClassUtils.getDefaultClassLoader());
parent.register(BaseConfig.class);
parent.refresh();
ExecutorService es = Executors.newSingleThreadExecutor(r -> {
Thread t = new Thread(r);
t.setContextClassLoader(new ThrowingClassLoader());
return t;
});
es.submit(() -> this.testChildContexts(parent)).get(5, TimeUnit.SECONDS);
}
private TestSpec getSpec(String name, Class<?> configClass) {
return new TestSpec(name, new Class[] { configClass });
}
static class ThrowingClassLoader extends ClassLoader {
ThrowingClassLoader() {
super(null);
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
throw new ClassNotFoundException(name);
}
}
static class TestClientFactory extends NamedContextFactory<TestSpec> {
TestClientFactory() {
@@ -147,6 +193,7 @@ public class NamedContextFactoryTests {
}
@ConditionalOnClass(Object.class)
static class FooConfig {
@Bean