成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

使用servlet3.0異步特性改造spring-cloud-zuul

HmyBmny / 796人閱讀

摘要:不過(guò)在出來(lái)之后支持異步了,可以把業(yè)務(wù)操作放到獨(dú)立的線程池里面去,這樣可以盡快釋放線程,本身也支持異步了,本篇文章將帶你如何使用的異步特性來(lái)改造優(yōu)化其性能。

? 我們知道spring-cloud-zuul是依賴springMVC來(lái)注冊(cè)路由的,而springMVC又是在建立在servlet之上的(這里微服務(wù)專家楊波老師寫(xiě)過(guò)一篇文章講述其網(wǎng)絡(luò)模型,可以參考看看),在servlet3.0之前使用的是thread per connection方式處理請(qǐng)求,就是每一個(gè)請(qǐng)求需要servlet容器為其分配一個(gè)線程來(lái)處理,直到響應(yīng)完用戶請(qǐng)求,才被釋放回容器線程池,如果后端業(yè)務(wù)處理比較耗時(shí),那么這個(gè)線程將會(huì)被一直阻塞,不能干其他事情,如果耗時(shí)請(qǐng)求比較多時(shí),servlet容器線程將被耗盡,也就無(wú)法處理新的請(qǐng)求了,所以Netflix還專門(mén)開(kāi)發(fā)了一個(gè)熔斷的組件Hystrix 來(lái)保護(hù)這樣的服務(wù),防止其因后端的一些慢服務(wù)耗盡資源,造成服務(wù)不可用。不過(guò)在servlet3.0出來(lái)之后支持異步servlet了,可以把業(yè)務(wù)操作放到獨(dú)立的線程池里面去,這樣可以盡快釋放servlet線程,springMVC本身也支持異步servlet了,本篇文章將帶你如何使用servlet3.0的異步特性來(lái)改造spring-cloud-zuul優(yōu)化其性能。

? 我們先來(lái)創(chuàng)建一個(gè)zuul的maven項(xiàng)目,就叫async-zuul吧,具體代碼我放在github上了。項(xiàng)目依賴于consul做注冊(cè)中心,啟動(dòng)時(shí)先要在本地啟動(dòng)consul,為了能看到效果我們先來(lái)新建一個(gè)zuul的filter類:

@Component
public class TestFilter extends ZuulFilter {
    //忽略無(wú)關(guān)代碼,具體看github上的源碼
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        System.out.println("==============線程名稱:" +                                         Thread.currentThread().getName() 
                + ",訪問(wèn)url:" + request.getRequestURI() + "================");
        return null;
    }
}

主要就是打印下線程的名稱,這個(gè)filter是zuul的前置過(guò)濾器,我們主要就是看下在zuul在執(zhí)行路由時(shí)是由什么線程執(zhí)行的。好了我們來(lái)啟動(dòng)下main方法,不過(guò)我們還需要一個(gè)后端服務(wù),很簡(jiǎn)單,創(chuàng)建一個(gè)springcloud項(xiàng)目名叫book即可,并提供一個(gè)url:/book/borrow,啟動(dòng)后把服務(wù)注冊(cè)到consul上,成功后我們通過(guò)zuul的代理來(lái)訪問(wèn)下book服務(wù):

http://localhost:8080/book/book/borrow

輸出:

==========線程名稱:http-nio-8080-exec-10,訪問(wèn)url:/book/book/borrow=======

很清楚的看到執(zhí)行filter的線程是servlet容器線程,等下我們改造成異步后再做一下對(duì)比。

? 還記得在文章spring-cloud-zuul原理解析(一)中我們分析到,spring-cloud-zuul的路由映射使用到springMVC的兩大組件ZuulHandlerMappingZuulController ,目前肯定是無(wú)法支持異步servlet的。那么這兩個(gè)類在哪里被加載的呢?答案就是ZuulServerAutoConfiguration,此類是spring-cloud-zuul自動(dòng)配置類,源碼如下:

@Configuration
@ConditionalOnBean(annotation=EnableZuulProxy.class)
@EnableConfigurationProperties({ ZuulProperties.class })
@ConditionalOnClass(ZuulServlet.class)
@Import(ServerPropertiesAutoConfiguration.class)
public class ZuulServerAutoConfiguration {
    //無(wú)關(guān)代碼省略..........
    @Bean
    public ZuulController zuulController() {
        return new ZuulController();
    }
    @Bean
    public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes) {
        ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController());
        mapping.setErrorController(this.errorController);
        return mapping;
    }
    //無(wú)關(guān)代碼省略..........
}

可以看到這兩個(gè)類在spring-cloud-zuul中并沒(méi)有為我們提供擴(kuò)展,沒(méi)法替換它們來(lái)實(shí)現(xiàn)servlet的異步邏輯,那該怎么辦呢?spring-cloud-zuul還有一個(gè)自動(dòng)配置配ZuulProxyAutoConfiguration繼承自ZuulServerAutoConfiguration,我們把這兩個(gè)配置類全部替換掉,換成我們自己的不就可以了么?是的,不過(guò)首先我們得先排除加載這兩個(gè)自動(dòng)配置類,springboot為我們提供這樣的設(shè)置:

