zoukankan      html  css  js  c++  java
  • SpringCloud之Ribbon源码解析(三)--@LoadBalanced

    本文着重分析下为什么加了@LoadBalanced就有了负载均衡的能力

    先看现象

    我们写代码都是这么写的

    @SpringBootApplication
    @EnableEurekaClient
    @EnableDiscoveryClient
    public class ServiceRibbonApplication {
    
        public static void main(String[] args) {
            SpringApplication.run( ServiceRibbonApplication.class, args );
        }
    
        @Bean
        @LoadBalanced
        RestTemplate restTemplate() {
            return new RestTemplate();
        }

    如果不加@LoadBalanced会怎么样呢?

    @Configuration
    @ConditionalOnClass(RestTemplate.class)
    @ConditionalOnBean(LoadBalancerClient.class)
    @EnableConfigurationProperties(LoadBalancerRetryProperties.class)
    public class LoadBalancerAutoConfiguration {
    
        @LoadBalanced
        @Autowired(required = false)
        private List<RestTemplate> restTemplates = Collections.emptyList();
    
        @Bean
        public SmartInitializingSingleton loadBalancedRestTemplateInitializerDeprecated(
                final ObjectProvider<List<RestTemplateCustomizer>> restTemplateCustomizers) {
            return () -> restTemplateCustomizers.ifAvailable(customizers -> {
                for (RestTemplate restTemplate : LoadBalancerAutoConfiguration.this.restTemplates) {//如果不加LoadBalanced那么这里restTemplates就是size=0
                    for (RestTemplateCustomizer customizer : customizers) {
                        customizer.customize(restTemplate);
                    }
                }
            });
        }

    所以不加@LoadBalanced注解的话,在LoadBalancerAutoConfiguration就不能自动注入restTemplates,也就导致了没法讲interceptor注入到RestTemplate中,这样RestTemplate就不会有负载均衡的能力

    换句话说,如果不在启动类里面加 @LoadBalanced那么在LoadBalancerAutoConfiguration 中就没法完成@Autowired

    @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
    @Retention(RetentionPolicy.RUNTIME)
    @Documented
    @Inherited
    @Qualifier
    public @interface LoadBalanced {
    }

    @LoadBalanced是@Qualifier的父类,所以它能配合@Autowired一起使用

    解析@Autowired最终会到达 DefaultListableBeanFactory

    protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
    DependencyDescriptor descriptor, AutowireCandidateResolver resolver)
    protected boolean isAutowireCandidate(String beanName, RootBeanDefinition mbd,
                DependencyDescriptor descriptor, AutowireCandidateResolver resolver) {
    
            String beanDefinitionName = BeanFactoryUtils.transformedBeanName(beanName);
            resolveBeanClass(mbd, beanDefinitionName);
            if (mbd.isFactoryMethodUnique) {
                boolean resolve;
                synchronized (mbd.constructorArgumentLock) {
                    resolve = (mbd.resolvedConstructorOrFactoryMethod == null);
                }
                if (resolve) {
                    new ConstructorResolver(this).resolveFactoryMethodIfPossible(mbd);
                }
            }
            return resolver.isAutowireCandidate(
                    new BeanDefinitionHolder(mbd, beanName, getAliases(beanDefinitionName)), descriptor);
        }

    说下上面的参数

     1 beanName是要判断是否应该注入的beanName,比如restTemplate

     2 DependencyDescriptor是指 描述成员变量restTemplates 的注解信息的比如它有@LoadBalanced

    public class LoadBalancerAutoConfiguration {
    
        @LoadBalanced
        @Autowired(required = false)
        private List<RestTemplate> restTemplates = Collections.emptyList();

      QualifierAnnotationAutowireCandidateResolver

    public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
            boolean match = super.isAutowireCandidate(bdHolder, descriptor);
            if (match) {
                match = checkQualifiers(bdHolder, descriptor.getAnnotations());
                if (match) {
                    MethodParameter methodParam = descriptor.getMethodParameter();
                    if (methodParam != null) {
                        Method method = methodParam.getMethod();
                        if (method == null || void.class == method.getReturnType()) {
                            match = checkQualifiers(bdHolder, methodParam.getMethodAnnotations());
                        }
                    }
                }
            }
            return match;
        }
    protected boolean checkQualifiers(BeanDefinitionHolder bdHolder, Annotation[] annotationsToSearch) {
            if (ObjectUtils.isEmpty(annotationsToSearch)) {
                return true;
            }
            SimpleTypeConverter typeConverter = new SimpleTypeConverter();
            for (Annotation annotation : annotationsToSearch) {
                Class<? extends Annotation> type = annotation.annotationType();
                boolean checkMeta = true;
                boolean fallbackToMeta = false;
                if (isQualifier(type)) {
                    if (!checkQualifier(bdHolder, annotation, typeConverter)) {
                        fallbackToMeta = true;
                    }
                    else {
                        checkMeta = false;
                    }
                }
                if (checkMeta) {
                    boolean foundMeta = false;
                    for (Annotation metaAnn : type.getAnnotations()) {
                        Class<? extends Annotation> metaType = metaAnn.annotationType();
                        if (isQualifier(metaType)) {
                            foundMeta = true;
                            // Only accept fallback match if @Qualifier annotation has a value...
                            // Otherwise it is just a marker for a custom qualifier annotation.
                            if ((fallbackToMeta && StringUtils.isEmpty(AnnotationUtils.getValue(metaAnn))) ||
                                    !checkQualifier(bdHolder, metaAnn, typeConverter)) {
                                return false;
                            }
                        }
                    }
                    if (fallbackToMeta && !foundMeta) {
                        return false;
                    }
                }
            }
            return true;
        }

    就是判断DependencyDescriptor中有的注解,候选beanDefinition是否也有,如果没有那就不应该选择它作为@Autowired的候选了

    所以说知道当我们给RestTemplate加上@LoadBalanced注解它才有负载均衡的能力

  • 相关阅读:
    仿发送微博限制只发送140个字(一个汉字占位2字节)
    Linux下多任务间通信和同步-信号
    Color
    面试遇到的问题
    Jquery Mobile左右滑动效果
    C++ primer(八)--内联函数 引用变量 引用传递函数参数 函数重载/模板/模板具体化
    Python3 配置文件 解析
    Python MySQL ORM QuickORM hacking
    Python 获取 网卡 MAC 地址
    AttributeError: 'dict_values' object has no attribute 'translate'
  • 原文地址:https://www.cnblogs.com/juniorMa/p/14421412.html
Copyright © 2011-2022 走看看