Spring-Cloud-Loadblancer详细分析_2

这篇具有很好参考价值的文章主要介绍了Spring-Cloud-Loadblancer详细分析_2。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

@LoadBalancerClients

终于分析到了此注解的作用,它是实现不同服务之间的配置隔离的关键

@Configuration(proxyBeanMethods = false)
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
@Documented
@Import(LoadBalancerClientConfigurationRegistrar.class)
public @interface LoadBalancerClients {

	LoadBalancerClient[] value() default {};

	/**
	 * {@link LoadBalancerClientConfigurationRegistrar} creates a
	 * {@link LoadBalancerClientSpecification} with this as an argument. These in turn are
	 * added as default contexts in {@link LoadBalancerClientFactory}. Configuration
	 * defined in these classes are used as defaults if values aren't defined via
	 * {@link LoadBalancerClient#configuration()}
	 * @return classes for default configurations
	 */
	Class<?>[] defaultConfiguration() default {};

}

@Configuration(proxyBeanMethods = false)
@Import(LoadBalancerClientConfigurationRegistrar.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface LoadBalancerClient {

	/**
	 * Synonym for name (the name of the client).
	 *
	 * @see #name()
	 * @return the name of the load balancer client
	 */
	@AliasFor("name")
	String value() default "";

	/**
	 * The name of the load balancer client, uniquely identifying a set of client
	 * resources, including a load balancer.
	 * @return the name of the load balancer client
	 */
	@AliasFor("value")
	String name() default "";

	/**
	 * A custom <code>@Configuration</code> for the load balancer client. Can contain
	 * override <code>@Bean</code> definition for the pieces that make up the client.
	 *
	 * @see LoadBalancerClientConfiguration for the defaults
	 * @return configuration classes for the load balancer client.
	 */
	Class<?>[] configuration() default {};

}
  • LoadBalancerClients 就是其实就是多个LoadBalancerClient
  • LoadBalancerClient 相当于一个负载均衡配置,name/value 就是 serviceId,configuration 就是负载均衡配置
  • 通过@Import(LoadBalancerClientConfigurationRegistrar.class)来进行注入

LoadBalancerClientConfigurationRegistrar

public class LoadBalancerClientConfigurationRegistrar implements ImportBeanDefinitionRegistrar {

	private static String getClientName(Map<String, Object> client) {
		if (client == null) {
			return null;
		}
		String value = (String) client.get("value");
		if (!StringUtils.hasText(value)) {
			value = (String) client.get("name");
		}
		if (StringUtils.hasText(value)) {
			return value;
		}
		throw new IllegalStateException("Either 'name' or 'value' must be provided in @LoadBalancerClient");
	}

	private static void registerClientConfiguration(BeanDefinitionRegistry registry, Object name,
			Object configuration) {
		BeanDefinitionBuilder builder = BeanDefinitionBuilder
				.genericBeanDefinition(LoadBalancerClientSpecification.class);
		builder.addConstructorArgValue(name);
		builder.addConstructorArgValue(configuration);
		//每个LoadBalancerClient其实就是LoadBalancerClientSpecification
		registry.registerBeanDefinition(name + ".LoadBalancerClientSpecification", builder.getBeanDefinition());
	}

	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
		Map<String, Object> attrs = metadata.getAnnotationAttributes(LoadBalancerClients.class.getName(), true);
		//获取LoadBalancerClients 注解的属性
		if (attrs != null && attrs.containsKey("value")) {
			//value属性为LoadBalancerClient注解,可以给configuration赋值,填写需要的配置类,比如RandomLoadBalancerConfig.class
			AnnotationAttributes[] clients = (AnnotationAttributes[]) attrs.get("value");
			for (AnnotationAttributes client : clients) {
				//将配置类 注册到当前容器
				registerClientConfiguration(registry, getClientName(client), client.get("configuration"));
			}
		}
		if (attrs != null && attrs.containsKey("defaultConfiguration")) {
			String name;
			if (metadata.hasEnclosingClass()) {
				name = "default." + metadata.getEnclosingClassName();
			}
			else {
				name = "default." + metadata.getClassName();
			}
			//如果defaultConfiguration有配置,当做默认配置注册中,并赋值给所有容器
			registerClientConfiguration(registry, name, attrs.get("defaultConfiguration"));
		}
		//处理@LoadBalancerClient注解,逻辑和上面LoadBalancerClients的相同
		Map<String, Object> client = metadata.getAnnotationAttributes(LoadBalancerClient.class.getName(), true);
		String name = getClientName(client);
		if (name != null) {
			//configuration 属性的类 注册到容器中
			registerClientConfiguration(registry, name, client.get("configuration"));
		}
	}

}
  • LoadBalancerClients有一个默认的配置属性 Class<?>[] configuration() default {};这个属性的类以default. 开头来命名
  • LoadBalancerClients含有多个LoadBalancerClient,属性valueserviceId属性 Class<?>[] configuration() default {};是当前serviceId名字下的配置
  • LoadBalancerClients和每个LoadBalancerClientconfiguration都会被封装以clientName为维度的LoadBalancerClientSpecification,注册到当前容器中
  • 注意! 这时注册的是BeanDefinition类型的元数据,还没有开始真正的实例化bean!真正的实例化是在子容器创建的时候会将父容器添加进去,也相当于子容器也含有了,然后会启动子容器这时,就会进行真正的实例化。
  • 最终注入到LoadBalancerAutoConfiguration配置类的属性configurations,用于LoadBalancerClientFactory 的实例化
  • LoadBalancerClientFactory实例化的时候,就会获取LoadBalancerClientSpecification的对象了
    Spring-Cloud-Loadblancer详细分析_2,spring cloud,spring cloudSpring-Cloud-Loadblancer详细分析_2,spring cloud,spring cloud
    可以看到将LoadBalancerAutoConfigurationBlockingLoadBalancerClientAutoConfiguration注入,包装成LoadBalancerClientSpecification类型