@EnableZuulProxy
//排除ZuulProxyAutoConfiguration配置類
@SpringBootApplication(exclude=ZuulProxyAutoConfiguration.class)
public class Startup {
    public static void main(String[] args) {
        SpringApplication.run(Startup.class, args);
    }
}

之后,我們創(chuàng)建兩個(gè)自己的配置配,完全拷貝ZuulServerAutoConfigurationZuulProxyAutoConfiguration這兩個(gè)類,不過(guò)光這兩個(gè)類還是不行,這兩個(gè)類使用到了類RibbonCommandFactoryConfiguration,里面的內(nèi)部類是protected的,我們沒(méi)法使用,也得自己創(chuàng)建,也是拷貝自RibbonCommandFactoryConfiguration,然后我們還需修改ZuulController的邏輯改成異步方式,所以再新建一個(gè)類繼承ZuulController,這樣我們就新建了自己的三個(gè)配置類和一個(gè)自己的ZuulController`類,如下:

public class MyZuulController extends ZuulController{
    private final AsyncTaskExecutor asyncTaskExecutor;
    public MyZuulController(AsyncTaskExecutor asyncTaskExecutor) {
        super();
        this.asyncTaskExecutor = asyncTaskExecutor;
    }
    @Override
    public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //真正的異步化邏輯
        final AsyncContext asyncCtx = request.startAsync();
        this.asyncTaskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                try {
        MyZuulController.this.handleRequestInternal((HttpServletRequest)asyncCtx.getRequest(),
                            (HttpServletResponse)asyncCtx.getResponse());
                }catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    asyncCtx.complete();
                    RequestContext.getCurrentContext().unset();
                }
            }
        });
        return null;
    }
}

@Configuration
@ConditionalOnBean(annotation=EnableZuulProxy.class)
@EnableConfigurationProperties({ ZuulProperties.class })
@ConditionalOnClass(ZuulServlet.class)
@Import(ServerPropertiesAutoConfiguration.class)
public class MyZuulServerAutoConfiguration {
    //省略代碼,完全拷貝自ZuulServerAutoConfiguration
    /**
     * 自定義線程池
     * @return
     */
    @Bean
    public AsyncTaskExecutor zuulAsyncPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setThreadNamePrefix("zuul-async-");
        executor.setCorePoolSize(5);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(50);
        return executor;
    }
    //這里換成我們自己的MyZuulController類,并且傳入一個(gè)我們自定義的線程池
    @Bean
    public ZuulController zuulController(AsyncTaskExecutor asyncTaskExecutor) {
        return new MyZuulController(asyncTaskExecutor);
    }
    @Bean
    public ZuulHandlerMapping zuulHandlerMapping(RouteLocator routes,AsyncTaskExecutor asyncTaskExecutor) {
        ZuulHandlerMapping mapping = new ZuulHandlerMapping(routes, zuulController(asyncTaskExecutor));
        mapping.setErrorController(this.errorController);
        return mapping;
    }
}

@Configuration
@Import({ MyRibbonCommandFactoryConfiguration.RestClientRibbonConfiguration.class,
    MyRibbonCommandFactoryConfiguration.OkHttpRibbonConfiguration.class,
    MyRibbonCommandFactoryConfiguration.HttpClientRibbonConfiguration.class })
@ConditionalOnBean(annotation=EnableZuulProxy.class)
public class MyZuulProxyAutoConfiguration extends MyZuulServerAutoConfiguration {
    //省略代碼,完全拷貝自ZuulProxyAutoConfiguration
}

public class MyRibbonCommandFactoryConfiguration {
    //省略代碼,完全拷貝自RibbonCommandFactoryConfiguration
}

這里我們稍作了一點(diǎn)修改

@ConditionalOnBean(ZuulProxyMarkerConfiguration.Marker.class)
//替換成:
@ConditionalOnBean(annotation=EnableZuulProxy.class)

這樣做的目的主要是配合注解@EnableZuulProxy使用,只有開(kāi)啟了此注解才加載配置類。我們還替換ZuulController成我們自定義的MyZuulController了,這里是異步化的主要邏輯,其實(shí)也非常簡(jiǎn)單,就是使用了serv3.0為我們提供的api來(lái)開(kāi)啟異步化。萬(wàn)事已經(jīng)具備啦,我們?cè)俅螁?dòng)zuul,訪問(wèn)上面的url,輸出:

==========線程名稱:zuul-async-1,訪問(wèn)url:/book/book/borrow==========

哈哈,執(zhí)行filter的線程變成我們自定義的線程名稱了,達(dá)到了我們的需求,servlet已經(jīng)變成異步的了。

這是我對(duì)spring-cloud-zuul實(shí)現(xiàn)異步servlet的想法,記錄下來(lái),可能不是最好的實(shí)現(xiàn)方式,如果您有更好的方法歡迎留言給我一起探討下!

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/77109.html

相關(guān)文章

  • dubbo源碼解析(四十三)2.7新特性

    摘要:大揭秘目標(biāo)了解的新特性,以及版本升級(jí)的引導(dǎo)。四元數(shù)據(jù)改造我們知道以前的版本只有注冊(cè)中心,注冊(cè)中心的有數(shù)十個(gè)的鍵值對(duì),包含了一個(gè)服務(wù)所有的元數(shù)據(jù)。 DUBBO——2.7大揭秘 目標(biāo):了解2.7的新特性,以及版本升級(jí)的引導(dǎo)。 前言 我們知道Dubbo在2011年開(kāi)源,停止更新了一段時(shí)間。在2017 年 9 月 7 日,Dubbo 悄悄的在 GitHub 發(fā)布了 2.5.4 版本。隨后,版本...

    qqlcbb 評(píng)論0 收藏0
  • Spring之旅 - 3.0、3.1、4.0導(dǎo)引

    摘要:之旅簡(jiǎn)化開(kāi)發(fā)的使命簡(jiǎn)化開(kāi)發(fā)為了降低開(kāi)發(fā)的復(fù)雜性,采取如下關(guān)鍵策略基于的輕量級(jí)和最小侵入性編程通過(guò)依賴注入和面向接口實(shí)現(xiàn)松耦合基于切面和慣例進(jìn)行聲明式編程通過(guò)切面和模版減少樣式代碼依賴注入耦合性具有兩面性一方面,緊密耦合的代碼難以測(cè)試難以復(fù) Spring之旅 簡(jiǎn)化Java開(kāi)發(fā) Spring的使命:簡(jiǎn)化Java開(kāi)發(fā) 為了降低Java開(kāi)發(fā)的復(fù)雜性,采取如下關(guān)鍵策略:基于POJO的輕量級(jí)和最...

    leon 評(píng)論0 收藏0
  • spring-cloud-zuul原理解析(一)

    摘要:是開(kāi)源的微服務(wù)網(wǎng)關(guān),它可以和,等組件配合使用,網(wǎng)上也有很多如何使用的文章,我們也在生產(chǎn)環(huán)境使用了,所以讀了下的源碼,下面把它分享出來(lái),與大家探討下核心原理。 Zuul是Netflix開(kāi)源的微服務(wù)網(wǎng)關(guān),它可以和Eureka,consul,Ribbon,Hystrix等組件配合使用,網(wǎng)上也有很多如何使用zuul的文章,我們也在生產(chǎn)環(huán)境使用了,所以讀了下zuul的源碼,下面把它分享出來(lái),與大...

    qingshanli1988 評(píng)論0 收藏0
  • 一起學(xué)習(xí)使用Spring Cloud Netflix之Zuul

    摘要:前言在體系中扮演著統(tǒng)一網(wǎng)關(guān)的角色,負(fù)責(zé)與外部交互。與結(jié)合使用,可以根據(jù)服務(wù)名來(lái)訪問(wèn)后端的服務(wù),對(duì)于而言,也是一個(gè)。這段代碼表示,如果請(qǐng)求中沒(méi)有信息,就會(huì)報(bào)錯(cuò)。 前言 Zuul在Spring Cloud 體系中扮演著統(tǒng)一網(wǎng)關(guān)的角色,負(fù)責(zé)與外部交互。用戶可以通過(guò)不同的URL特征來(lái)訪問(wèn)不同的后端服務(wù),類似于Nginx代理的效果。Zuul與Eureka結(jié)合使用,可以根據(jù)服務(wù)名來(lái)訪問(wèn)后端的服務(wù),...

    FullStackDeveloper 評(píng)論0 收藏0
  • comet實(shí)現(xiàn)(原理)

    摘要:最近對(duì)服務(wù)器推送技術(shù)比較感興趣,在網(wǎng)上也看了好些文章,由于每個(gè)人理解的不同,實(shí)現(xiàn)細(xì)節(jié)或者語(yǔ)言表達(dá)方式不同,本人被各種名詞或者技術(shù)實(shí)現(xiàn)搞的頭大,于是自己準(zhǔn)備整理下。定時(shí)器就可以實(shí)現(xiàn),每次請(qǐng)求如果服務(wù)器端有更新數(shù)據(jù)則響應(yīng)到客戶端。 最近對(duì)服務(wù)器推送技術(shù)比較感興趣,在網(wǎng)上也看了好些文章,由于每個(gè)人理解的不同,實(shí)現(xiàn)細(xì)節(jié)或者語(yǔ)言表達(dá)方式不同,本人被各種名詞或者技術(shù)實(shí)現(xiàn)搞的頭大,于是自己準(zhǔn)備整理下...

    rozbo 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<