当前位置:网站首页>Working principle of sentinel series (source code analysis)

Working principle of sentinel series (source code analysis)

2022-06-13 05:41:00 codain

stay SpringCloud Use in sentinel Achieve current limiting , We don't need too many configurations in the project ,Sentinel Will automatically protect all HTTP service

Let's see Spring-Cloud-Starter-Alibaba-Sentinel Under this bag , This bag with this Starter The automatic assembly is realized , So we went straight to the bag below spring.factories file , All I see is key=value Configuration information , I won't post it here , Mainly explain the main configuration classes

1、SentinelWebAutoConfiguration It's right Web Servlet Environmental support

2、SentinelWebFluxAutoConfiguration It's right Spring WebFlux Support for

3、SentinelEndpointAutoConfiguration expose Endpoint Information

4、SentinelFeignAutoConfiguration For adaptation Feign Components

5、SentinelAutoConfiguration Support for RestTemplate Service invocation using Sentinel To protect

Let's focus on :SentinelWebAutoConfiguration, This Web Servlet The implementation of the , Source code :

package com.alibaba.cloud.sentinel;

import com.alibaba.csp.sentinel.adapter.servlet.CommonFilter;
import com.alibaba.csp.sentinel.adapter.servlet.callback.RequestOriginParser;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlBlockHandler;
import com.alibaba.csp.sentinel.adapter.servlet.callback.UrlCleaner;
import com.alibaba.csp.sentinel.adapter.servlet.callback.WebCallbackManager;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import javax.annotation.PostConstruct;
import javax.servlet.Filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
@ConditionalOnClass({CommonFilter.class})
@ConditionalOnProperty(
    name = {"spring.cloud.sentinel.enabled"},
    matchIfMissing = true
)
@EnableConfigurationProperties({SentinelProperties.class})
public class SentinelWebAutoConfiguration {
    private static final Logger log = LoggerFactory.getLogger(SentinelWebAutoConfiguration.class);
    @Autowired
    private SentinelProperties properties;
    @Autowired
    private Optional<UrlCleaner> urlCleanerOptional;
    @Autowired
    private Optional<UrlBlockHandler> urlBlockHandlerOptional;
    @Autowired
    private Optional<RequestOriginParser> requestOriginParserOptional;

    public SentinelWebAutoConfiguration() {
    }

    @PostConstruct
    public void init() {
        this.urlBlockHandlerOptional.ifPresent(WebCallbackManager::setUrlBlockHandler);
        this.urlCleanerOptional.ifPresent(WebCallbackManager::setUrlCleaner);
        this.requestOriginParserOptional.ifPresent(WebCallbackManager::setRequestOriginParser);
    }

    @Bean
    @ConditionalOnProperty(
        name = {"spring.cloud.sentinel.filter.enabled"},
        matchIfMissing = true
    )
    public FilterRegistrationBean sentinelFilter() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean();
        com.alibaba.cloud.sentinel.SentinelProperties.Filter filterConfig = this.properties.getFilter();
        if (filterConfig.getUrlPatterns() == null || filterConfig.getUrlPatterns().isEmpty()) {
            List<String> defaultPatterns = new ArrayList();
            defaultPatterns.add("/*");
            filterConfig.setUrlPatterns(defaultPatterns);
        }

        registration.addUrlPatterns((String[])filterConfig.getUrlPatterns().toArray(new String[0]));
        Filter filter = new CommonFilter();
        registration.setFilter(filter);
        registration.setOrder(filterConfig.getOrder());
        registration.addInitParameter("HTTP_METHOD_SPECIFY", String.valueOf(this.properties.getHttpMethodSpecify()));
        log.info("[Sentinel Starter] register Sentinel CommonFilter with urlPatterns: {}.", filterConfig.getUrlPatterns());
        return registration;
    }
}

In this class , Found an automatic assembly FilterRegistrationBean, The main function is to register a CommonFilter, And the default is /*, Means to intercept all requests , Let's check CommonFilter Source code logic of , It's very simple :

public class CommonFilter implements Filter {
    public static final String HTTP_METHOD_SPECIFY = "HTTP_METHOD_SPECIFY";
    public static final String WEB_CONTEXT_UNIFY = "WEB_CONTEXT_UNIFY";
    private static final String COLON = ":";
    private boolean httpMethodSpecify = false;
    private boolean webContextUnify = true;
    private static final String EMPTY_ORIGIN = "";

    public CommonFilter() {
    }

    public void init(FilterConfig filterConfig) {
        this.httpMethodSpecify = Boolean.parseBoolean(filterConfig.getInitParameter("HTTP_METHOD_SPECIFY"));
        if (filterConfig.getInitParameter("WEB_CONTEXT_UNIFY") != null) {
            this.webContextUnify = Boolean.parseBoolean(filterConfig.getInitParameter("WEB_CONTEXT_UNIFY"));
        }

    }

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest sRequest = (HttpServletRequest)request;
        Entry urlEntry = null;

        try {
            // Parse requested URL
            String target = FilterUtil.filterTarget(sRequest);
            //URL cleaning 
            UrlCleaner urlCleaner = WebCallbackManager.getUrlCleaner();
            if (urlCleaner != null) {
                target = urlCleaner.clean(target);
            }

            if (!StringUtil.isEmpty(target)) {
                String origin = this.parseOrigin(sRequest);
                String contextName = this.webContextUnify ? "sentinel_web_servlet_context" : target;
                ContextUtil.enter(contextName, origin);
                if (this.httpMethodSpecify) {
                    String pathWithHttpMethod = sRequest.getMethod().toUpperCase() + ":" + target;
                    // We talked about this in hot data flow restriction 
                    urlEntry = SphU.entry(pathWithHttpMethod, 1, EntryType.IN);
                } else {
                    urlEntry = SphU.entry(target, 1, EntryType.IN);
                }
            }

            chain.doFilter(request, response);
        } catch (BlockException var15) {
            HttpServletResponse sResponse = (HttpServletResponse)response;
            WebCallbackManager.getUrlBlockHandler().blocked(sRequest, sResponse, var15);
        } catch (ServletException | RuntimeException | IOException var16) {
            Tracer.traceEntry(var16, urlEntry);
            throw var16;
        } finally {
            if (urlEntry != null) {
                urlEntry.exit();
            }

            ContextUtil.exit();
        }

    }

    private String parseOrigin(HttpServletRequest request) {
        RequestOriginParser originParser = WebCallbackManager.getRequestOriginParser();
        String origin = "";
        if (originParser != null) {
            origin = originParser.parseOrigin(request);
            if (StringUtil.isEmpty(origin)) {
                return "";
            }
        }

        return origin;
    }

    public void destroy() {
    }
}

Is the logic simple , Actually, I did three things :

1、 Obtain requested URL

2、 obtain Urlcleaner, If non empty exists , Just explain URL The cleaning strategy is configured , call clean Methods to replace target

3、 Use SphU.entry For the current URL Add current limiting buried point

therefore , about Web Servlet Environmental Science , Only by Filter All requests are automatically set to Sentinel Resources for , So as to achieve the purpose of current limiting  

原网站

版权声明
本文为[codain]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/02/202202280508406524.html