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

解決spring-boot使用logback的大坑

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

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

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

打斷點進行debug,第一次進入start()方法如下:

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

當跳過該斷點時又會進入以此這個方法,看下調(diào)用鏈:

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

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

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

spring-boot的啟動代碼為:

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

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

進入SpringAppication.java會發(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();
}

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

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ù)進入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這個常量的值為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應該就是我們需要修改的地方了,去掉org.springframework.boot.logging.LoggingApplicationListener就可以了,我們可以在代碼里面覆蓋一份這塊代碼從而實現(xiàn)去掉這行,但是實際得再跑一遍,發(fā)現(xiàn)還是一樣初始化兩次

問題出在

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

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

具體代碼如下(啟動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:其實log初始化兩次并無傷大雅,關鍵是遇到了問題總是想解決下或者了解下原理

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

相關文章

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

    Spring中的八大模式簡單介紹

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

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

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

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

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

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

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

    springboot中RestTemplate配置HttpClient連接池詳解

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

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

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

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

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

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

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

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

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

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

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

最新評論

徐水县| 虹口区| 西充县| 漠河县| 西平县| 文安县| 长沙县| 临夏县| 克山县| 杭锦后旗| 揭东县| 汕头市| 屏南县| 启东市| 霍州市| 侯马市| 边坝县| 山东省| 镇巴县| 景泰县| 湘潭县| 五华县| 正阳县| 密云县| 寻甸| 西安市| 客服| 油尖旺区| 四川省| 珲春市| 黎城县| 德钦县| 前郭尔| 明星| 酒泉市| 商河县| 璧山县| 云林县| 阿拉善左旗| 兴城市| 浠水县|