LoadBalancerClientFactory

再看一眼LoadBalancerClientFactorybean实例生成的过程
Spring-Cloud-Loadblancer详细分析_2,spring cloud,spring cloud
可以看到将LoadBalancerClientSpecification类型的LoadBalancerAutoConfigurationBlockingLoadBalancerClientAutoConfiguration通过setConfiguations方法注入了进入

setConfiguations方法是在父类NamedContextFactory中执行的,稍微会分析NamedContextFactory,这里先分析LoadBalancerClientFactory 的结构

public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification>
		implements ReactiveLoadBalancer.Factory<ServiceInstance> {

	private static final Log log = LogFactory.getLog(LoadBalancerClientFactory.class);

	/**
	 * Property source name for load balancer.
	 */
	public static final String NAMESPACE = "loadbalancer";

	/**
	 * Property for client name within the load balancer namespace.
	 */
	public static final String PROPERTY_NAME = NAMESPACE + ".client.name";

	private final LoadBalancerClientsProperties properties;


	public LoadBalancerClientFactory(LoadBalancerClientsProperties properties) {
		//记住这个LoadBalancerClientConfiguration,被当成了默认配置类注入到 NamedContextFactory ,也就是每个子容器都会有这个配置类
		super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);
		this.properties = properties;
	}

	public static String getName(Environment environment) {
		return environment.getProperty(PROPERTY_NAME);
	}

	@Override
	public ReactiveLoadBalancer<ServiceInstance> getInstance(String serviceId) {
		return getInstance(serviceId, ReactorServiceInstanceLoadBalancer.class);
	}

	@Override
	public LoadBalancerProperties getProperties(String serviceId) {
		if (properties == null) {
			if (log.isWarnEnabled()) {
				log.warn("LoadBalancerClientsProperties is null. Please use the new constructor.");
			}
			return null;
		}
		if (serviceId == null || !properties.getClients().containsKey(serviceId)) {
			// no specific client properties, return default
			return properties;
		}
		// because specifics are overlayed on top of defaults, everything in `properties`,
		// unless overridden, is in `clientsProperties`
		return properties.getClients().get(serviceId);
	}

}

既然LoadBalancerClientConfiguration注入到NamedContextFactory中,我们就分析此配置类

LoadBalancerClientConfiguration

@Configuration(proxyBeanMethods = false)
@ConditionalOnDiscoveryEnabled
public class LoadBalancerClientConfiguration {

	private static final int REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER = 193827465;
    
