依赖
<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;}@Overridepublic 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());}@Overridepublic 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 contextif (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/475ClassLoader 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 beanscontext.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;}@Overridepublic T getObject(Object... args) throws BeansException {return delegate().getObject(args);}@Override@Nullablepublic T getIfAvailable() throws BeansException {return delegate().getIfAvailable();}@Overridepublic T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {return delegate().getIfAvailable(defaultSupplier);}@Overridepublic void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {delegate().ifAvailable(dependencyConsumer);}@Override@Nullablepublic T getIfUnique() throws BeansException {return delegate().getIfUnique();}@Overridepublic T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {return delegate().getIfUnique(defaultSupplier);}@Overridepublic void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {delegate().ifUnique(dependencyConsumer);}@Overridepublic Iterator<T> iterator() {return delegate().iterator();}@Overridepublic Stream<T> stream() {return delegate().stream();}@Overridepublic T getObject() throws BeansException {return delegate().getObject();}@Overridepublic void forEach(Consumer<? super T> action) {delegate().forEach(action);}@Overridepublic 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]-源码分析