欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

自定義starter引發(fā)的線上事故記錄復(fù)盤

 更新時(shí)間:2023年05月24日 11:47:28   作者:linyb極客之路  
這篇文章主要為大家介紹了自定義starter引發(fā)的線上事故記錄復(fù)盤,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

本文素材來源于業(yè)務(wù)部門技術(shù)負(fù)責(zé)人某次線上事故復(fù)盤分享。故事的背景是這樣,該業(yè)務(wù)部門招了一個(gè)技術(shù)挺不錯(cuò)的小伙子小張,由于小張技術(shù)能力在該部門比較突出,在入職不久后,他便成為這個(gè)部門某個(gè)項(xiàng)目組的team leader,同時(shí)也擁有review 該項(xiàng)目的權(quán)利。(注: 該項(xiàng)目為微服務(wù)項(xiàng)目),在某次小張review項(xiàng)目的時(shí)候,他發(fā)現(xiàn)好幾個(gè)項(xiàng)目,發(fā)現(xiàn)代碼有很多重復(fù),于是他就動(dòng)了把這些重復(fù)代碼封裝成starter的念頭,然后也是因?yàn)檫@次的封裝,帶來一次線上事故。下面就以代碼示例的形式,模擬這次事故

代碼示例

注: 本文僅模擬出現(xiàn)事故的代碼片段,不涉及業(yè)務(wù)

1、模擬小張的封裝的starter

@Slf4j
public class HelloSevice {
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    public HelloSevice(ThreadPoolTaskExecutor threadPoolTaskExecutor){
        this.threadPoolTaskExecutor = threadPoolTaskExecutor;
    }
    public String sayHello(String username){
        threadPoolTaskExecutor.execute(()->{
            log.info("hello: {} ",username);
        });
        return " hello : " + username;
    }
}
@Configuration
public class HelloServiceAutoConfiguration {
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(2);
        threadPoolTaskExecutor.setMaxPoolSize(4);
        threadPoolTaskExecutor.setQueueCapacity(1);
        threadPoolTaskExecutor.setThreadFactory(new ThreadFactory() {
            private AtomicInteger atomicInteger = new AtomicInteger();
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("hello-pool-" + atomicInteger.getAndIncrement());
                return thread;
            }
        });
        return threadPoolTaskExecutor;
    }
    @Bean
    public HelloSevice helloSevice(ThreadPoolTaskExecutor threadPoolTaskExecutor){
        return new HelloSevice(threadPoolTaskExecutor);
    }
}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.github.lybgeek.thirdparty.autoconfigure.HelloServiceAutoConfiguration

 2、模擬有引用小張封裝的starter的微服務(wù)項(xiàng)目

因?yàn)檫@些微服務(wù)中有一些耗時(shí)的任務(wù),因此使用了spring的異步。示例如下

@Configuration
public class ThreadPoolConfig {
    @Bean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(2);
        threadPoolTaskExecutor.setMaxPoolSize(5);
        threadPoolTaskExecutor.setQueueCapacity(10);
        threadPoolTaskExecutor.setThreadFactory(new ThreadFactory() {
            private AtomicInteger atomicInteger = new AtomicInteger();
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("echo-pool-" + atomicInteger.getAndIncrement());
                return thread;
            }
        });
        threadPoolTaskExecutor.setRejectedExecutionHandler((r, executor) -> System.err.println("記錄日志。。。。"));
        return threadPoolTaskExecutor;
    }
}
@Service
@Slf4j
public class EchoService {
    @Async("threadPoolTaskExecutor")
    public void echo(String content){
        log.info("echo -> {} ",content);
        try {
            //模擬耗時(shí)操作
            TimeUnit.MINUTES.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

 3、和本文有關(guān)系的配置內(nèi)容

spring:
  main:
    allow-bean-definition-overriding: true

 4、模擬調(diào)用耗時(shí)業(yè)務(wù)代碼塊示例

@Component
public class BeanCommandRunner implements CommandLineRunner {
    @Autowired
    private EchoService echoService;
    @Override
    public void run(String... args) throws Exception {
        for (int i = 0; i < 6; i++) {
            echoService.echo("content:" + i);
        }
    }
}

相關(guān)的代碼如上述內(nèi)容

大家可以思考一下上面的示例有沒有什么問題

我們啟動(dòng)一下程序,觀察一下控制臺(tái)

報(bào)了一個(gè)線程池拒絕異常,而且通過這個(gè)異常信息,我們發(fā)現(xiàn)這個(gè)線程池走是小張封裝線程池,而非業(yè)務(wù)自己定義的線程池。這明顯是不正常的,正常的邏輯是業(yè)務(wù)代碼優(yōu)先級(jí)需比公共代碼優(yōu)先高才合理

那如何解決呢?

僅需利用springboot的條件注解即可,在小張封裝的starter下做如下改動(dòng)

@Bean
    @ConditionalOnMissingBean
    public ThreadPoolTaskExecutor threadPoolTaskExecutor(){
        ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(2);
        threadPoolTaskExecutor.setMaxPoolSize(4);
        threadPoolTaskExecutor.setQueueCapacity(1);
        threadPoolTaskExecutor.setThreadFactory(new ThreadFactory() {
            private AtomicInteger atomicInteger = new AtomicInteger();
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setName("hello-pool-" + atomicInteger.getAndIncrement());
                return thread;
            }
        });
        return threadPoolTaskExecutor;
    }

修改后,我們?cè)趩?dòng)一下程序,觀察控制臺(tái)