    /**
     * 怕读者忘了此配置的注入过程,这里再说一下
     * 上文说的LoadBalancerAutoConfiguration配置类中,创建了 LoadBalancerClientFactory 的bean对象,存在于父容器中
     * 在此bean创建的过程中,会通过构造方法将此配置LoadBalancerClientConfiguration转入到LoadBalancerClientFactory中
     * 然后会当做默认配置类注册到 NamedContextFactory 的子容器中,这样每个子容器都拥有
     * 我们也可以自己实现这个ReactorLoadBalancer类型的bean,覆盖此配置
     *
     * */
	@Bean
	@ConditionalOnMissingBean
	public ReactorLoadBalancer<ServiceInstance> reactorServiceInstanceLoadBalancer(Environment environment,
			LoadBalancerClientFactory loadBalancerClientFactory) {
        // 获取当前子容器的名称(也是服务名)
		String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
		return new RoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
	}

	//省略...

	@Configuration(proxyBeanMethods = false)
	@ConditionalOnBlockingDiscoveryEnabled
	@Order(REACTIVE_SERVICE_INSTANCE_SUPPLIER_ORDER + 1)
	public static class BlockingSupportConfiguration {
        //ServiceInstanceListSupplier来查询ServiceInstance服务列表,能看到这里是DiscoveryClient提供的。这样就和注册中心关联了
		@Bean
		@ConditionalOnBean(DiscoveryClient.class)
		@ConditionalOnMissingBean
		@Conditional(DefaultConfigurationCondition.class)
		public ServiceInstanceListSupplier discoveryClientServiceInstanceListSupplier(
				ConfigurableApplicationContext context) {
			return ServiceInstanceListSupplier.builder().withBlockingDiscoveryClient().withCaching().build(context);
		}

	}

	//省略...

}

LoadBalancerClientConfiguration的作用分析完了,在上文中

public LoadBalancerClientFactory(LoadBalancerClientsProperties properties) {
	//记住这个LoadBalancerClientConfiguration,被当成了默认配置类注入到 NamedContextFactory ,也就是每个子容器都会有这个配置类
	super(LoadBalancerClientConfiguration.class, NAMESPACE, PROPERTY_NAME);
	this.properties = properties;
}

LoadBalancerClientConfiguration是传给了父类,LoadBalancerClientFactory 的结构

public class LoadBalancerClientFactory extends NamedContextFactory<LoadBalancerClientSpecification>
		implements ReactiveLoadBalancer.Factory<ServiceInstance> {..}

LoadBalancerClientFactory生成bean的过程中,调用完构造方法后,又执行了clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList)),此方法是在父类NamedContextFactory执行的

看一下clientFactory.setConfigurations(this.configurations.getIfAvailable(Collections::emptyList))执行结果
Spring-Cloud-Loadblancer详细分析_2,spring cloud,spring cloud

下面我们要分析父类NamedContextFactory,非常的重要

