最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

加速spring/springboot應(yīng)用啟動(dòng)速度詳解

 更新時(shí)間:2023年07月31日 10:07:30   作者:wen-pan  
這篇文章主要介紹了加速spring/springboot應(yīng)用啟動(dòng)速度詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì)對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

Gitee地址 :https://gitee.com/mr_wenpan/basis-enhance/tree/master

一、解決的痛點(diǎn)

在實(shí)際使用 Spring/Spring Boot 開(kāi)發(fā)中,一些 Bean 在初始化過(guò)程中,會(huì)執(zhí)行一些準(zhǔn)備操作,如:

  • 拉取遠(yuǎn)程配置
  • 初始化數(shù)據(jù)源
  • 加載數(shù)據(jù)到j(luò)vm本地緩存

在應(yīng)用啟動(dòng)期間,這些 Bean 會(huì)增加 Spring 上下文刷新時(shí)間,導(dǎo)致應(yīng)用啟動(dòng)耗時(shí)變長(zhǎng)。為了加速應(yīng)用啟動(dòng),enhance-boot-async-init模塊提供了通過(guò)配置的可選項(xiàng),將 Bean 的初始化方法(init-method)使用單獨(dú)線程異步執(zhí)行的能力,加快 Spring 上下文加載過(guò)程,提高應(yīng)用啟動(dòng)速度。僅需要將 @BasisAsyncInit注解標(biāo)注到需要異步執(zhí)行的初始化方法上即可實(shí)現(xiàn)應(yīng)用啟動(dòng)過(guò)程中異步初始化。

加粗樣式## 二、異步初始化組件說(shuō)明

  • 需要顯示的將@BasisAsyncInit注解標(biāo)注在某些需要在啟動(dòng)過(guò)程中異步初始化的方法上才能實(shí)現(xiàn)啟動(dòng)過(guò)程中異步執(zhí)行。自動(dòng)探測(cè)所有可異步初始化的功能待實(shí)現(xiàn)(因?yàn)橐M(jìn)行依賴關(guān)系分析,比如在執(zhí)行異步初始化某個(gè)類時(shí),該類依賴關(guān)系非常復(fù)雜,并且可能他所依賴的某些bean還為被spring 容器創(chuàng)建,那么此時(shí)就需要去創(chuàng)建依賴的bean,且分析依賴樹(shù)。這個(gè)后面實(shí)現(xiàn))
  • 異步初始化時(shí)需要滿足如下條件才能算是安全的穩(wěn)定的異步初始化
    • 所有異步初始化完成之前容器不能算是啟動(dòng)成功。所以在容器啟動(dòng)完成前需要檢查是否所有的異步初始化都執(zhí)行完畢了
    • 如果有某個(gè)異步初始化執(zhí)行失敗了,則不能讓容器完成啟動(dòng),而是要阻止容器啟動(dòng)(如果異步初始化失敗了,但此時(shí)容器啟動(dòng)完成了,比如:將restful接口對(duì)外暴露了,那么將會(huì)導(dǎo)致調(diào)用失敗)
    • 異步啟動(dòng)的線程池可根據(jù)項(xiàng)目的需要?jiǎng)討B(tài)配置
  • @BasisAsyncInit 注解可以使用在類上,也可以配合@Bean注解標(biāo)注在注入方法上,eg:
// 在注入HelloService處標(biāo)注@BasisAsyncInit注解(此時(shí)HelloService上可以不標(biāo)注)
@BasisAsyncInit
@Bean(initMethod = "init")
public HelloService helloService() {
  return new HelloService();
}
// 或者直接標(biāo)注在類上
@BasisAsyncInit
public class HelloService {
}

二、使用

1、yml配置文件中開(kāi)啟異步初始化

basis:
  enhance:
    async:
      init:
        # 開(kāi)啟異步初始化功能
        enable: true
        # 異步初始化線程池核心線程數(shù)量(不配置的話默認(rèn)是 2*cpu核數(shù) + 1)
        asyncInitBeanCoreSize: 10
        # 異步初始化線程池最大線程數(shù)量(不配置的話默認(rèn)是 2*cpu核數(shù) + 1)
        asyncInitBeanMaxSize: 20