此時(shí)走就是業(yè)務(wù)自定義的線程池了

為什么加了一個(gè) @ConditionalOnMissingBean就可以了

這就得從springboot的自動(dòng)裝配說起了,springboot的自動(dòng)裝配類繼承了org.springframework.context.annotation.DeferredImportSelector,這個(gè)接口具有懶加載的功能,當(dāng)項(xiàng)目啟動(dòng)后,先加載業(yè)務(wù)自定義的bean,再來加載starter的bean,當(dāng)我們項(xiàng)目中沒有配置

spring:
  main:
    allow-bean-definition-overriding: true

時(shí),項(xiàng)目啟動(dòng)就會(huì)直接報(bào)類似如下異常

當(dāng)時(shí)他們業(yè)務(wù)項(xiàng)目因?yàn)樗麄僨eign沒有指定contextId,導(dǎo)致報(bào)了上述的異常,業(yè)務(wù)開發(fā)為了省事就直接把
allow-bean-definition-overriding設(shè)置成true,這也為后續(xù)小張自定義的starter引發(fā)的事故埋下了很好的根基。那我們?cè)偾谢刂骶€,當(dāng)spring發(fā)現(xiàn)有兩個(gè)一樣的bean,且發(fā)現(xiàn)allow-bean-definition-overriding為true,后面加載的bean會(huì)把前面加載的bean覆蓋掉,這也是為啥小張starter的bean會(huì)生效。

當(dāng)我們?cè)趕tarter上的bean上加載 @ConditionalOnMissingBean后,因?yàn)闃I(yè)務(wù)項(xiàng)目的bean已經(jīng)存在了,starter的bean就不會(huì)加載進(jìn)spring容器了。

我們從技術(shù)維度說明了解決方案,我們?cè)購姆羌夹g(shù)的角度上復(fù)盤一下這次事故

復(fù)盤

不知道會(huì)不會(huì)有朋友說,你說那么多,不就加一個(gè)@ConditionalOnMissingBean就能解決這個(gè)問題,下次注意就好了啊。但據(jù)業(yè)務(wù)技術(shù)人反饋當(dāng)時(shí)他們排查了挺久,因?yàn)樗麄儤I(yè)務(wù)項(xiàng)目平時(shí)沒啥并發(fā)量,所以小張那個(gè)問題就被掩蓋住了,而有次他們業(yè)務(wù)搞了一個(gè)營(yíng)銷活動(dòng),因?yàn)椴l(fā)上去了,才把問題暴露出來。這側(cè)面也說明項(xiàng)目壓測(cè)的重要性,不能因?yàn)槠綍r(shí)沒啥并發(fā),就掉以輕心

