1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        面試官:Spring Boot 的啟動(dòng)原理是什么?

        共 13446字,需瀏覽 27分鐘

         ·

        2024-05-22 10:30

        來(lái)源:juejin.cn/post/7308610896803659812

        ?? 歡迎加入小哈的星球 ,你將獲得: 專屬的項(xiàng)目實(shí)戰(zhàn) / Java 學(xué)習(xí)路線 / 一對(duì)一提問(wèn) / 學(xué)習(xí)打卡 /  每月贈(zèng)書


        新項(xiàng)目:仿小紅書(微服務(wù)架構(gòu))正在更新中... , 全棧前后端分離博客項(xiàng)目 2.0 版本完結(jié)啦, 演示鏈接http://116.62.199.48/ 。全程手摸手,后端 + 前端全棧開(kāi)發(fā),從 0 到 1 講解每個(gè)功能點(diǎn)開(kāi)發(fā)步驟,1v1 答疑,直到項(xiàng)目上線。目前已更新了261小節(jié),累計(jì)41w+字,講解圖:1806張,還在持續(xù)爆肝中.. 后續(xù)還會(huì)上新更多項(xiàng)目,目標(biāo)是將Java領(lǐng)域典型的項(xiàng)目都整一波,如秒殺系統(tǒng), 在線商城, IM即時(shí)通訊,Spring Cloud Alibaba 等等,戳我加入學(xué)習(xí),已有1400+小伙伴加入(早鳥價(jià)超低)


        雖然Java程序員大部分工作都是CRUD,但是工作中常用的中間件必須和Spring集成,如果不知道Spring的原理,很難理解這些中間件和框架的原理。

        一張長(zhǎng)圖透徹解釋 Spring啟動(dòng)順序

        圖片

        測(cè)試對(duì)Spring啟動(dòng)原理的理解程度

        我舉個(gè)例子,測(cè)試一下,你對(duì)Spring啟動(dòng)原理的理解程度。

        • Rpc框架和Spring的集成問(wèn)題。Rpc框架何時(shí)注冊(cè)暴露服務(wù),在哪個(gè)Spring擴(kuò)展點(diǎn)注冊(cè)呢?init-method 中行不行?
        • MQ 消費(fèi)組和Spring的集成問(wèn)題。MQ消費(fèi)者何時(shí)開(kāi)始消費(fèi),在哪個(gè)Spring擴(kuò)展點(diǎn)”注冊(cè)“自己?init-method 中行不行?
        • SpringBoot 集成Tomcat問(wèn)題。如果出現(xiàn)已開(kāi)啟Http流量,Spring還未啟動(dòng)完成,怎么辦?Tomcat何時(shí)開(kāi)啟端口,對(duì)外服務(wù)?

        SpringBoot項(xiàng)目常見(jiàn)的流量入口無(wú)外乎 Rpc、Http、MQ 三種方式。一名合格的架構(gòu)師必須精通服務(wù)的入口流量何時(shí)開(kāi)啟,如何正確開(kāi)啟?最近我遇到的兩次線上故障都和Spring啟動(dòng)過(guò)程相關(guān)。

        故障的具體表現(xiàn)是:Kafka消費(fèi)組已經(jīng)開(kāi)始消費(fèi),已開(kāi)啟流量,然而Spring 還未啟動(dòng)完成。因?yàn)闃I(yè)務(wù)代碼中使用的Spring Event事件訂閱組件還未啟動(dòng)(訂閱者還未注冊(cè)到Spring),所以處理異常,出了線上故障。根本原因是————項(xiàng)目在錯(cuò)誤的時(shí)機(jī)開(kāi)啟 MQ 流量,然而Spring還未啟動(dòng)完成,導(dǎo)致出現(xiàn)故障。

        正確的做法是:項(xiàng)目在Spring啟動(dòng)完成后開(kāi)啟入口流量,然而我司的Kafka消費(fèi)組 在Spring init-method bean 實(shí)例化階段就開(kāi)啟了流量,導(dǎo)致故障發(fā)生。出現(xiàn)這樣的問(wèn)題,說(shuō)明項(xiàng)目初期的程序員沒(méi)有深入理解Spring的啟動(dòng)原理。

        接下來(lái),我再次拋出 11 個(gè)問(wèn)題,說(shuō)明這個(gè)問(wèn)題————深入理解Spring啟動(dòng)原理的重要性。

        1. Spring還未完全啟動(dòng),在 PostConstruct 中調(diào)用 getBeanByAnnotation 能否獲得準(zhǔn)確的結(jié)果?
        2. 項(xiàng)目應(yīng)該如何監(jiān)聽(tīng) Spring 的啟動(dòng)就緒事件?
        3. 項(xiàng)目如何監(jiān)聽(tīng)Spring 刷新事件?
        4. Spring就緒事件和刷新事件的執(zhí)行順序和區(qū)別?
        5. Http 流量入口何時(shí)啟動(dòng)完成?
        6. 項(xiàng)目中在 init-method 方法中注冊(cè) Rpc 是否合理?什么是合理的時(shí)機(jī)?
        7. 項(xiàng)目中在 init-method 方法中注冊(cè) MQ 消費(fèi)組是否合理?什么是合理的時(shí)機(jī)?
        8. PostConstruct 中方法依賴ApplicationContextAware拿到 ApplicationContext,兩者的順序誰(shuí)先誰(shuí)后?是否會(huì)出現(xiàn)空指針!
        9. init-methodPostConstruct、afterPropertiesSet 三個(gè)方法的執(zhí)行順序?
        10. 有兩個(gè) Bean聲明了初始化方法。A使用 PostConstruct注解聲明,B使用 init-method 聲明。Spring一定先執(zhí)行 A 的PostConstruct 方法嗎?
        11. Spring 何時(shí)裝配Autowire屬性,PostConstruct 方法中引用 Autowired 字段什么場(chǎng)景會(huì)空指針?

        精通Spring 啟動(dòng)原理,以上問(wèn)題則迎刃而解。接下來(lái),大家一起學(xué)習(xí)Spring的啟動(dòng)原理,看看Spring的擴(kuò)展點(diǎn)分別在何時(shí)執(zhí)行。

        一起數(shù)數(shù) Spring啟動(dòng)過(guò)程的擴(kuò)展點(diǎn)有幾個(gè)?

        Spring的擴(kuò)展點(diǎn)極多,這里為了講清楚啟動(dòng)原理,所以只列舉和啟動(dòng)過(guò)程有關(guān)的擴(kuò)展點(diǎn)。

        1. BeanFactoryAware 可在Bean 中獲取 BeanFactory 實(shí)例
        2. ApplicationContextAware 可在Bean 中獲取 ApplicationContext 實(shí)例
        3. BeanNameAware 可以在Bean中得到它在IOC容器中的Bean的實(shí)例的名字。
        4. ApplicationListener 可監(jiān)聽(tīng) ContextRefreshedEvent等。
        5. CommandLineRunner 整個(gè)項(xiàng)目啟動(dòng)完畢后,自動(dòng)執(zhí)行
        6. SmartLifecycle#start 在Spring Bean實(shí)例化完成后,執(zhí)行start 方法。
        7. 使用@PostConstruct注解,用于Bean實(shí)例初始化
        8. 實(shí)現(xiàn)InitializingBean接口,用于Bean實(shí)例初始化
        9. xml 中聲明 init-method 方法,用于Bean實(shí)例初始化
        10. Configuration 配置類 通過(guò)@Bean注解 注冊(cè)Bean到Spring
        11. BeanPostProcessor 在Bean的初始化前后,植入擴(kuò)展點(diǎn)!
        12. BeanFactoryPostProcessorBeanFactory創(chuàng)建后植入 擴(kuò)展點(diǎn)!

        通過(guò)打印日志學(xué)習(xí)Spring的執(zhí)行順序

        首先我們先通過(guò) 代碼實(shí)驗(yàn),驗(yàn)證一下以上擴(kuò)展點(diǎn)的執(zhí)行順序。

        1.聲明 TestSpringOrder 分別繼承以下接口,并且在接口方法實(shí)現(xiàn)中,日志打印該接口的名稱。

        public class TestSpringOrder implements
              ApplicationContextAware,
              BeanFactoryAware, 
              InitializingBean, 
              SmartLifecycle, 
              BeanNameAware, 
              ApplicationListener<ContextRefreshedEvent>, 
              CommandLineRunner,
              SmartInitializingSingleton {
        @Override
        public void afterPropertiesSet() throws Exception {
           log.error("啟動(dòng)順序:afterPropertiesSet");
        }

        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
           log.error("啟動(dòng)順序:setApplicationContext");
        }

        2.TestSpringOrder 使用 PostConstruct注解初始化,聲明 init-method方法初始化。

        @PostConstruct
        public void postConstruct() {
           log.error("啟動(dòng)順序:post-construct");
        }

        public void initMethod() {
           log.error("啟動(dòng)順序:init-method");
        }

        3.新建 TestSpringOrder2 繼承

        public class TestSpringOrder3 implements
                 BeanPostProcessor, 
                 BeanFactoryPostProcessor {
           @Override
           public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
              log.error("啟動(dòng)順序:BeanPostProcessor postProcessBeforeInitialization beanName:{}", beanName);
              return bean;
           }

           @Override
           public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
              log.error("啟動(dòng)順序:BeanPostProcessor postProcessAfterInitialization beanName:{}", beanName);
              return bean;
           }

           @Override
           public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
              log.error("啟動(dòng)順序:BeanFactoryPostProcessor postProcessBeanFactory ");
           }
        }

        執(zhí)行以上代碼后,可以在日志中看到啟動(dòng)順序!

        實(shí)際的執(zhí)行順序

        2023-11-25 18:10:53,748 [main] ERROR (TestSpringOrder3:37) - 啟動(dòng)順序:BeanFactoryPostProcessor postProcessBeanFactory 
        2023-11-25 18:10:59,299 [main] ERROR (TestSpringOrder:53) - 啟動(dòng)順序:構(gòu)造函數(shù) TestSpringOrder
        2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:127) - 啟動(dòng)順序: Autowired
        2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:129) - 啟動(dòng)順序:setBeanName
        2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:111) - 啟動(dòng)順序:setBeanFactory
        2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:121) - 啟動(dòng)順序:setApplicationContext
        2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder3:25) - 啟動(dòng)順序:BeanPostProcessor postProcessBeforeInitialization beanName:testSpringOrder
        2023-11-25 18:10:59,316 [main] ERROR (TestSpringOrder:63) - 啟動(dòng)順序:post-construct
        2023-11-25 18:10:59,317 [main] ERROR (TestSpringOrder:116) - 啟動(dòng)順序:afterPropertiesSet
        2023-11-25 18:10:59,317 [main] ERROR (TestSpringOrder:46) - 啟動(dòng)順序:init-method
        2023-11-25 18:10:59,320 [main] ERROR (TestSpringOrder3:31) - 啟動(dòng)順序:BeanPostProcessor postProcessAfterInitialization beanName:testSpringOrder
        2023-11-25 18:17:21,563 [main] ERROR (SpringOrderConfiguartion:21) - 啟動(dòng)順序: @Bean 注解方法執(zhí)行
        2023-11-25 18:17:21,668 [main] ERROR (TestSpringOrder:58) - 啟動(dòng)順序:SmartInitializingSingleton
        2023-11-25 18:17:21,675 [main] ERROR (TestSpringOrder:74) - 啟動(dòng)順序:start
        2023-11-25 18:17:23,508 [main] ERROR (TestSpringOrder:68) - 啟動(dòng)順序:ContextRefreshedEvent
        2023-11-25 18:17:23,574 [main] ERROR (TestSpringOrder:79) - 啟動(dòng)順序:CommandLineRunner

        我通過(guò)在以上擴(kuò)展點(diǎn) 添加 debug 斷點(diǎn),調(diào)試代碼,整理出 Spring啟動(dòng)原理的 長(zhǎng)圖。過(guò)程省略…………

        一張長(zhǎng)圖透徹解釋 Spring啟動(dòng)順序

        圖片

        實(shí)例化和初始化的區(qū)別

        new TestSpringOrder():new 創(chuàng)建對(duì)象實(shí)例,即為實(shí)例化一個(gè)對(duì)象;執(zhí)行該Bean的 init-method 等方法 為初始化一個(gè)Bean。注意初始化和實(shí)例化的區(qū)別。

        Spring 重要擴(kuò)展點(diǎn)的啟動(dòng)順序

        1.BeanFactoryPostProcessor

        BeanFactory初始化之后,所有的Bean定義已經(jīng)被加載,但Bean實(shí)例還沒(méi)被創(chuàng)建(不包括BeanFactoryPostProcessor類型)。Spring IoC容器允許BeanFactoryPostProcessor讀取配置元數(shù)據(jù),修改bean的定義,Bean的屬性值等。

        2.實(shí)例化Bean

        Spring 調(diào)用java反射API 實(shí)例化 Bean。等同于 new TestSpringOrder();

        3.Autowired 裝配依賴

        Autowired是 借助于 AutowiredAnnotationBeanPostProcessor 解析 Bean 的依賴,裝配依賴。如果被依賴的Bean還未初始化,則先初始化 被依賴的Bean。在 Bean實(shí)例化完成后,Spring將首先裝配Bean依賴的屬性。

        4.BeanNameAware

        setBeanName

        5.BeanFactoryAware

        setBeanFactory

        6.ApplicationContextAware setApplicationContext

        在Bean實(shí)例化前,會(huì)率先設(shè)置Aware接口,例如 BeanNameAware BeanFactoryAware ApplicationContextAware

        7.BeanPostProcessor postProcessBeforeInitialization

        如果我想在 bean初始化方法前后要添加一些自己邏輯處理。可以提供 BeanPostProcessor接口實(shí)現(xiàn)類,然后注冊(cè)到Spring IoC容器中。在此接口中,可以創(chuàng)建Bean的代理,甚至替換這個(gè)Bean。

        8.PostConstruct 執(zhí)行

        接下來(lái) Spring會(huì)依次調(diào)用 Bean實(shí)例初始化的 三大方法。

        9.InitializingBean

        afterPropertiesSet

        10.init-method

        方法執(zhí)行

        11.BeanPostProcessor postProcessAfterInitialization

        在 Spring 對(duì)Bean的初始化方法執(zhí)行完成后,執(zhí)行該方法

        12.其他Bean 實(shí)例化和初始化

        Spring 會(huì)循環(huán)初始化Bean。直至所有的單例Bean都完成初始化

        13.所有單例Bean 初始化完成后

        14.SmartInitializingSingleton Bean實(shí)例化后置處理

        該接口的執(zhí)行時(shí)機(jī)在 所有的單例Bean執(zhí)行完成后。例如Spring 事件訂閱機(jī)制的 EventListener注解,所有的訂閱者 都是 在這個(gè)位置被注冊(cè)進(jìn) Spring的。而在此之前,Spring Event訂閱機(jī)制還未初始化完成。所以如果有 MQ、Rpc 入口流量在此之前開(kāi)啟,Spring Event就可能出問(wèn)題!

        所以強(qiáng)烈建議 Http、MQ、Rpc 入口流量在 SmartInitializingSingleton 之后開(kāi)啟流量。

        Http、MQ、Rpc 入口流量必須在 SmartInitializingSingleton 之后開(kāi)啟流量。

        15.Spring 提供的擴(kuò)展點(diǎn),在所有單例Bean的 EventListener等組件全部啟動(dòng)完成后,即Spring啟動(dòng)完成,則執(zhí)行 start 方法。在這個(gè)位置適合開(kāi)啟入口流量!

        Http、MQ、Rpc 入口流量適合 在 SmartLifecyle 中開(kāi)啟

        16.發(fā)布 ContextRefreshedEvent 方法

        該事件會(huì)執(zhí)行多次,在 Spring Refresh 執(zhí)行完成后,就會(huì)發(fā)布該事件!

        17.注冊(cè)和初始化 Spring MVC

        SpringBoot 應(yīng)用,在父級(jí) Spring啟動(dòng)完成后,會(huì)嘗試啟動(dòng) 內(nèi)嵌式 tomcat容器。在此之前,SpringBoot會(huì)初始化 SpringMVC 和注冊(cè)DispatcherServlet到Web容器。

        18.Tomcat/Jetty 容器開(kāi)啟端口

        SpringBoot 調(diào)用內(nèi)嵌式容器,會(huì)開(kāi)啟并監(jiān)聽(tīng)端口,此時(shí)Http流量就開(kāi)啟了。

        19.應(yīng)用啟動(dòng)完成后,執(zhí)行 CommandLineRunner

        SpringBoot 特有的機(jī)制,待所有的完全執(zhí)行完成后,會(huì)執(zhí)行該接口 run方法。值得一提的是,由于此時(shí)Http流量已經(jīng)開(kāi)啟,如果此時(shí)進(jìn)行本地緩存初始化、預(yù)熱緩存等,稍微有些晚了!在這個(gè)間隔期,可能緩存還未就緒!

        所以預(yù)熱緩存的時(shí)機(jī)應(yīng)該發(fā)生在 入口流量開(kāi)啟之前,比較合適的機(jī)會(huì)是在 Bean初始化的階段。雖然 在Bean初始化時(shí) Spring尚未完成啟動(dòng),但是調(diào)用 Bean預(yù)熱緩存也是可以的。但是注意:不要在 Bean初始化時(shí) 使用 Spring Event,因?yàn)樗€未完成初始化 。

        回答 關(guān)于 Spring 啟動(dòng)原理的若干問(wèn)題

        1.init-method、PostConstruct、afterPropertiesSet 三個(gè)方法的執(zhí)行順序。

        回答:PostConstruct,afterPropertiesSet,init-method

        2.有兩個(gè) Bean聲明了初始化方法。A使用 PostConstruct注解聲明,B使用 init-method 聲明。Spring一定先執(zhí)行 A 的PostConstruct 方法嗎?

        回答:Spring 會(huì)循環(huán)初始化Bean實(shí)例,初始化完成1個(gè)Bean,再初始化下一個(gè)Bean。Spring并沒(méi)有使用這種機(jī)制啟動(dòng),即所有的Bean先執(zhí)行 PostConstruct,再統(tǒng)一執(zhí)行afterProperfiesSet。

        此外,A、B兩個(gè)Bean的初始化順序不確定,誰(shuí)先誰(shuí)后不確定。無(wú)法保證 A 的PostConstruct 一定先執(zhí)行。除非使用 Order注解,聲明Bean的初始化順序!

        3.Spring 何時(shí)裝配Autowire屬性,PostConstruct方法中引用 Autowired 字段是否會(huì)空指針?

        Autowired裝配依賴發(fā)生在 PostConstruct之前,不會(huì)出現(xiàn)空指針!

        4.PostConstruct 中方法依賴ApplicationContextAware拿到 ApplicationContext,兩者的順序誰(shuí)先誰(shuí)后?是否會(huì)出現(xiàn)空指針!

        ApplicationContextAware 會(huì)先執(zhí)行,不會(huì)出現(xiàn)空指針!但是當(dāng)Autowired沒(méi)有找到對(duì)應(yīng)的依賴,并且聲明了非強(qiáng)制依賴時(shí),該字段會(huì)為空,有潛在 空指針風(fēng)險(xiǎn)。

        5.項(xiàng)目應(yīng)該如何監(jiān)聽(tīng) Spring 的啟動(dòng)就緒事件。

        通過(guò)SmartLifecyle start方法,監(jiān)聽(tīng)Spring就緒 。適合在此開(kāi)啟入口流量!

        6.項(xiàng)目如何監(jiān)聽(tīng)Spring 刷新事件。

        監(jiān)聽(tīng) Spring Event ContextRefreshedEvent

        7.Spring就緒事件和刷新事件的執(zhí)行順序和區(qū)別。

        Spring就緒事件會(huì)先于 刷新事件。兩者都可能多次執(zhí)行,要確保方法的冪等處理,避免重復(fù)注冊(cè)問(wèn)題

        8.Http 流量入口何時(shí)啟動(dòng)完成。

        SpringBoot 最后階段,啟動(dòng)完成Spring 上下文,才開(kāi)啟Http入口流量,此時(shí) SmartLifecycle#start 已執(zhí)行。所有單例Bean和SpringEvent等組件都已經(jīng)就緒!

        9.項(xiàng)目中在 init-method 方法中注冊(cè) Rpc是否合理?什么是合理的時(shí)機(jī)?

        init 開(kāi)啟Rpc流量非常不合理。因?yàn)镾pring尚未啟動(dòng)完成,包括 Spring Event尚未就緒!

        10.項(xiàng)目中在 init-method 方法中注冊(cè) MQ消費(fèi)組是否合理?什么是合理的時(shí)機(jī)?

        init 開(kāi)啟 MQ 流量非常不合理。因?yàn)镾pring尚未啟動(dòng)完成,包括 Spring Event尚未就緒!

        11.Spring還未完全啟動(dòng),在 PostConstruct 中調(diào)用 getBeanByAnnotation能否獲得準(zhǔn)確的結(jié)果?

        雖然未啟動(dòng)完成,但是Spring執(zhí)行該getBeanByAnnotation方法時(shí),會(huì)率先檢查 Bean定義,如果Bean定義對(duì)應(yīng)的 Bean尚未初始化,則初始化這些Bean。所以即便是Spring初始化過(guò)程中調(diào)用,調(diào)用結(jié)果是準(zhǔn)確的。

        源碼級(jí)別介紹

        SmartInitializingSingleton 接口的執(zhí)行位置

        下圖代碼說(shuō)明了,Spring在初始化全部 單例Bean以后,會(huì)執(zhí)行 SmartInitializingSingleton 接口。

        圖片

        Autowired 何時(shí)裝配Bean的依賴

        在Bean實(shí)例化之后,但初始化之前,AutowiredAnnotationBeanPostProcessor 會(huì)注入Autowired字段。

        圖片

        SpringBoot 何時(shí)開(kāi)啟Http端口

        下圖代碼中可以看到,SpringBoot會(huì)首先啟動(dòng) Spring上下文,完成后才啟動(dòng) 嵌入式Web容器,初始化SpringMVC,監(jiān)聽(tīng)端口

        圖片

        Spring 初始化Bean的關(guān)鍵代碼

        下圖我加了注釋,Spring初始化Bean的關(guān)鍵代碼,全在 這個(gè)方法里,感興趣的可以自行查閱代碼 。

        AbstractAutowireCapableBeanFactory#initializeBean
        圖片

        Spring CommandLineRunner 執(zhí)行位置

        Spring Boot外部,當(dāng)啟動(dòng)完Spring上下文以后,最后才啟動(dòng) CommandLineRunner

        圖片

        總結(jié)

        SpringBoot 會(huì)在Spring完全啟動(dòng)完成后,才開(kāi)啟Http流量。這給了我們啟示:應(yīng)該在Spring啟動(dòng)完成后開(kāi)啟入口流量。Rpc和 MQ流量 也應(yīng)該如此,所以建議大家 在 SmartLifecype 或者 ContextRefreshedEvent 等位置 注冊(cè)服務(wù),開(kāi)啟流量。

        例如 Spring Cloud  Eureka 服務(wù)發(fā)現(xiàn)組件,就是在 SmartLifecype中注冊(cè)服務(wù)的!

        整理 10 個(gè)小時(shí)寫完本篇文章,希望大家有所收獲。

        ?? 歡迎加入小哈的星球 ,你將獲得: 專屬的項(xiàng)目實(shí)戰(zhàn) / Java 學(xué)習(xí)路線 / 一對(duì)一提問(wèn) / 學(xué)習(xí)打卡 /  每月贈(zèng)書


        新項(xiàng)目:仿小紅書(微服務(wù)架構(gòu))正在更新中... , 全棧前后端分離博客項(xiàng)目 2.0 版本完結(jié)啦, 演示鏈接http://116.62.199.48/ 。全程手摸手,后端 + 前端全棧開(kāi)發(fā),從 0 到 1 講解每個(gè)功能點(diǎn)開(kāi)發(fā)步驟,1v1 答疑,直到項(xiàng)目上線。目前已更新了261小節(jié),累計(jì)41w+字,講解圖:1806張,還在持續(xù)爆肝中.. 后續(xù)還會(huì)上新更多項(xiàng)目,目標(biāo)是將Java領(lǐng)域典型的項(xiàng)目都整一波,如秒殺系統(tǒng), 在線商城, IM即時(shí)通訊,Spring Cloud Alibaba 等等,戳我加入學(xué)習(xí),已有1400+小伙伴加入(早鳥價(jià)超低)



            
               

        1. 我的私密學(xué)習(xí)小圈子~

        2. 你還在使用 WebSocket 實(shí)現(xiàn)實(shí)時(shí)消息推送嗎?

        3. 高性能必殺技:Java中的池化技術(shù)

        4. 官方推出了 Spring AI 框架,Java集成 AI 不再是難事!

        最近面試BAT,整理一份面試資料Java面試BATJ通關(guān)手冊(cè),覆蓋了Java核心技術(shù)、JVM、Java并發(fā)、SSM、微服務(wù)、數(shù)據(jù)庫(kù)、數(shù)據(jù)結(jié)構(gòu)等等。

        獲取方式:點(diǎn)“在看”,關(guān)注公眾號(hào)并回復(fù) Java 領(lǐng)取,更多內(nèi)容陸續(xù)奉上。

        PS:因公眾號(hào)平臺(tái)更改了推送規(guī)則,如果不想錯(cuò)過(guò)內(nèi)容,記得讀完點(diǎn)一下在看,加個(gè)星標(biāo),這樣每次新文章推送才會(huì)第一時(shí)間出現(xiàn)在你的訂閱列表里。

        點(diǎn)“在看”支持小哈呀,謝謝啦

        瀏覽 340
        2點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        2點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            女生张开腿男生桶 | aaa视频| 国产帅男男Gay在线观看 | 一级少妇婬高潮免费全看 | 久久久久无码精品国产H动漫猫咪 | 中文字幕在线不卡 | 色老板成人 | 小龙女┅┅快┅┅用力啊 | 太粗太大小雪老师受不了 | 久久黄色视 |