2、創(chuàng)建異步初始化的bean

@Slf4j
// 炸裂標(biāo)注該bean是異步初始化的
@BasisAsyncInit
public class HelloService {
    /**
     * init方法
     */
    public void init() throws InterruptedException {
        log.info("i am HelloService.init method, start........");
      // 睡一會(huì)兒,這里模擬初始化方法非常耗時(shí),初始化方法執(zhí)行完畢前容器不允許正常啟動(dòng)成功
        TimeUnit.SECONDS.sleep(10);
      // 這里模擬異步初始化失敗容器不允許正常啟動(dòng)
//        final int i = 1 / 0;
        log.info("i am HelloService.init method, end........");
    }
    public String sayHello(String name) {
        log.info("hello {}", name);
        return "hello-" + name;
    }
}

3、注入異步初始化的bean并指定初始化方法

@Bean(initMethod = "init")
public HelloService helloService() {
    return new HelloService();
}

4、啟動(dòng)應(yīng)用觀察日志

①、正常啟動(dòng)日志

  • 可以看到HelloService的init方法是被異步線程pool-1-thread-1執(zhí)行的,而不是main線程
  • 可以看到main線程一直是等到異步線程pool-1-thread-1執(zhí)行完畢后再讓容器啟動(dòng)成功的

2023-07-30 16:09:29.238  INFO 24094 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 711 ms
2023-07-30 16:09:29.307  INFO 24094 --- [           main] o.b.e.a.init.executor.AsyncTaskExecutor  : create async-init-bean thread pool, corePoolSize: 10, maxPoolSize: 20.
2023-07-30 16:09:29.308  INFO 24094 --- [pool-1-thread-1] o.e.async.init.service.HelloService      : i am HelloService.init method, start........
2023-07-30 16:09:29.541  INFO 24094 --- [           main] io.undertow                              : starting server: Undertow - 2.2.8.Final
2023-07-30 16:09:29.545  INFO 24094 --- [           main] org.xnio                                 : XNIO version 3.8.0.Final
2023-07-30 16:09:29.549  INFO 24094 --- [           main] org.xnio.nio                             : XNIO NIO Implementation Version 3.8.0.Final
2023-07-30 16:09:29.578  INFO 24094 --- [           main] org.jboss.threads                        : JBoss Threads version 3.1.0.Final
2023-07-30 16:09:29.623  INFO 24094 --- [           main] o.s.b.w.e.undertow.UndertowWebServer     : Undertow started on port(s) 8080 (http)
2023-07-30 16:09:39.310  INFO 24094 --- [pool-1-thread-1] o.e.async.init.service.HelloService      : i am HelloService.init method, end........
2023-07-30 16:09:39.311  INFO 24094 --- [pool-1-thread-1] o.b.e.a.i.p.AsyncProxyBeanPostProcessor  : org.enhance.async.init.service.HelloService(helloService) init method execute 10003 ms.
2023-07-30 16:09:39.321  INFO 24094 --- [           main] o.e.async.init.DemoAsyncInitApplication  : Started DemoAsyncInitApplication in 11.168 seconds (JVM running for 11.853)

②、初始化方法執(zhí)行異常日志

  • 可以看到初始化方法異步執(zhí)行失敗,容器不會(huì)啟動(dòng)成功,不會(huì)將服務(wù)暴露出去