不懂大家的公司是否也有這樣的情況,在我們這邊,底下成員代碼只能merge request,只有team leader review后,再將代碼合并到主干,因?yàn)閠eam leader擁有的權(quán)限比較大,他寫的代碼,只要他愿意,直接就能合并到主干了。這次也是因?yàn)樾堉苯訉⑺麑懙拇a推到主干發(fā)布,釀成事故。后面我們這邊提出了一個(gè)方法,就是team leader的代碼要由更高級(jí)的leader進(jìn)行走查,但是這個(gè)方法我是感覺也不是很好,因?yàn)橛胁簧夙?xiàng)目組的team leader的老板基本上已經(jīng)脫離一線,不敲代碼了,也不懂能不能行。

其次因?yàn)樾埲肼毑痪?,?duì)業(yè)務(wù)其實(shí)沒有完全吃透,因?yàn)榭吹街貜?fù)的代碼,出于技術(shù)潔癖,就想去改,出發(fā)點(diǎn)是好的,但有句話技術(shù)是為業(yè)務(wù)服務(wù),業(yè)務(wù)都沒搞懂,就去動(dòng),有時(shí)候會(huì)帶來意想不到的風(fēng)險(xiǎn)

總結(jié)

對(duì)自己的不熟悉的項(xiàng)目或者開發(fā)公共組件,深思熟慮再動(dòng)手是很重要的

以上就是自定義starter引發(fā)的線上事故記錄復(fù)盤的詳細(xì)內(nèi)容,更多關(guān)于自定義starter線上事故的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java中生成微信小程序太陽碼的實(shí)現(xiàn)方案

    Java中生成微信小程序太陽碼的實(shí)現(xiàn)方案

    這篇文章主要介紹了Java中生成微信小程序太陽碼的實(shí)現(xiàn)方案,本文講解了如何生成微信小程序太陽碼,通過微信提供的兩種方案都可以實(shí)現(xiàn),在實(shí)際的項(xiàng)目中建議采用第二種方案,需要的朋友可以參考下
    2022-05-05
  • Idea的Generate Sources無法生成QueryDSL問題及解決方法

    Idea的Generate Sources無法生成QueryDSL問題及解決方法

    這篇文章主要介紹了解決Idea的Generate Sources無法生成QueryDSL問題,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-02-02
  • java設(shè)計(jì)模式學(xué)習(xí)之簡(jiǎn)單工廠模式

    java設(shè)計(jì)模式學(xué)習(xí)之簡(jiǎn)單工廠模式

    這篇文章主要為大家詳細(xì)介紹了java設(shè)計(jì)模式學(xué)習(xí)之簡(jiǎn)單工廠模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • java使用顏色選擇器示例分享

    java使用顏色選擇器示例分享

    這篇文章主要介紹了java使用顏色選擇器示例,需要的朋友可以參考下
    2014-03-03
  • java讀取簡(jiǎn)單excel通用工具類

    java讀取簡(jiǎn)單excel通用工具類

    這篇文章主要為大家詳細(xì)介紹了java讀取簡(jiǎn)單excel通用工具類,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-12-12
  • Java Cmd運(yùn)行Jar出現(xiàn)亂碼的解決方案

    Java Cmd運(yùn)行Jar出現(xiàn)亂碼的解決方案

    這篇文章主要介紹了Java Cmd運(yùn)行Jar出現(xiàn)亂碼的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java8 Predicate花樣用法詳解

    Java8 Predicate花樣用法詳解

    本文主要介紹了Java 8 Predicate花樣用法詳解,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-03-03
  • Java使用JDBC驅(qū)動(dòng)連接MySQL數(shù)據(jù)庫

    Java使用JDBC驅(qū)動(dòng)連接MySQL數(shù)據(jù)庫

    這篇文章主要為大家詳細(xì)介紹了Java使用JDBC驅(qū)動(dòng)連接MySQL數(shù)據(jù)庫的具體步驟,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • 一篇文章帶你了解Java基礎(chǔ)-接口

    一篇文章帶你了解Java基礎(chǔ)-接口

    這篇文章主要介紹了java接口基礎(chǔ)知識(shí),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-08-08
  • Java Spring集成MapStruct詳情

    Java Spring集成MapStruct詳情

    這篇文章主要介紹了Java Spring集成MapStruct詳情,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06

最新評(píng)論