依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
<version>4.3.0</version>
</dependency>
源码
NamedContextFactory
NamedContextFactory
类通过创建多个子上下文并为每个子上下文定义不同的配置,提供了灵活的 Spring 上下文管理方式。
/**
* Creates a set of child contexts that allows a set of Specifications to define the beans
* in each child context. Ported from spring-cloud-netflix FeignClientFactory and
* SpringClientFactory
*
* @param <C> specification
* @author Spencer Gibb
* @author Dave Syer
* @author Tommy Karlsson
* @author Olga Maciaszek-Sharma
*/
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification> implements DisposableBean, ApplicationContextAware {
// 子容器初始化
private final Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers;
private final String propertySourceName;
private final String propertyName;
// 子容器集合
private final Map<String, GenericApplicationContext> contexts = new ConcurrentHashMap<>();
// 子容器配置
private final Map<String, C> configurations = new ConcurrentHashMap<>();
// 父容器
private ApplicationContext parent;
private final Class<?> defaultConfigType;
public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) {
this(defaultConfigType, propertySourceName, propertyName, new HashMap<>());
}
public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName, Map<String, ApplicationContextInitializer<GenericApplicationContext>> applicationContextInitializers) {
this.defaultConfigType = defaultConfigType;
this.propertySourceName = propertySourceName;
this.propertyName = propertyName;
this.applicationContextInitializers = applicationContextInitializers;
}
@Override
public void setApplicationContext(ApplicationContext parent) throws BeansException {
this.parent = parent;
}
public ApplicationContext getParent() {
return parent;
}
public void setConfigurations(List<C> configurations) {
for (C client : configurations) {
this.configurations.put(client.getName(), client);
}
}
public Set<String> getContextNames() {
return new HashSet<>(this.contexts.keySet());
}
@Override
public void destroy() {
Collection<GenericApplicationContext> values = this.contexts.values();
for (GenericApplicationContext context : values) {
// This can fail, but it never throws an exception (you see stack traces
// logged as WARN).
context.close();
}
this.contexts.clear();
}
protected GenericApplicationContext getContext(String name) {
if (!this.contexts.containsKey(name)) {
synchronized (this.contexts) {
if (!this.contexts.containsKey(name)) {
this.contexts.put(name, createContext(name));
}
}
}
return this.contexts.get(name);
}
public GenericApplicationContext createContext(String name) {
GenericApplicationContext context = buildContext(name);
// there's an AOT initializer for this context
if (applicationContextInitializers.get(name) != null) {
applicationContextInitializers.get(name).initialize(context);
context.refresh();
return context;
}
registerBeans(name, context);
context.refresh();
return context;
}
public void registerBeans(String name, GenericApplicationContext context) {
Assert.isInstanceOf(AnnotationConfigRegistry.class, context);
AnnotationConfigRegistry registry = (AnnotationConfigRegistry) context;
if (this.configurations.containsKey(name)) {
for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
registry.register(configuration);
}
}
for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
if (entry.getKey().startsWith("default.")) {
for (Class<?> configuration : entry.getValue().getConfiguration()) {
registry.register(configuration);
}
}
}
registry.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
}
// 根据指定名称创建并配置一个 GenericApplicationContext,并根据父上下文、AOT 支持等条件动态选择上下文实现。
public GenericApplicationContext buildContext(String name) {
// https://github.com/spring-cloud/spring-cloud-netflix/issues/3101
// https://github.com/spring-cloud/spring-cloud-openfeign/issues/475
ClassLoader classLoader = getClass().getClassLoader();
GenericApplicationContext context;
if (this.parent != null) {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
if (parent instanceof ConfigurableApplicationContext) {
beanFactory.setBeanClassLoader(((ConfigurableApplicationContext) parent).getBeanFactory().getBeanClassLoader());
}
else {
beanFactory.setBeanClassLoader(classLoader);
}
context = AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext(beanFactory) : new AnnotationConfigApplicationContext(beanFactory);
}
else {
context = AotDetector.useGeneratedArtifacts() ? new GenericApplicationContext() : new AnnotationConfigApplicationContext();
}
context.setClassLoader(classLoader);
context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName, Collections.singletonMap(this.propertyName, name)));
if (this.parent != null) {
// Uses Environment from parent as well as beans
context.setParent(this.parent);
}
context.setDisplayName(generateDisplayName(name));
return context;
}
protected String generateDisplayName(String name) {
return this.getClass().getSimpleName() + "-" + name;
}
public <T> T getInstance(String name, Class<T> type) {
GenericApplicationContext context = getContext(name);
try {
return context.getBean(type);
}
catch (NoSuchBeanDefinitionException e) {
// ignore
}
return null;
}
public <T> ObjectProvider<T> getLazyProvider(String name, Class<T> type) {
return new ClientFactoryObjectProvider<>(this, name, type);
}
public <T> ObjectProvider<T> getProvider(String name, Class<T> type) {
GenericApplicationContext context = getContext(name);
return context.getBeanProvider(type);
}
public <T> T getInstance(String name, Class<?> clazz, Class<?>... generics) {
ResolvableType type = ResolvableType.forClassWithGenerics(clazz, generics);
return getInstance(name, type);
}
@SuppressWarnings("unchecked")
public <T> T getInstance(String name, ResolvableType type) {
GenericApplicationContext context = getContext(name);
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type);
for (String beanName : beanNames) {
if (context.isTypeMatch(beanName, type)) {
return (T) context.getBean(beanName);
}
}
return null;
}
@SuppressWarnings("unchecked")
public <T> T getAnnotatedInstance(String name, ResolvableType type, Class<? extends Annotation> annotationType) {
GenericApplicationContext context = getContext(name);
String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(context, annotationType);
List<T> beans = new ArrayList<>();
for (String beanName : beanNames) {
if (context.isTypeMatch(beanName, type)) {
beans.add((T) context.getBean(beanName));
}
}
if (beans.size() > 1) {
throw new IllegalStateException("Only one annotated bean for type expected.");
}
return beans.isEmpty() ? null : beans.get(0);
}
public <T> Map<String, T> getInstances(String name, Class<T> type) {
GenericApplicationContext context = getContext(name);
return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);
}
public Map<String, C> getConfigurations() {
return configurations;
}
/**
* Specification with name and configuration.
*/
public interface Specification {
String getName();
Class<?>[] getConfiguration();
}
}
ClientFactoryObjectProvider
ClientFactoryObjectProvider
是一个特殊的 ObjectProvider
,它通过延迟解析实际的 ObjectProvider
,以便在创建命名的子上下文后再解析对象。
class ClientFactoryObjectProvider<T> implements ObjectProvider<T> {
private final NamedContextFactory<?> clientFactory;
private final String name;
private final Class<T> type;
private ObjectProvider<T> provider;
ClientFactoryObjectProvider(NamedContextFactory<?> clientFactory, String name, Class<T> type) {
this.clientFactory = clientFactory;
this.name = name;
this.type = type;
}
@Override
public T getObject(Object... args) throws BeansException {
return delegate().getObject(args);
}
@Override
@Nullable
public T getIfAvailable() throws BeansException {
return delegate().getIfAvailable();
}
@Override
public T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
return delegate().getIfAvailable(defaultSupplier);
}
@Override
public void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {
delegate().ifAvailable(dependencyConsumer);
}
@Override
@Nullable
public T getIfUnique() throws BeansException {
return delegate().getIfUnique();
}
@Override
public T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {
return delegate().getIfUnique(defaultSupplier);
}
@Override
public void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
delegate().ifUnique(dependencyConsumer);
}
@Override
public Iterator<T> iterator() {
return delegate().iterator();
}
@Override
public Stream<T> stream() {
return delegate().stream();
}
@Override
public T getObject() throws BeansException {
return delegate().getObject();
}
@Override
public void forEach(Consumer<? super T> action) {
delegate().forEach(action);
}
@Override
public Spliterator<T> spliterator() {
return delegate().spliterator();
}
private ObjectProvider<T> delegate() {
if (this.provider == null) {
this.provider = this.clientFactory.getProvider(this.name, this.type);
}
return this.provider;
}
}
实现
推荐阅读:[spring-cloud: @LoadBalanced & @LoadBalancerClient]-源码分析