2023-07-30 16:12:30.000  INFO 24127 --- [           main] o.e.async.init.DemoAsyncInitApplication  : Starting DemoAsyncInitApplication using Java 1.8.0_281 on wenpf-MacBook-Pro.local with PID 24127 (/Users/wenpanfeng/MyFolder/DevelopWorkspace/IdeaWorkSpace/StudyProjects/basis-enhance/enhance-demo-parent/demo-enhance-async-init/target/classes started by wenpanfeng in /Users/wenpanfeng/MyFolder/DevelopWorkspace/IdeaWorkSpace/StudyProjects/basis-enhance)
2023-07-30 16:12:30.002  INFO 24127 --- [           main] o.e.async.init.DemoAsyncInitApplication  : No active profile set, falling back to default profiles: default
2023-07-30 16:12:30.763  WARN 24127 --- [           main] io.undertow.websockets.jsr               : UT026010: Buffer pool was not set on WebSocketDeploymentInfo, the default pool will be used
2023-07-30 16:12:30.779  INFO 24127 --- [           main] io.undertow.servlet                      : Initializing Spring embedded WebApplicationContext
2023-07-30 16:12:30.779  INFO 24127 --- [           main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 731 ms
2023-07-30 16:12:30.860  INFO 24127 --- [           main] o.b.e.a.init.executor.AsyncTaskExecutor  : create async-init-bean thread pool, corePoolSize: 10, maxPoolSize: 20.
2023-07-30 16:12:30.861  INFO 24127 --- [pool-1-thread-1] o.e.async.init.service.HelloService      : i am HelloService.init method, start........
2023-07-30 16:12:31.109  INFO 24127 --- [           main] io.undertow                              : starting server: Undertow - 2.2.8.Final
2023-07-30 16:12:31.114  INFO 24127 --- [           main] org.xnio                                 : XNIO version 3.8.0.Final
2023-07-30 16:12:31.119  INFO 24127 --- [           main] org.xnio.nio                             : XNIO NIO Implementation Version 3.8.0.Final
2023-07-30 16:12:31.151  INFO 24127 --- [           main] org.jboss.threads                        : JBoss Threads version 3.1.0.Final
2023-07-30 16:12:31.197  INFO 24127 --- [           main] o.s.b.w.e.undertow.UndertowWebServer     : Undertow started on port(s) 8080 (http)
2023-07-30 16:12:40.867  INFO 24127 --- [           main] io.undertow                              : stopping server: Undertow - 2.2.8.Final
2023-07-30 16:12:40.879  INFO 24127 --- [           main] ConditionEvaluationReportLoggingListener : 

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2023-07-30 16:12:40.899 ERROR 24127 --- [           main] o.s.boot.SpringApplication               : Application run failed

org.basis.enhance.async.init.exception.BasisAsyncInitException: 異步初始化失敗.
    at org.basis.enhance.async.init.executor.AsyncTaskExecutor.ensureAsyncTasksFinish(AsyncTaskExecutor.java:94) ~[classes/:na]
    at org.basis.enhance.async.init.listener.AsyncTaskExecutionListener.onApplicationEvent(AsyncTaskExecutionListener.java:28) ~[classes/:na]
    at org.basis.enhance.async.init.listener.AsyncTaskExecutionListener.onApplicationEvent(AsyncTaskExecutionListener.java:20) ~[classes/:na]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:176) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:169) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:143) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:421) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:378) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:938) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:586) ~[spring-context-5.3.8.jar:5.3.8]
    at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144) ~[spring-boot-2.4.8.jar:2.4.8]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:771) [spring-boot-2.4.8.jar:2.4.8]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:763) [spring-boot-2.4.8.jar:2.4.8]
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:438) [spring-boot-2.4.8.jar:2.4.8]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:339) [spring-boot-2.4.8.jar:2.4.8]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1329) [spring-boot-2.4.8.jar:2.4.8]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1318) [spring-boot-2.4.8.jar:2.4.8]
    at org.enhance.async.init.DemoAsyncInitApplication.main(DemoAsyncInitApplication.java:15) [classes/:na]
Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at java.util.concurrent.FutureTask.report(FutureTask.java:122) ~[na:1.8.0_281]
    at java.util.concurrent.FutureTask.get(FutureTask.java:192) ~[na:1.8.0_281]
    at org.basis.enhance.async.init.executor.AsyncTaskExecutor.ensureAsyncTasksFinish(AsyncTaskExecutor.java:92) ~[classes/:na]
    ... 17 common frames omitted
Caused by: java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at org.basis.enhance.async.init.processor.AsyncProxyBeanPostProcessor$AsyncInitializeBeanMethodInvoker.lambda$invoke$0(AsyncProxyBeanPostProcessor.java:119) ~[classes/:na]
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) ~[na:1.8.0_281]
    at java.util.concurrent.FutureTask.run(FutureTask.java:266) ~[na:1.8.0_281]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) ~[na:1.8.0_281]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) ~[na:1.8.0_281]
    at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_281]