NamedContextFactory
public abstract class NamedContextFactory<C extends NamedContextFactory.Specification>
		implements DisposableBean, ApplicationContextAware {

	private final String propertySourceName;

	private final String propertyName;

	private Map<String, AnnotationConfigApplicationContext> contexts = new ConcurrentHashMap<>();

	private Map<String, C> configurations = new ConcurrentHashMap<>();

	private ApplicationContext parent;

	private Class<?> defaultConfigType;

	/**
	 * defaultConfigType是刚才文中说的子类LoadBalancerClientFactory创建时注入的。类型为LoadBalancerClientConfiguration
	 * */
	public NamedContextFactory(Class<?> defaultConfigType, String propertySourceName, String propertyName) {
		this.defaultConfigType = defaultConfigType;
		this.propertySourceName = propertySourceName;
		this.propertyName = propertyName;
	}

	@Override
	public void setApplicationContext(ApplicationContext parent) throws BeansException {
		this.parent = parent;
	}

	public ApplicationContext getParent() {
		return parent;
	}
	/**
	 * configurations为LoadBalancerAutoConfiguration和BlockingLoadBalancerClientAutoConfiguration,
	 * 文中刚才分析过
	 * */

	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<AnnotationConfigApplicationContext> values = this.contexts.values();
		for (AnnotationConfigApplicationContext context : values) {
			// This can fail, but it never throws an exception (you see stack traces
			// logged as WARN).
			context.close();
		}
		this.contexts.clear();
	}

	protected AnnotationConfigApplicationContext 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);
	}

	protected AnnotationConfigApplicationContext createContext(String name) {
		AnnotationConfigApplicationContext context;
		//创建容器
		if (this.parent != null) {
			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();
		}
		//configurations就是LoadBalancerClientSpecification类型的LoadBalancerAutoConfiguration和BlockingLoadBalancerClientAutoConfiguration
		//这里是将@LoadBalancerClient对应的负载均衡配置注册到对应的容器中
		//由以上可知通过此步我们可以使用@LoadBalancerClient自定义负载均衡策略
		//如果不自定义的话,这里为false
		if (this.configurations.containsKey(name)) {
			for (Class<?> configuration : this.configurations.get(name).getConfiguration()) {
				context.register(configuration);
			}
		}
		//也就是将configurations中LoadBalancerClientSpecification类型的LoadBalancerAutoConfiguration和BlockingLoadBalancerClientAutoConfiguration注册到容器中
		//这样每个容器就拥有了
		for (Map.Entry<String, C> entry : this.configurations.entrySet()) {
			if (entry.getKey().startsWith("default.")) {
				for (Class<?> configuration : entry.getValue().getConfiguration()) {
					context.register(configuration);
				}
			}
		}
		//defaultConfigType就是LoadBalancerClientConfiguration,在子类LoadBalancerClientFactory的构造方法传入
		//在刚才分析LoadBalancerClientFactory的时候介绍过
		context.register(PropertyPlaceholderAutoConfiguration.class, this.defaultConfigType);
		context.getEnvironment().getPropertySources().addFirst(new MapPropertySource(this.propertySourceName,
				Collections.<String, Object>singletonMap(this.propertyName, name)));
		//将父容器添加进去
		if (this.parent != null) {
			// Uses Environment from parent as well as beans
			context.setParent(this.parent);
		}
		context.setDisplayName(generateDisplayName(name));
		context.refresh();
		return context;
	}

	protected String generateDisplayName(String name) {
		return this.getClass().getSimpleName() + "-" + name;
	}
	/**
	 * 每个LoadBalancerClientSpecification都创建一个AnnotationConfigApplicationContext
	 * 也就是每个LoadBalancerClient会对应一个容器,其中的配置就对应容器中bean实例
	 * */
	public <T> T getInstance(String name, Class<T> type) {
		//获取AnnotationConfigApplicationContext类型的容器
		AnnotationConfigApplicationContext 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) {
		AnnotationConfigApplicationContext 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) {
		AnnotationConfigApplicationContext context = getContext(name);
		String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(context, type);
		if (beanNames.length > 0) {
			for (String beanName : beanNames) {
				if (context.isTypeMatch(beanName, type)) {
					return (T) context.getBean(beanName);
				}
			}
		}
		return null;
	}

	public <T> Map<String, T> getInstances(String name, Class<T> type) {
		AnnotationConfigApplicationContext context = getContext(name);

		return BeanFactoryUtils.beansOfTypeIncludingAncestors(context, type);
	}

	/**
	 * Specification with name and configuration.
	 */
	public interface Specification {

		String getName();

		Class<?>[] getConfiguration();

	}

}

到这里将每个@LoadBalancerClient都创建了AnnotationConfigApplicationContext的容器,然后放到了 LoadBalancerClientFactory

到这里bean的生成过程分析完毕,下一篇文章会分析整个执行过程文章来源地址https://www.toymoban.com/news/detail-646424.html

