Browse Source
Add an `AotServices` class to replace `AotFactoriesLoader`. The replacement class allow instances to be loaded from just the `aot.factories` file if required. It also retains a link to the bean names so that a `findByBeanName(...)` method can be provided. See gh-28833pull/30304/head
Phillip Webb
2 years ago
14 changed files with 451 additions and 227 deletions
@ -1,103 +0,0 @@
@@ -1,103 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.beans.factory.aot; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.List; |
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils; |
||||
import org.springframework.beans.factory.ListableBeanFactory; |
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory; |
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator; |
||||
import org.springframework.core.io.support.SpringFactoriesLoader; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* AOT specific factory loading mechanism for internal use within the framework. |
||||
* |
||||
* <p>Loads and instantiates factories of a given type from |
||||
* {@value #FACTORIES_RESOURCE_LOCATION} and merges them with matching beans |
||||
* from a {@link ListableBeanFactory}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 6.0 |
||||
* @see SpringFactoriesLoader |
||||
*/ |
||||
public class AotFactoriesLoader { |
||||
|
||||
/** |
||||
* The location to look for AOT factories. |
||||
*/ |
||||
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring/aot.factories"; |
||||
|
||||
|
||||
private final ListableBeanFactory beanFactory; |
||||
|
||||
private final SpringFactoriesLoader factoriesLoader; |
||||
|
||||
|
||||
/** |
||||
* Create a new {@link AotFactoriesLoader} instance backed by the given bean |
||||
* factory. |
||||
* @param beanFactory the bean factory to use |
||||
*/ |
||||
public AotFactoriesLoader(ListableBeanFactory beanFactory) { |
||||
Assert.notNull(beanFactory, "'beanFactory' must not be null"); |
||||
ClassLoader classLoader = (beanFactory instanceof ConfigurableBeanFactory configurableBeanFactory) |
||||
? configurableBeanFactory.getBeanClassLoader() : null; |
||||
this.beanFactory = beanFactory; |
||||
this.factoriesLoader = SpringFactoriesLoader.forResourceLocation(FACTORIES_RESOURCE_LOCATION, |
||||
classLoader); |
||||
} |
||||
|
||||
/** |
||||
* Create a new {@link AotFactoriesLoader} instance backed by the given bean |
||||
* factory and loading items from the given {@link SpringFactoriesLoader} |
||||
* rather than from {@value #FACTORIES_RESOURCE_LOCATION}. |
||||
* @param beanFactory the bean factory to use |
||||
* @param factoriesLoader the factories loader to use |
||||
*/ |
||||
public AotFactoriesLoader(ListableBeanFactory beanFactory, |
||||
SpringFactoriesLoader factoriesLoader) { |
||||
|
||||
Assert.notNull(beanFactory, "'beanFactory' must not be null"); |
||||
Assert.notNull(factoriesLoader, "'factoriesLoader' must not be null"); |
||||
this.beanFactory = beanFactory; |
||||
this.factoriesLoader = factoriesLoader; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Load items from factories file and merge them with any beans defined in |
||||
* the {@link DefaultListableBeanFactory}. |
||||
* @param <T> the item type |
||||
* @param type the item type to load |
||||
* @return a list of loaded instances |
||||
*/ |
||||
public <T> List<T> load(Class<T> type) { |
||||
List<T> result = new ArrayList<>(); |
||||
result.addAll(BeanFactoryUtils |
||||
.beansOfTypeIncludingAncestors(this.beanFactory, type, true, false) |
||||
.values()); |
||||
result.addAll(this.factoriesLoader.load(type)); |
||||
AnnotationAwareOrderComparator.sort(result); |
||||
return Collections.unmodifiableList(result); |
||||
} |
||||
|
||||
} |
@ -0,0 +1,192 @@
@@ -0,0 +1,192 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.beans.factory.aot; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collections; |
||||
import java.util.Iterator; |
||||
import java.util.List; |
||||
import java.util.Map; |
||||
import java.util.stream.Stream; |
||||
|
||||
import org.springframework.beans.factory.BeanFactoryUtils; |
||||
import org.springframework.beans.factory.ListableBeanFactory; |
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory; |
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator; |
||||
import org.springframework.core.io.support.SpringFactoriesLoader; |
||||
import org.springframework.lang.Nullable; |
||||
import org.springframework.util.Assert; |
||||
|
||||
/** |
||||
* A collection of AOT services that can be {@link Loader loaded} from |
||||
* a {@link SpringFactoriesLoader} or obtained from a {@link ListableBeanFactory}. |
||||
* |
||||
* @author Phillip Webb |
||||
* @since 6.0 |
||||
* @param <T> the service type |
||||
*/ |
||||
public final class AotServices<T> implements Iterable<T> { |
||||
|
||||
/** |
||||
* The location to look for AOT factories. |
||||
*/ |
||||
public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring/aot.factories"; |
||||
|
||||
private final List<T> services; |
||||
|
||||
private final Map<String, T> beans; |
||||
|
||||
|
||||
private AotServices(List<T> loaded, Map<String, T> beans) { |
||||
List<T> services = new ArrayList<>(); |
||||
services.addAll(beans.values()); |
||||
services.addAll(loaded); |
||||
AnnotationAwareOrderComparator.sort(services); |
||||
this.services = Collections.unmodifiableList(services); |
||||
this.beans = beans; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Return a new {@link Loader} that will obtain AOT services from |
||||
* {@value #FACTORIES_RESOURCE_LOCATION}. |
||||
* @return a new {@link Loader} instance |
||||
*/ |
||||
public static Loader factories() { |
||||
return factories((ClassLoader) null); |
||||
} |
||||
|
||||
/** |
||||
* Return a new {@link Loader} that will obtain AOT services from |
||||
* {@value #FACTORIES_RESOURCE_LOCATION}. |
||||
* @param classLoader the class loader used to load the factories resource |
||||
* @return a new {@link Loader} instance |
||||
*/ |
||||
public static Loader factories(@Nullable ClassLoader classLoader) { |
||||
return factories(getSpringFactoriesLoader(classLoader)); |
||||
} |
||||
|
||||
/** |
||||
* Return a new {@link Loader} that will obtain AOT services from the given |
||||
* {@link SpringFactoriesLoader}. |
||||
* @param springFactoriesLoader the spring factories loader |
||||
* @return a new {@link Loader} instance |
||||
*/ |
||||
public static Loader factories(SpringFactoriesLoader springFactoriesLoader) { |
||||
Assert.notNull(springFactoriesLoader, "'springFactoriesLoader' must not be null"); |
||||
return new Loader(springFactoriesLoader, null); |
||||
} |
||||
|
||||
/** |
||||
* Return a new {@link Loader} that will obtain AOT services from |
||||
* {@value #FACTORIES_RESOURCE_LOCATION} as well as the given |
||||
* {@link ListableBeanFactory}. |
||||
* @param beanFactory the bean factory |
||||
* @return a new {@link Loader} instance |
||||
*/ |
||||
public static Loader factoriesAndBeans(ListableBeanFactory beanFactory) { |
||||
ClassLoader classLoader = (beanFactory instanceof ConfigurableBeanFactory configurableBeanFactory) |
||||
? configurableBeanFactory.getBeanClassLoader() : null; |
||||
return factoriesAndBeans(getSpringFactoriesLoader(classLoader), beanFactory); |
||||
} |
||||
|
||||
/** |
||||
* Return a new {@link Loader} that will obtain AOT services from the given |
||||
* {@link SpringFactoriesLoader} and {@link ListableBeanFactory}. |
||||
* @param springFactoriesLoader the spring factories loader |
||||
* @param beanFactory the bean factory |
||||
* @return a new {@link Loader} instance |
||||
*/ |
||||
public static Loader factoriesAndBeans(SpringFactoriesLoader springFactoriesLoader, ListableBeanFactory beanFactory) { |
||||
Assert.notNull(beanFactory, "'beanFactory' must not be null"); |
||||
Assert.notNull(springFactoriesLoader, "'springFactoriesLoader' must not be null"); |
||||
return new Loader(springFactoriesLoader, beanFactory); |
||||
} |
||||
|
||||
private static SpringFactoriesLoader getSpringFactoriesLoader( |
||||
@Nullable ClassLoader classLoader) { |
||||
return SpringFactoriesLoader.forResourceLocation(FACTORIES_RESOURCE_LOCATION, |
||||
classLoader); |
||||
} |
||||
|
||||
@Override |
||||
public Iterator<T> iterator() { |
||||
return this.services.iterator(); |
||||
} |
||||
|
||||
/** |
||||
* Return a {@link Stream} of the AOT services. |
||||
* @return a stream of the services |
||||
*/ |
||||
public Stream<T> stream() { |
||||
return this.services.stream(); |
||||
} |
||||
|
||||
/** |
||||
* Return the AOT services as a {@link List}. |
||||
* @return a list of the services |
||||
*/ |
||||
public List<T> asList() { |
||||
return this.services; |
||||
} |
||||
|
||||
/** |
||||
* Return the AOT services that was loaded for the given bean name. |
||||
* @param beanName the bean name |
||||
* @return the AOT service or {@code null} |
||||
*/ |
||||
@Nullable |
||||
public T findByBeanName(String beanName) { |
||||
return this.beans.get(beanName); |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Loader class used to actually load the services. |
||||
*/ |
||||
public static class Loader { |
||||
|
||||
private final SpringFactoriesLoader springFactoriesLoader; |
||||
|
||||
private final ListableBeanFactory beanFactory; |
||||
|
||||
|
||||
Loader(SpringFactoriesLoader springFactoriesLoader, @Nullable ListableBeanFactory beanFactory) { |
||||
this.springFactoriesLoader = springFactoriesLoader; |
||||
this.beanFactory = beanFactory; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Load all AOT services of the given type. |
||||
* @param <T> the service type |
||||
* @param type the service type |
||||
* @return a new {@link AotServices} instance |
||||
*/ |
||||
public <T> AotServices<T> load(Class<T> type) { |
||||
return new AotServices<T>(this.springFactoriesLoader.load(type), loadBeans(type)); |
||||
} |
||||
|
||||
private <T> Map<String, T> loadBeans(Class<T> type) { |
||||
return (this.beanFactory != null) ? BeanFactoryUtils |
||||
.beansOfTypeIncludingAncestors(this.beanFactory, type, true, false) |
||||
: Collections.emptyMap(); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -1,92 +0,0 @@
@@ -1,92 +0,0 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.beans.factory.aot; |
||||
|
||||
import java.util.List; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.ListableBeanFactory; |
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.core.Ordered; |
||||
import org.springframework.core.mock.MockSpringFactoriesLoader; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; |
||||
|
||||
/** |
||||
* Tests for {@link AotFactoriesLoader}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
class AotFactoriesLoaderTests { |
||||
|
||||
@Test |
||||
void createWhenBeanFactoryIsNullThrowsException() { |
||||
assertThatIllegalArgumentException() |
||||
.isThrownBy(() -> new AotFactoriesLoader(null)) |
||||
.withMessage("'beanFactory' must not be null"); |
||||
} |
||||
|
||||
@Test |
||||
void createWhenSpringFactoriesLoaderIsNullThrowsException() { |
||||
ListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
assertThatIllegalArgumentException() |
||||
.isThrownBy(() -> new AotFactoriesLoader(beanFactory, null)) |
||||
.withMessage("'factoriesLoader' must not be null"); |
||||
} |
||||
|
||||
@Test |
||||
void loadLoadsFromBeanFactoryAndSpringFactoriesLoaderInOrder() { |
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
beanFactory.registerSingleton("b1", new TestFactoryImpl(0, "b1")); |
||||
beanFactory.registerSingleton("b2", new TestFactoryImpl(2, "b2")); |
||||
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader(); |
||||
springFactoriesLoader.addInstance(TestFactory.class, new TestFactoryImpl(1, "l1")); |
||||
springFactoriesLoader.addInstance(TestFactory.class, new TestFactoryImpl(3, "l2")); |
||||
AotFactoriesLoader loader = new AotFactoriesLoader(beanFactory, springFactoriesLoader); |
||||
List<TestFactory> loaded = loader.load(TestFactory.class); |
||||
assertThat(loaded).map(Object::toString).containsExactly("b1", "l1", "b2", "l2"); |
||||
} |
||||
|
||||
interface TestFactory { |
||||
} |
||||
|
||||
static class TestFactoryImpl implements TestFactory, Ordered { |
||||
|
||||
private final int order; |
||||
|
||||
private final String name; |
||||
|
||||
TestFactoryImpl(int order, String name) { |
||||
this.order = order; |
||||
this.name = name; |
||||
} |
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return this.order; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return this.name; |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,227 @@
@@ -0,0 +1,227 @@
|
||||
/* |
||||
* Copyright 2002-2022 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.beans.factory.aot; |
||||
|
||||
import java.io.IOException; |
||||
import java.net.URL; |
||||
import java.util.Enumeration; |
||||
|
||||
import org.junit.jupiter.api.Test; |
||||
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory; |
||||
import org.springframework.beans.factory.support.RootBeanDefinition; |
||||
import org.springframework.core.Ordered; |
||||
import org.springframework.core.io.support.SpringFactoriesLoader; |
||||
import org.springframework.core.mock.MockSpringFactoriesLoader; |
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat; |
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException; |
||||
|
||||
/** |
||||
* Tests for {@link AotServices}. |
||||
* |
||||
* @author Phillip Webb |
||||
*/ |
||||
class AotServicesTests { |
||||
|
||||
@Test |
||||
void factoriesLoadsFromAotFactoriesFiles() { |
||||
AotServices<?> loaded = AotServices.factories() |
||||
.load(BeanFactoryInitializationAotProcessor.class); |
||||
assertThat(loaded) |
||||
.anyMatch(BeanFactoryInitializationAotProcessor.class::isInstance); |
||||
} |
||||
|
||||
@Test |
||||
void factoriesWithClassLoaderLoadsFromAotFactoriesFile() { |
||||
TestSpringFactoriesClassLoader classLoader = new TestSpringFactoriesClassLoader( |
||||
"aot-services.factories"); |
||||
AotServices<?> loaded = AotServices.factories(classLoader) |
||||
.load(TestService.class); |
||||
assertThat(loaded).anyMatch(TestServiceImpl.class::isInstance); |
||||
} |
||||
|
||||
@Test |
||||
void factoriesWithSpringFactoriesLoaderWhenSpringFactoriesLoaderIsNullThrowsException() { |
||||
assertThatIllegalArgumentException() |
||||
.isThrownBy(() -> AotServices.factories((SpringFactoriesLoader) null)) |
||||
.withMessage("'springFactoriesLoader' must not be null"); |
||||
} |
||||
|
||||
@Test |
||||
void factoriesWithSpringFactoriesLoaderLoadsFromSpringFactoriesLoader() { |
||||
MockSpringFactoriesLoader loader = new MockSpringFactoriesLoader(); |
||||
loader.addInstance(TestService.class, new TestServiceImpl()); |
||||
AotServices<?> loaded = AotServices.factories(loader).load(TestService.class); |
||||
assertThat(loaded).anyMatch(TestServiceImpl.class::isInstance); |
||||
} |
||||
|
||||
@Test |
||||
void factoriesAndBeansWhenBeanFactoryIsNullThrowsException() { |
||||
assertThatIllegalArgumentException() |
||||
.isThrownBy(() -> AotServices.factoriesAndBeans(null)) |
||||
.withMessage("'beanFactory' must not be null"); |
||||
} |
||||
|
||||
@Test |
||||
void factoriesAndBeansLoadsFromFactoriesAndBeanFactory() { |
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
beanFactory.setBeanClassLoader( |
||||
new TestSpringFactoriesClassLoader("aot-services.factories")); |
||||
beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); |
||||
AotServices<?> loaded = AotServices.factoriesAndBeans(beanFactory).load(TestService.class); |
||||
assertThat(loaded).anyMatch(TestServiceImpl.class::isInstance); |
||||
assertThat(loaded).anyMatch(TestBean.class::isInstance); |
||||
} |
||||
|
||||
@Test |
||||
void factoriesAndBeansWithSpringFactoriesLoaderLoadsFromSpringFactoriesLoaderAndBeanFactory() { |
||||
MockSpringFactoriesLoader loader = new MockSpringFactoriesLoader(); |
||||
loader.addInstance(TestService.class, new TestServiceImpl()); |
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); |
||||
AotServices<?> loaded = AotServices.factoriesAndBeans(loader, beanFactory).load(TestService.class); |
||||
assertThat(loaded).anyMatch(TestServiceImpl.class::isInstance); |
||||
assertThat(loaded).anyMatch(TestBean.class::isInstance); |
||||
} |
||||
|
||||
@Test |
||||
void factoriesAndBeansWithSpringFactoriesLoaderWhenSpringFactoriesLoaderIsNullThrowsException() { |
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
assertThatIllegalArgumentException() |
||||
.isThrownBy(() -> AotServices.factoriesAndBeans(null, beanFactory)) |
||||
.withMessage("'springFactoriesLoader' must not be null"); |
||||
} |
||||
|
||||
@Test |
||||
void iteratorReturnsServicesIterator() { |
||||
AotServices<?> loaded = AotServices |
||||
.factories(new TestSpringFactoriesClassLoader("aot-services.factories")) |
||||
.load(TestService.class); |
||||
assertThat(loaded.iterator().next()).isInstanceOf(TestServiceImpl.class); |
||||
} |
||||
|
||||
@Test |
||||
void streamReturnsServicesStream() { |
||||
AotServices<?> loaded = AotServices |
||||
.factories(new TestSpringFactoriesClassLoader("aot-services.factories")) |
||||
.load(TestService.class); |
||||
assertThat(loaded.stream()).anyMatch(TestServiceImpl.class::isInstance); |
||||
} |
||||
|
||||
@Test |
||||
void asListReturnsServicesList() { |
||||
AotServices<?> loaded = AotServices |
||||
.factories(new TestSpringFactoriesClassLoader("aot-services.factories")) |
||||
.load(TestService.class); |
||||
assertThat(loaded.asList()).anyMatch(TestServiceImpl.class::isInstance); |
||||
} |
||||
|
||||
@Test |
||||
void findByBeanNameWhenMatchReturnsService() { |
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); |
||||
AotServices<?> loaded = AotServices.factoriesAndBeans(beanFactory).load(TestService.class); |
||||
assertThat(loaded.findByBeanName("test")).isInstanceOf(TestBean.class); |
||||
} |
||||
|
||||
@Test |
||||
void findByBeanNameWhenNoMatchReturnsNull() { |
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
beanFactory.registerBeanDefinition("test", new RootBeanDefinition(TestBean.class)); |
||||
AotServices<?> loaded = AotServices.factoriesAndBeans(beanFactory).load(TestService.class); |
||||
assertThat(loaded.findByBeanName("missing")).isNull(); |
||||
} |
||||
|
||||
@Test |
||||
void loadLoadsFromBeanFactoryAndSpringFactoriesLoaderInOrder() { |
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); |
||||
beanFactory.registerSingleton("b1", new TestServiceImpl(0, "b1")); |
||||
beanFactory.registerSingleton("b2", new TestServiceImpl(2, "b2")); |
||||
MockSpringFactoriesLoader springFactoriesLoader = new MockSpringFactoriesLoader(); |
||||
springFactoriesLoader.addInstance(TestService.class, |
||||
new TestServiceImpl(1, "l1")); |
||||
springFactoriesLoader.addInstance(TestService.class, |
||||
new TestServiceImpl(3, "l2")); |
||||
Iterable<TestService> loaded = AotServices |
||||
.factoriesAndBeans(springFactoriesLoader, beanFactory) |
||||
.load(TestService.class); |
||||
assertThat(loaded).map(Object::toString).containsExactly("b1", "l1", "b2", "l2"); |
||||
} |
||||
|
||||
|
||||
interface TestService { |
||||
} |
||||
|
||||
|
||||
static class TestServiceImpl implements TestService, Ordered { |
||||
|
||||
private final int order; |
||||
|
||||
private final String name; |
||||
|
||||
|
||||
TestServiceImpl() { |
||||
this(0, "test"); |
||||
} |
||||
|
||||
TestServiceImpl(int order, String name) { |
||||
this.order = order; |
||||
this.name = name; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public int getOrder() { |
||||
return this.order; |
||||
} |
||||
|
||||
@Override |
||||
public String toString() { |
||||
return this.name; |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
static class TestBean implements TestService { |
||||
|
||||
} |
||||
|
||||
|
||||
static class TestSpringFactoriesClassLoader extends ClassLoader { |
||||
|
||||
private final String factoriesName; |
||||
|
||||
|
||||
TestSpringFactoriesClassLoader(String factoriesName) { |
||||
super(Thread.currentThread().getContextClassLoader()); |
||||
this.factoriesName = factoriesName; |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Enumeration<URL> getResources(String name) throws IOException { |
||||
return (!"META-INF/spring/aot.factories".equals(name)) |
||||
? super.getResources(name) |
||||
: super.getResources("org/springframework/beans/factory/aot/" |
||||
+ this.factoriesName); |
||||
} |
||||
|
||||
} |
||||
|
||||
} |
@ -0,0 +1,2 @@
@@ -0,0 +1,2 @@
|
||||
org.springframework.beans.factory.aot.AotServicesTests$TestService=\ |
||||
org.springframework.beans.factory.aot.AotServicesTests$TestServiceImpl |
Loading…
Reference in new issue