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

解決spring-boot使用logback的大坑

 更新時(shí)間:2021年07月27日 11:07:26   作者:Cumu_  
這篇文章主要介紹了解決spring-boot使用logback的大坑,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

最近在寫一個(gè)logback的kafka appender,無意中發(fā)現(xiàn)spring-boot在使用logback時(shí)的一個(gè)坑

用ConsoleAppender.java來舉例,假設(shè)在logback.xml中使用了該appender,那么這個(gè)類的相關(guān)的初始化方法都會(huì)調(diào)兩次,如start()方法

打斷點(diǎn)進(jìn)行debug,第一次進(jìn)入start()方法如下:

可以看到所有的調(diào)用鏈(除了自己代碼的方法)都是logback或者slf4j相關(guān)的比較正常

當(dāng)跳過該斷點(diǎn)時(shí)又會(huì)進(jìn)入以此這個(gè)方法,看下調(diào)用鏈:

可以看到這次的初始化是由spring-boot發(fā)起的,所以這樣logback初始化一次,然后spring-boot初始化一次,一共兩次

我們現(xiàn)在可以將spring-boot的初始化去掉

debug代碼可以發(fā)現(xiàn)LoggingApplicationListener.java這個(gè)監(jiān)聽器主要是用來初始化spring-boot的日志系統(tǒng),現(xiàn)在目的將該listener在啟動(dòng)之前去掉

spring-boot的啟動(dòng)代碼為:

new SpringApplicationBuilder(Launcher.class).application().run(args);

在SpringApplicationBuilder.java的構(gòu)造方法打斷點(diǎn)進(jìn)行跟蹤,

進(jìn)入SpringAppication.java會(huì)發(fā)現(xiàn)該類中的代碼:

private void initialize(Object[] sources) {
   if (sources != null && sources.length > 0) {
      this.sources.addAll(Arrays.asList(sources));
   }
   this.webEnvironment = deduceWebEnvironment();
   setInitializers((Collection) getSpringFactoriesInstances(
         ApplicationContextInitializer.class));
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   this.mainApplicationClass = deduceMainApplicationClass();
}

第八行應(yīng)該就是注冊監(jiān)聽器的地方了,繼續(xù)往下跟蹤,進(jìn)入以下方法:

private <T> Collection<? extends T> getSpringFactoriesInstances(Class<T> type,
      Class<?>[] parameterTypes, Object... args) {
   ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
   // Use names and ensure unique to protect against duplicates
   Set<String> names = new LinkedHashSet<String>(
         SpringFactoriesLoader.loadFactoryNames(type, classLoader));
   List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
         classLoader, args, names);
   AnnotationAwareOrderComparator.sort(instances);
   return instances;
}

繼續(xù)進(jìn)入loadFactoryNames()方法,核心就在這里了

public static List<String> loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader) {
   String factoryClassName = factoryClass.getName();
   try {
      Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
            ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      List<String> result = new ArrayList<String>();
      while (urls.hasMoreElements()) {
         URL url = urls.nextElement();
         Properties properties = PropertiesLoaderUtils.loadProperties(new UrlResource(url));
         String factoryClassNames = properties.getProperty(factoryClassName);
         result.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(factoryClassNames)));
      }
      return result;
   }
   catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load [" + factoryClass.getName() +
            "] factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex);
   }
}

FACTORIES_RESOURCE_LOCATION這個(gè)常量的值為META-INF/spring.factories,

打開該文件可以發(fā)現(xiàn):

# PropertySource Loaders
org.springframework.boot.env.PropertySourceLoader=\
org.springframework.boot.env.PropertiesPropertySourceLoader,\
org.springframework.boot.env.YamlPropertySourceLoader
# Run Listeners
org.springframework.boot.SpringApplicationRunListener=\
org.springframework.boot.context.event.EventPublishingRunListener
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.context.web.ServerPortInfoApplicationContextInitializer
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.ConfigFileApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener,\
org.springframework.boot.logging.ClasspathLoggingApplicationListener,\
org.springframework.boot.logging.LoggingApplicationListener
# Environment Post Processors
org.springframework.boot.env.EnvironmentPostProcessor=\
org.springframework.boot.cloud.CloudFoundryVcapEnvironmentPostProcessor,\
org.springframework.boot.env.SpringApplicationJsonEnvironmentPostProcessor
# Failure Analyzers
org.springframework.boot.diagnostics.FailureAnalyzer=\
org.springframework.boot.diagnostics.analyzer.BeanCurrentlyInCreationFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BeanNotOfRequiredTypeFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.BindFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.NoUniqueBeanDefinitionFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.PortInUseFailureAnalyzer,\
org.springframework.boot.diagnostics.analyzer.ValidationExceptionFailureAnalyzer
# FailureAnalysisReporters
org.springframework.boot.diagnostics.FailureAnalysisReporter=\
org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter

ApplicationListener應(yīng)該就是我們需要修改的地方了,去掉org.springframework.boot.logging.LoggingApplicationListener就可以了,我們可以在代碼里面覆蓋一份這塊代碼從而實(shí)現(xiàn)去掉這行,但是實(shí)際得再跑一遍,發(fā)現(xiàn)還是一樣初始化兩次

問題出在

Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
      ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));