到了这里,关于Spring-Cloud-Loadblancer详细分析_2的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Cloud常见问题处理和代码分析

    Spring Cloud常见问题处理 解决方案:使用 Spring Cloud 提供的 Eureka、Zookeeper、Cloud Foundry 和 Consul 等注册中心来实现服务注册和发现。 示例代码: 解决方案:使用 Spring Cloud 提供的 Config Server 和 Config Client 来实现分布式配置。 示例代码: 解决方案:使用 Spring Cloud 提供的 Spring

    2024年02月14日
    浏览(47)
  • Spring Cloud Alibaba整合RocketMQ架构原理分析

    关于RocketMQ的原理,本文就不做详细分析了,这里就重点关注Spring Cloud Alibaba是如何整合RocketrMQ的。 RocketMQ提供了RocketMQ Client SDK,开发者可以直接依赖这个SDK,就可以完成消息的生产和消费。 1.生产消息 RocketMQ Client SDK提供了生产消息的API接口DefaultMQProducer,开发者可以直接使

    2024年01月22日
    浏览(55)
  • 如何在 Spring Cloud 项目中配置 Gateway 的详细说明

    在 Spring Cloud 中,可以使用 Spring Cloud Gateway 作为 API 网关。以下是如何在 Spring Cloud 项目中配置 Gateway 的详细说明: 添加依赖 在 pom.xml 文件中添加 spring-cloud-starter-gateway 依赖: 同时,确保你的项目已经添加了 Spring Cloud 的依赖管理: ${spring-cloud.version} 是你使用的 Spring Cloud 版

    2024年02月12日
    浏览(31)
  • Spring Cloud Gateway 服务网关的部署与使用详细介绍

    1、什么是服务网关:         传统的单体架构中只需要开放一个服务给客户端调用,但是微服务架构中是将一个系统拆分成多个微服务,如果没有网关,客户端只能在本地记录每个微服务的调用地址,当需要调用的微服务数量很多时,它需要了解每个服务的接口,这个工

    2024年02月02日
    浏览(48)
  • 【深入解析spring cloud gateway】06 gateway源码简要分析

    上一节做了一个很简单的示例,微服务通过注册到eureka上,然后网关通过服务发现访问到对应的微服务。本节将简单地对整个gateway请求转发过程做一个简单的分析。 主要流程: Gateway Client向 Spring Cloud Gateway 发送请求 请求首先会被HttpWebHandlerAdapter 进行提取组装成网关上下文

    2024年02月10日
    浏览(41)
  • SpringBoot、SpringCloud、Spring Cloud Alibaba版本对照表(详细)

    由于 Spring Boot 3.0,Spring Boot 2.7~2.4 和 2.4 以下版本之间变化较大,目前企业级客户老项目相关 Spring Boot 版本仍停留在 Spring Boot 2.4 以下,为了同时满足存量用户和新用户不同需求,社区以 Spring Boot 3.0 和 2.4 分别为分界线,同时维护 2022.x、2021.x、2.2.x 三个分支迭代。如果不想跨

    2024年02月12日
    浏览(61)
  • SpringBoot、SpringCloud、Spring Cloud Alibaba版本对照表(详细准确)

    ❤️一切信息来自官网,准确详细❤️ Spring Cloud Version Spring Boot Version 2022.0.x aka Kilburn 3.0.x 2021.0.x aka Jubilee 2.6.x, 2.7.x (Starting with 2021.0.3) 2020.0.x aka Ilford 2.4.x, 2.5.x (Starting with 2020.0.3) Hoxton 2.2.x, 2.3.x (Starting with SR5) Greenwich 2.1.x Finchley 2.0.x Edgware 1.5.x Dalston 1.5.x Spring Cloud Dalston, Ed

    2024年02月13日
    浏览(53)
  • 微服务之Spring Cloud Alibaba Sentinel介绍与下载(详细方法)

    随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、流量路由、熔断降级、系统自适应过载保护、热点流量防护等多个维度保护服务的稳定性。 2012 年,Sentinel 诞生,主要功能为入口流量控制。 2013-2017 年,Sentinel 在阿里巴巴

    2024年02月11日
    浏览(60)
  • 特别详细的Spring Cloud 系列教程1:服务注册中心Eureka的启动

    Eureka已经被Spring Cloud继承在其子项目spring-cloud-netflix中,搭建Eureka Server的方式还是非常简单的。只需要通过一个独立的maven工程即可搭建Eureka Server。  我们引入spring cloud的依赖和eureka的依赖。 注意spring cloud和springboot的版本要对应,不然容易出现各种奇怪的错误。 不知道spr

    2024年04月08日
    浏览(76)
  • 开源微服务如何选型?Spring Cloud、Dubbo、gRPC、Istio 详细对比

    作者:刘军 不论您是一名开发者、架构师、CTO, 如果您曾深度参与在微服务开发中,那么相信您一定有过开源微服务框架或体系选型的疑问:Apache Dubbo、Spring Cloud、gRPC 以及 Service Mesh 体系产品如 Istio,到底应该选型哪一个?这篇文章对这几个框架进行了详细的说明,并在选

    2024年02月11日
    浏览(41)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包