Caused by: java.lang.reflect.InvocationTargetException: null
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_281]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_281]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_281]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_281]
    at org.basis.enhance.async.init.processor.AsyncProxyBeanPostProcessor$AsyncInitializeBeanMethodInvoker.lambda$invoke$0(AsyncProxyBeanPostProcessor.java:115) ~[classes/:na]
    ... 5 common frames omitted
Caused by: java.lang.ArithmeticException: / by zero
    at org.enhance.async.init.service.HelloService.init(HelloService.java:25) ~[classes/:na]
    ... 10 common frames omitted

三、原理/源碼淺析

  • 使用實(shí)現(xiàn)了BeanFactoryPostProcessor接口的 AsyncInitBeanFactoryPostProcessor 類,在bean定義信息創(chuàng)建完成后會(huì)調(diào)postProcessBeanFactory方法的特性,在該方法中掃描容器中每個(gè)bean定義信息
  • 在解析bean定義信息時(shí),如果發(fā)現(xiàn)某個(gè)bean標(biāo)注了@BasisAsyncInit注解,則查找該bean的init方法,并以beanId為key,初始化方法名稱為value,將初始化方法保存到map中(ASYNC_BEAN_INFO_CACHE),后續(xù)統(tǒng)一處理
    • 源碼 @see org.basis.enhance.async.init.processor.AsyncInitBeanFactoryPostProcessor#postProcessBeanFactory
  • 再借助實(shí)現(xiàn)了BeanPostProcessor接口的AsyncProxyBeanPostProcessor類,攔截spring中每個(gè)bean的創(chuàng)建過(guò)程(bean初始化方法執(zhí)行前,see: postProcessBeforeInitialization),通過(guò)beanName名稱去ASYNC_BEAN_INFO_CACHE緩存中查找該bean是否有需要異步初始化的方法。
    • 如果沒(méi)有找到,則說(shuō)明該bean沒(méi)有需要異步初始化的方法,直接返回這個(gè)bean即可
    • 如果找到了,則在這里攔截該bean的創(chuàng)建(spring中常用的代理對(duì)象創(chuàng)建攔截點(diǎn)),為該bean創(chuàng)建一個(gè)代理對(duì)象(代理對(duì)象的核心邏輯AsyncInitializeBeanMethodInvoker),攔截該bean的每一個(gè)方法并返回。
    • 源碼 @see org.basis.enhance.async.init.processor.AsyncProxyBeanPostProcessor#postProcessBeforeInitialization
  • 當(dāng)容器啟動(dòng)過(guò)程中執(zhí)行bean的init方法時(shí),此時(shí)如果是需要異步執(zhí)行的初始化方法,則會(huì)進(jìn)入到我們上一步創(chuàng)建的代理對(duì)象的invoke方法內(nèi)。
    • 在該方法中將異步初始化方法提交到線程池中執(zhí)行,提交完成后會(huì)返回一個(gè) Future
    • 并且利用 Future 特性,將submit后返回的Future放到一個(gè)list (FUTURES)中統(tǒng)一管理
    • @see org.basis.enhance.async.init.processor.AsyncProxyBeanPostProcessor.AsyncInitializeBeanMethodInvoker#invoke
    • 那么容器啟動(dòng)過(guò)程中如何感知異步初始化方法執(zhí)行的結(jié)果呢?比如:是否都執(zhí)行完畢了?是否有異常?往下看
  • 利用實(shí)現(xiàn)了ApplicationListener 接口的AsyncTaskExecutionListener類,監(jiān)聽(tīng)容器啟動(dòng)過(guò)程中發(fā)布的的刷新事件ContextRefreshedEvent,在監(jiān)聽(tīng)到容器啟動(dòng)過(guò)程中發(fā)布的 ContextRefreshedEvent 事件后,檢查提交的每一個(gè)異步任務(wù)的執(zhí)行情況(利用上一步submit后返回的Future)
    • 如果有任意一個(gè)異步初始化方法執(zhí)行異常,則拋出異常,終止容器繼續(xù)啟動(dòng)
    • 如果所有的異步初始化方法都執(zhí)行完畢,則容器繼續(xù)啟動(dòng)
    • @see org.basis.enhance.async.init.listener.AsyncTaskExecutionListener#onApplicationEvent