這塊代碼是將所有的META-INF/spring.factories都讀取過來了然后進(jìn)行合并,所以說哦這個(gè)META-INF/spring.factories只能增加內(nèi)容,但是不能去掉某些內(nèi)容,沒辦法了只能在代碼初始化了所有的listener之后再將listener去掉,

具體代碼如下(啟動(dòng)spring-boot的main方法中):

SpringApplicationBuilder builder = new SpringApplicationBuilder(Launcher.class);
Set<ApplicationListener<?>> listeners = builder.application().getListeners();
for (Iterator<ApplicationListener<?>> it = listeners.iterator(); it.hasNext();) {
    ApplicationListener<?> listener = it.next();
    if (listener instanceof LoggingApplicationListener) {
        it.remove();
    }
}
builder.application().setListeners(listeners);
builder.run(args);

PS:其實(shí)log初始化兩次并無傷大雅,關(guān)鍵是遇到了問題總是想解決下或者了解下原理

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring中的八大模式簡單介紹

    Spring中的八大模式簡單介紹

    這篇文章主要介紹了Spring中的八大模式簡單介紹,結(jié)合實(shí)例代碼給大家講解的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • 老生常談java數(shù)組中的常見異常

    老生常談java數(shù)組中的常見異常

    數(shù)組是用來存儲(chǔ)一系列數(shù)據(jù),但它往往被認(rèn)為是一系列相同類型的變量,異常是程序中的一些錯(cuò)誤,但并不是所有的錯(cuò)誤都是異常,并且錯(cuò)誤有時(shí)候是可以避免的,接下來讓我們詳細(xì)的了解吧
    2022-03-03
  • java實(shí)現(xiàn)多人聊天工具(socket+多線程)

    java實(shí)現(xiàn)多人聊天工具(socket+多線程)

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)多人聊天工具,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • SpringBoot中的Spring Cloud Hystrix原理和用法詳解

    SpringBoot中的Spring Cloud Hystrix原理和用法詳解

    在Spring Cloud中,Hystrix是一個(gè)非常重要的組件,Hystrix可以幫助我們構(gòu)建具有韌性的分布式系統(tǒng),保證系統(tǒng)的可用性和穩(wěn)定性,在本文中,我們將介紹SpringBoot中的Hystrix,包括其原理和如何使用,需要的朋友可以參考下
    2023-07-07
  • springboot中RestTemplate配置HttpClient連接池詳解

    springboot中RestTemplate配置HttpClient連接池詳解

    這篇文章主要介紹了springboot中RestTemplate配置HttpClient連接池詳解,這些Http連接工具,使用起來都比較復(fù)雜,如果項(xiàng)目中使用的是Spring框架,可以使用Spring自帶的RestTemplate來進(jìn)行Http連接請求,需要的朋友可以參考下
    2023-11-11
  • Java中的Timer與TimerTask源碼及使用解析

    Java中的Timer與TimerTask源碼及使用解析

    這篇文章主要介紹了Java中的Timer與TimerTask源碼及使用解析,在Java中,經(jīng)常使用Timer來定時(shí)調(diào)度任務(wù),Timer調(diào)度任務(wù)有一次性調(diào)度和循環(huán)調(diào)度,循環(huán)調(diào)度有分為固定速率調(diào)度(fixRate)和固定時(shí)延調(diào)度(fixDelay),需要的朋友可以參考下
    2023-10-10
  • java實(shí)現(xiàn)三角形分形山脈

    java實(shí)現(xiàn)三角形分形山脈

    這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)三角形分形山脈,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-01-01
  • Java判斷字符串為空、字符串是否為數(shù)字

    Java判斷字符串為空、字符串是否為數(shù)字

    這篇文章主要介紹了Java判斷字符串為空、字符串是否為數(shù)字,其中數(shù)字的判斷介紹了3種方法,需要的朋友可以參考下
    2014-06-06
  • Spring?Boot中的微信支付全過程(小程序)

    Spring?Boot中的微信支付全過程(小程序)

    微信支付是企業(yè)級項(xiàng)目中經(jīng)常使用到的功能,作為后端開發(fā)人員,完整地掌握該技術(shù)是十分有必要的。今天通過本文給大家介紹Spring?Boot中的微信支付全過程,感興趣的朋友一起看看吧
    2022-05-05
  • 使用jd-gui反編譯修改jar包里的.class并重新生成新jar問題

    使用jd-gui反編譯修改jar包里的.class并重新生成新jar問題

    這篇文章主要介紹了使用jd-gui反編譯修改jar包里的.class并重新生成新jar問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-05-05

最新評論

天祝| 凤山市| 美姑县| 莱阳市| 闸北区| 绥中县| 崇仁县| 耒阳市| 雅江县| 桃园市| 万全县| 任丘市| 黔江区| 苏州市| 宜章县| 屏东市| 黄龙县| 娄烦县| 西盟| 黄大仙区| 栾城县| 天峨县| 五峰| 彩票| 岚皋县| 吴川市| 铅山县| 海林市| 长阳| 青神县| 桑植县| 涿鹿县| 武隆县| 中山市| 搜索| 绥宁县| 秦安县| 钟祥市| 南阳市| 冕宁县| 聂拉木县|