千家信息网

SpringCloud的Gateway怎么使用

发表于:2026-11-02 作者:千家信息网编辑
千家信息网最后更新 2026年11月02日,这篇文章主要讲解了"SpringCloud的Gateway怎么使用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"SpringCloud的Gateway
千家信息网最后更新 2026年11月02日SpringCloud的Gateway怎么使用

这篇文章主要讲解了"SpringCloud的Gateway怎么使用",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"SpringCloud的Gateway怎么使用"吧!

SpringCloud微服务项目之间调用是通过httprest请求来进行服务调用的,之前我们会用到HttpClient等工具来进行服务请求,Spring对这种请求进行了处理,封装成了可声明式的web客户端,使得编写web客户端更容易,feign还支持可插拔的编码器和解码器,Spring在用的时候增加了对@requestMapping的处理,同时,SpringCloud还对feign集成了注册中心(eureka)和客户端负载均衡(ribbon),使得我们拥有一个客户端负载均衡的web请求客户端。

Feign源码分析

  @Override    public void refresh() throws BeansException, IllegalStateException {        synchronized (this.startupShutdownMonitor) {            // 扫描本项目里面的java文件,把bean对象封装成BeanDefinitiaon对象,然后调用DefaultListableBeanFactory#registerBeanDefinition()方法把beanName放到DefaultListableBeanFactory 的 List beanDefinitionNames 中去            ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();            // Prepare the bean factory for use in this context.            prepareBeanFactory(beanFactory);            try {                postProcessBeanFactory(beanFactory);                // 在这里调用到FeignClientsRegistrar对象的registerBeanDefinitions()方法                invokeBeanFactoryPostProcessors(beanFactory);                //从DefaultListableBeanFactory里面的beanDefinitionNames中找到所有实现了BeanPostProcessor接口的方法,如果有排序进行排序后放到list中                registerBeanPostProcessors(beanFactory);                //Spring的国际化                initMessageSource();                //                 initApplicationEventMulticaster();                // Initialize other special beans in specific context subclasses.                onRefresh();                //                 registerListeners();                // Spring的IOC、ID处理。Spring的AOP。事务都是在IOC完成之后调用了BeanPostProcessor#postProcessBeforeInitialization()和postProcessBeforeInitialization()方法,AOP(事务)就是在这里处理的                finishBeanFactoryInitialization(beanFactory);                // 执行完之后调用实现了所有LifecycleProcessor接口的类的onRefresh()方法,同时调用所有观察了ApplicationEvent接口的事件(观察者模式)                finishRefresh();            }            catch (BeansException ex) {                // 找到所有实现了DisposableBean接口的方法,调用了destroy()方法,这就是bean的销毁                destroyBeans();                // Reset 'active' flag.                cancelRefresh(ex);                throw ex;            }            finally {                resetCommonCaches();            }        }    }

根据上面整理的代码发现,FeignClientsRegistrar#registerBeanDefinitions()方法是在扫描完bean之后,只放了一个beanname的情况下, 并没有进行IOC注册的时候调用的,这就是Spring动态扩展Bean,实现BeanDefinitionRegistryPostProcessor接口的所有方法也会在这里调用下postProcessBeanDefinitionRegistry()方法。关于Spring的东西就分析到这里。下面回到正题,分析FeignClientsRegistrar#registerBeanDefinitions()方法:

 @Override    public void registerBeanDefinitions(AnnotationMetadata metadata,            BeanDefinitionRegistry registry) {        registerDefaultConfiguration(metadata, registry);//扫描EnableFeignClients标签里配置的信息,注册到beanDefinitionNames中。        registerFeignClients(metadata, registry);    }     public void registerFeignClients(AnnotationMetadata metadata,            BeanDefinitionRegistry registry) {        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(                FeignClient.class);        //省略代码...根据EnableFeignClients配置的basePackages找到包下所有FeignClient注解的类,Spring的Commponet也是这么干的        for (String basePackage : basePackages) {            Set candidateComponents = scanner                    .findCandidateComponents(basePackage);            for (BeanDefinition candidateComponent : candidateComponents) {                if (candidateComponent instanceof AnnotatedBeanDefinition) {                    // verify annotated class is an interface                    AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent;                    AnnotationMetadata annotationMetadata = beanDefinition.getMetadata();                    Assert.isTrue(annotationMetadata.isInterface(),                            "@FeignClient can only be specified on an interface");                    Map attributes = annotationMetadata                            .getAnnotationAttributes(                                    FeignClient.class.getCanonicalName());                    String name = getClientName(attributes);                   /**                     * 关键地方:Feign子容器概念:                     * 在注入FeignAutoConfiguration类的时候,注入了一个FeignContext对象,这个就是Feign的子容器。                     * 这里面装了List对象,FeignClientSpecification对象的实质就是在@feignClient上配置的name为key,value为configuration对象的值                     * 比如feignclient 这样配置的@FeignClient(url="https://api.weixin.qq.com",name="${usercenter.name}", configuration = UserCenterFeignConfiguration.class, primary= false)                     * 那么在FeignContext中就会出现一个FeignClientSpecification{name='sms-server', configuration=[class com.jfbank.sms.configuration.FeignConfiguration]}这样的数据。                     *  这个地方比较关键,主要是因为后期对feign客户端的编码解码会用到自定义的类                     */                    //这个方法就是在ioc容器中塞入一个FeignClientSpecification对象,从而构建FeignContext子容器。                    registerClientConfiguration(registry, name,                            attributes.get("configuration"));                           //重点分析这个                    registerFeignClient(registry, annotationMetadata, attributes);                }            }        }    }    private void registerFeignClient(BeanDefinitionRegistry registry,            AnnotationMetadata annotationMetadata, Map attributes) {        String className = annotationMetadata.getClassName();        BeanDefinitionBuilder definition = BeanDefinitionBuilder                .genericBeanDefinition(FeignClientFactoryBean.class);//对FeignClientFactoryBean对象生成一个BeanDefinition对象        ...读取配置        String alias = name + "FeignClient";        AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();        boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null        beanDefinition.setPrimary(primary);        String qualifier = getQualifier(attributes);        if (StringUtils.hasText(qualifier)) {            alias = qualifier;        }        BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className,                new String[] { alias });        //注册到beanDefinitionNames中对象        BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry);//    }

读过Dubbo源码的同学都知道,当在DubboNamespaceHandler中解析reference标签的时候,传入了一个ReferenceBean对象,把xml中配置的属性都塞到这个对象上,也是装到了beanDefinitionNames中,然后发现ReferenceBean类和FeignClientFactoryBean都实现了FactoryBean的接口,并且里面都有getObject()和getObjectType()方法。当接口调用到这个feign客户端的时候,会从IOC中读取这个FeignClientFactoryBean并且调用getObject方法。下面就是分析getObject方法:

 @Override    public Object getObject() throws Exception {        FeignContext context = applicationContext.getBean(FeignContext.class);        //从上文中的子容器中获取编码器,解码器等自定义类,然后封装一个Feign.Builder类        Feign.Builder builder = feign(context);        if (!StringUtils.hasText(this.url)) {//当@FeignClient没有配置url的时候            String url;            if (!this.name.startsWith("http")) {                url = "http://" + this.name;            }            else {                url = this.name;            }            url += cleanPath();            return loadBalance(builder, context, new HardCodedTarget<>(this.type,                    this.name, url));//集成了ribbon客户端负载均衡,下一篇分析        }        //当@FeignClient配置了url的时候        if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {            this.url = "http://" + this.url;        }        String url = this.url + cleanPath();        Client client = getOptional(context, Client.class);        if (client != null) {            if (client instanceof LoadBalancerFeignClient) {                // not lod balancing because we have a url,                // but ribbon is on the classpath, so unwrap                client = ((LoadBalancerFeignClient)client).getDelegate();            }            builder.client(client);        }        Targeter targeter = get(context, Targeter.class);        return targeter.target(this, builder, context, new HardCodedTarget<>(                this.type, this.name, url));    }

首先看配置了url的,指定了url的feignclient解析,一直跟着代码跟到了Feign.Builder#target()方法:

   public  T target(Target target) {      return build().newInstance(target);    }    public Feign build() {      SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =          new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,                                               logLevel, decode404);      ParseHandlersByName handlersByName =          new ParseHandlersByName(contract, options, encoder, decoder,                                  errorDecoder, synchronousMethodHandlerFactory);      return new ReflectiveFeign(handlersByName, invocationHandlerFactory);    }

直接看ReflectiveFeign#newInstance()方法:

//ReflectiveFeign#newInstance()    public  T newInstance(Target target) {                                                //动态代理的handler类目前穿进来的是ParseHandlersByName类,所以这里要看ParseHandlersByName#apply()直接看下一个方法      Map nameToHandler = targetToHandlersByName.apply(target);      Map methodToHandler = new LinkedHashMap();      List defaultMethodHandlers = new LinkedList();      for (Method method : target.type().getMethods()) {        if (method.getDeclaringClass() == Object.class) {          continue;        } else if(Util.isDefault(method)) {//默认方法会走到这里,比如toString(),hashCode()等方法          DefaultMethodHandler handler = new DefaultMethodHandler(method);          defaultMethodHandlers.add(handler);          methodToHandler.put(method, handler);        } else {//这里才是装配的调用类,上文分析到计息的handler是SynchronousMethodHandler#invoke()          methodToHandler.put(method, nameToHandler.get(Feign.configKey(target.type(), method)));        }      }      InvocationHandler handler = factory.create(target, methodToHandler);      T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class[]{target.type()}, handler);//jdk动态代理      for(DefaultMethodHandler defaultMethodHandler : defaultMethodHandlers) {        defaultMethodHandler.bindTo(proxy);      }      return proxy;    }    //ParseHandlersByName#apply类,构建动态代理的handler    public Map apply(Target key) {        List metadata = contract.parseAndValidatateMetadata(key.type());        Map result = new LinkedHashMap();        for (MethodMetadata md : metadata) {          BuildTemplateByResolvingArgs buildTemplate;          if (!md.formParams().isEmpty() && md.template().bodyTemplate() == null) {            buildTemplate = new BuildFormEncodedTemplateFromArgs(md, encoder);//通过自定义的encoder去解析参数          } else if (md.bodyIndex() != null) {            buildTemplate = new BuildEncodedTemplateFromArgs(md, encoder);//通过自定义的encoder去解析参数          } else {            buildTemplate = new BuildTemplateByResolvingArgs(md);          }          //创建handler,再看Factory#create()方法,下一个方法          result.put(md.configKey(),                     factory.create(key, md, buildTemplate, options, decoder, errorDecoder));        }        return result;      }    //Factory#create(),构建一个SynchronousMethodHandler去处理请求,调用invoke方法    public MethodHandler create(Target target, MethodMetadata md,            RequestTemplate.Factory buildTemplateFromArgs,            Options options, Decoder decoder, ErrorDecoder errorDecoder) {        return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,                      logLevel, md, buildTemplateFromArgs, options, decoder,                      errorDecoder, decode404);    }    //SynchronousMethodHandler#invoke()方法:实际调用的方法    //@Override    public Object invoke(Object[] argv) throws Throwable {        RequestTemplate template = buildTemplateFromArgs.create(argv);//构建requestTemplate对象        Retryer retryer = this.retryer.clone();        while (true) {          try {            return executeAndDecode(template);//下面不分析了,就是执行execute方法并且解码饭后返回值          } catch (RetryableException e) {            retryer.continueOrPropagate(e);            if (logLevel != Logger.Level.NONE) {              logger.logRetry(metadata.configKey(), logLevel);            }            continue;          }        }      }

感谢各位的阅读,以上就是"SpringCloud的Gateway怎么使用"的内容了,经过本文的学习后,相信大家对SpringCloud的Gateway怎么使用这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

方法 对象 就是 配置 客户 分析 接口 时候 客户端 容器 处理 动态 均衡 代码 编码 代理 学习 封装 服务 上文 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 咖啡 互联网科技海报 互联网科技名片 互联网科技公司排名 广东万易互联网科技有限公司惠州分公司 哈尔滨大商圈互联网科技有限公司 互联网公司 科技公司 平安科技 互联网 善班互联网科技有限公司 互联网科技的未来发展 互联网科技美容 哈尔滨秒房互联网科技有限公司 互联网媒体平台算高科技产业 坤平互联网科技 佛山市翊博互联网络科技有限公司 互联网科技包装股份有限公司上市 江苏互联网科技小贷 安徽零酒互联网科技有限公司 优雇互联网科技有限公司 每日互联网科技新闻 安徽鑫晟辉互联网科技 互联网金融科技创新 互联网科技大会案例 银川新华互联网科技职业技术培训学校图片 福建科技产业互联网发展 上海创道互联网络科技有限公司 江苏互联网智能科技产品出厂价 科技信息时代互联网发展 青岛易易互联网科技 重庆科技产业互联网有哪些
0