到此這篇關(guān)于如何加速spring/springboot應(yīng)用啟動(dòng)速度的文章就介紹到這了,更多相關(guān)springboot啟動(dòng)速度內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Centos中yum方式安裝java的實(shí)現(xiàn)示例

    Centos中yum方式安裝java的實(shí)現(xiàn)示例

    這篇文章主要介紹了Centos中yum方式安裝java的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • JavaWeb HttpServletResponse對(duì)象及常用方法

    JavaWeb HttpServletResponse對(duì)象及常用方法

    這篇文章主要介紹了JavaWeb-HttpServletResponse對(duì)象,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-03-03
  • java screen的配置詳解及注意事項(xiàng)

    java screen的配置詳解及注意事項(xiàng)

    這篇文章主要介紹了java screen的配置詳解及注意事項(xiàng)的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • 詳解java中this.getClass()和super.getClass()的實(shí)例

    詳解java中this.getClass()和super.getClass()的實(shí)例

    這篇文章主要介紹了詳解java中this.getClass()和super.getClass()的實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-08-08
  • java 實(shí)現(xiàn)圖片像素質(zhì)量壓縮與圖片長(zhǎng)寬縮放

    java 實(shí)現(xiàn)圖片像素質(zhì)量壓縮與圖片長(zhǎng)寬縮放

    這篇文章主要介紹了java 實(shí)現(xiàn)圖片像素質(zhì)量壓縮與圖片長(zhǎng)寬縮放,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • 淺析JPA分類表的操作函數(shù)

    淺析JPA分類表的操作函數(shù)

    這篇文章主要介紹了JPA分類表的操作函數(shù),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)吧
    2023-02-02
  • java 如何從字符串里面提取時(shí)間

    java 如何從字符串里面提取時(shí)間

    這篇文章主要介紹了java實(shí)現(xiàn)從字符串里面提取時(shí)間的方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • SpringMVC攔截器實(shí)現(xiàn)登錄認(rèn)證

    SpringMVC攔截器實(shí)現(xiàn)登錄認(rèn)證

    這篇文章主要介紹了SpringMVC攔截器實(shí)現(xiàn)登錄認(rèn)證的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-11-11
  • SpringBoot中的Condition包下常用條件依賴注解案例介紹

    SpringBoot中的Condition包下常用條件依賴注解案例介紹

    這篇文章主要介紹了SpringBoot中的Condition包下常用條件依賴注解案例,文章基于Java的相關(guān)資料展開(kāi)主題詳細(xì)內(nèi)容,需要的小伙伴可以參考一下
    2022-04-04
  • 深入理解java動(dòng)態(tài)代理機(jī)制

    深入理解java動(dòng)態(tài)代理機(jī)制

    本篇文章主要介紹了深入理解java動(dòng)態(tài)代理機(jī)制,詳細(xì)的介紹動(dòng)態(tài)代理有哪些應(yīng)用場(chǎng)景,什么是動(dòng)態(tài)代理,怎樣使用,它的局限性在什么地方?有興趣的可以了解一下。
    2017-02-02

最新評(píng)論

喜德县| 安仁县| 昆山市| 离岛区| 论坛| 华坪县| 拉萨市| 乌兰县| 阿瓦提县| 钟山县| 博爱县| 耒阳市| 开封市| 和龙市| 大石桥市| 青川县| 嘉兴市| 文成县| 彰化县| 耿马| 广安市| 咸宁市| 桃园县| 天门市| 旌德县| 客服| 晋宁县| 土默特右旗| 乐陵市| 中宁县| 山东省| 枞阳县| 辽阳县| 永城市| 石屏县| 五寨县| 眉山市| 卓尼县| 临颍县| 兴仁县| 泗阳县|