In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-17 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly explains "how to use Gateway in SpringCloud". The content in the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "how to use Gateway in SpringCloud".
The invocation between SpringCloud micro-service projects is called through httprest requests. Before, we used tools such as HttpClient to make service requests. Spring handles this request and encapsulates it into a declarable web client, which makes it easier to write web clients. Feign also supports pluggable encoders and decoders. Spring adds the processing of @ requestMapping when in use. SpringCloud also integrates the registry (eureka) and client load balancing (ribbon) for feign, so that we have a web request client for client load balancing.
Feign source code analysis
@ Override public void refresh () throws BeansException, IllegalStateException {synchronized (this.startupShutdownMonitor) {/ / scan the java file in this project, encapsulate the bean object into a BeanDefinitiaon object, and then call the DefaultListableBeanFactory#registerBeanDefinition () method to put beanName in the List beanDefinitionNames of DefaultListableBeanFactory to ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory (); / / Prepare the bean factory for use in this context. PrepareBeanFactory (beanFactory); try {postProcessBeanFactory (beanFactory); / / call the registerBeanDefinitions () method invokeBeanFactoryPostProcessors (beanFactory) of the FeignClientsRegistrar object here; / / find all the methods that implement the BeanPostProcessor interface from the beanDefinitionNames in DefaultListableBeanFactory. If there is a sort, put it in registerBeanPostProcessors (beanFactory) in list / / Spring's internationalized initMessageSource (); / / initApplicationEventMulticaster (); / / Initialize other special beans in specific context subclasses. OnRefresh (); / / registerListeners (); / / IOC and ID processing of Spring. AOP for Spring. The BeanPostProcessor#postProcessBeforeInitialization () and postProcessBeforeInitialization () methods are called after the IOC is completed, and AOP (transaction) is the finishBeanFactoryInitialization (beanFactory) processed here; / / after execution, the onRefresh () method of the class that implements all LifecycleProcessor interfaces is called, and all events (observer mode) finishRefresh () that observe the ApplicationEvent interface are called. } catch (BeansException ex) {/ / find all the methods that implement the DisposableBean interface and call the destroy () method, which is bean's destroy destroyBeans (); / / Reset 'active' flag. CancelRefresh (ex); throw ex;} finally {resetCommonCaches ();}
According to the code sorted out above, it is found that the FeignClientsRegistrar#registerBeanDefinitions () method is called when there is only one beanname after scanning the bean, and there is no IOC registration. This is the Spring dynamic extension Bean, and all methods that implement the BeanDefinitionRegistryPostProcessor interface will also call the postProcessBeanDefinitionRegistry () method here. So much for the analysis of Spring. Let's get back to the point and analyze the FeignClientsRegistrar#registerBeanDefinitions () method:
@ Override public void registerBeanDefinitions (AnnotationMetadata metadata, BeanDefinitionRegistry registry) {registerDefaultConfiguration (metadata, registry); / / scan the information configured in the EnableFeignClients tag and register in beanDefinitionNames. RegisterFeignClients (metadata, registry);} public void registerFeignClients (AnnotationMetadata metadata, BeanDefinitionRegistry registry) {AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter (FeignClient.class); / / omit the code. Find all the FeignClient annotated classes under the package according to the basePackages configured by EnableFeignClients, and Spring's Commponet does the same. 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) / * key point: the concept of Feign sub-container: * when you inject the FeignAutoConfiguration class, you inject a FeignContext object, which is the sub-container of Fein. * there is a List object in it. The essence of the FeignClientSpecification object is that the name configured on @ feignClient is key. Value is the value of the configuration object * such as @ FeignClient (url= "https://api.weixin.qq.com",name="${usercenter.name}", configuration= UserCenterFeignConfiguration.class, primary= false) * configured by feignclient, then a data such as FeignClientSpecification {name='sms-server', configuration= [class com.jfbank.sms.configuration.FeignConfiguration]} appears in the FeignContext. * this place is critical, mainly because the custom class will be used to encode and decode the feign client * / / this method is to insert a FeignClientSpecification object into the ioc container to build the FeignContext sub-container. RegisterClientConfiguration (registry, name, attributes.get ("configuration")); / / focus on analyzing this registerFeignClient (registry, annotationMetadata, attributes);}} private void registerFeignClient (BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map attributes) {String className = annotationMetadata.getClassName () BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition (FeignClientFactoryBean.class); / / generate a BeanDefinition object for a pair of FeignClientFactoryBean objects. Read configuration 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}); / / register to the object BeanDefinitionReaderUtils.registerBeanDefinition (holder, registry) in beanDefinitionNames; / /}
Students who have read the Dubbo source code know that when parsing the reference tag in DubboNamespaceHandler, a ReferenceBean object is passed in, stuffing all the attributes configured in xml into this object, which is also installed in beanDefinitionNames, and then it is found that both the ReferenceBean class and FeignClientFactoryBean implement the interface of FactoryBean, and there are getObject () and getObjectType () methods in it. When the interface is called to the feign client, the FeignClientFactoryBean is read from the IOC and the getObject method is called. Here is the analysis of the getObject method:
@ Override public Object getObject () throws Exception {FeignContext context = applicationContext.getBean (FeignContext.class); / / get custom classes such as encoders and decoders from the sub-containers above, and then encapsulate a Feign.Builder class Feign.Builder builder = feign (context); if (! StringUtils.hasText (this.url)) {/ / when @ FeignClient is not configured with 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 client load balancing is integrated. Next analysis} / / when @ FeignClient is configured with 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);}
First of all, look at the feignclient parsing of url configured with url, and follow the code all the way to the Feign.Builder#target () method:
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);}
Look directly at the ReflectiveFeign#newInstance () method:
/ / ReflectiveFeign#newInstance () public T newInstance (Target target) {/ / the handler class of the dynamic proxy currently comes in the ParseHandlersByName class, so here we want to look at ParseHandlersByName#apply () and look directly at the next method 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)) {/ / default methods such as toString (), hashCode (), DefaultMethodHandler handler = new DefaultMethodHandler (method); defaultMethodHandlers.add (handler); methodToHandler.put (method, handler) } else {/ / here is the calling class of the assembly. The handler analyzed above is 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 dynamic proxy for (DefaultMethodHandler defaultMethodHandler: defaultMethodHandlers) {defaultMethodHandler.bindTo (proxy);} return proxy;} / / ParseHandlersByName#apply class to build 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); / / parse the parameter} else if (md.bodyIndex ()! = null) {buildTemplate = new BuildEncodedTemplateFromArgs (md, encoder) through custom encoder / / parse the parameter} else {buildTemplate = new BuildTemplateByResolvingArgs (md) through the custom encoder;} / / create the handler, then see the Factory#create () method, the next method result.put (md.configKey (), factory.create (key, md, buildTemplate, options, decoder, errorDecoder);} return result } / / Factory#create (), build a SynchronousMethodHandler to handle the request, call the invoke method 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 () method: method actually called / / @ Override public Object invoke (Object [] argv) throws Throwable {RequestTemplate template = buildTemplateFromArgs.create (argv); / / build requestTemplate object Retryer retryer = this.retryer.clone (); while (true) {try {return executeAndDecode (template) / / without further analysis, execute the execute method and decode the returned value} catch (RetryableException e) {retryer.continueOrPropagate (e); if (logLevel! = Logger.Level.NONE) {logger.logRetry (metadata.configKey (), logLevel);} continue } Thank you for your reading, the above is the content of "how to use SpringCloud Gateway". After the study of this article, I believe you have a deeper understanding of how to use SpringCloud Gateway, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.