spring-boot 에서 logback 을 사용 하 는 큰 구 덩이 를 해결 합 니 다.
7891 단어 spring-bootlogback
ConsoleAppender.java 를 예 로 들 면,logback.xml 에서 이 appender 를 사용 했다 고 가정 하면,이와 관련 된 초기 화 방법 은 start()방법 과 같이 두 번 조 정 됩 니 다.
중단 점 에서 debug 를 진행 합 니 다.start()에 처음 들 어 가 는 방법 은 다음 과 같 습 니 다.
모든 호출 체인(자신의 코드 를 제외 한 방법)은 logback 또는 slf4j 와 관련 된 것 이 정상 적 인 것 을 볼 수 있 습 니 다.
이 정지점 을 뛰 어 넘 었 을 때 이 방법 으로 들 어 갑 니 다.하향 조정 용 체인 을 보 세 요.
이번 초기 화 는 spring-boot 에서 시 작 된 것 을 볼 수 있 습 니 다.따라서 logback 을 한 번 초기 화하 고 spring-boot 를 한 번 초기 화 합 니 다.모두 두 번 입 니 다.
저 희 는 이제 spring-boot 의 초기 화 를 지 울 수 있 습 니 다.
debug 코드 에서 LoggingApplicationListener.java 를 발견 할 수 있 습 니 다.이 모니터 는 주로 spring-boot 로그 시스템 을 초기 화 하 는 데 사 용 됩 니 다.현재 이 listener 를 시작 하기 전에 제거 하기 위해 서 입 니 다.
spring-boot 의 시작 코드 는:
new SpringApplicationBuilder(Launcher.class).application().run(args);
SpringApplicationBuilder.자바 의 구조 방법 중단 점 을 추적 합 니 다.SpringAppication.java 에 들 어가 면 이 종류의 코드 를 발견 할 수 있 습 니 다.
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();
}
여덟 번 째 줄 은 모니터 를 등록 한 곳 일 것 입 니 다.계속 추적 하고 다음 과 같은 방법 으로 들 어 갑 니 다.
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;
}
loadFactory Names()방법 에 계속 들 어가 면 핵심 은 바로 여기에 있 습 니 다.
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 입 니 다.이 파일 을 열 면 다음 을 발견 할 수 있 습 니 다:
# 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.spring from work.boot.logging.Logging application Listener 를 없 애 면 됩 니 다.우 리 는 코드 에 이 코드 를 덮어 서 이 줄 을 없 앨 수 있 습 니 다.그러나 실제 적 으로 다시 한 번 달 려 야 합 니 다.현금 은 똑 같이 두 번 초기 화 됩 니 다.문제
Enumeration<URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
이 코드 는 모든 META-INF/spring.factories 를 읽 고 합 친 것 입 니 다.그 러 니까 이 META-INF/spring.factories 는 내용 만 추가 할 수 있 지만 어떤 내용 은 삭제 할 수 없습니다.어 쩔 수 없 이 코드 가 모든 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 를 두 번 초기 화 하 는 것 은 우아 함 을 해치 지 않 습 니 다.관건 은 문제 가 발생 하면 항상 해결 하거나 원 리 를 이해 하 는 것 입 니 다.이상 은 개인 적 인 경험 이 므 로 여러분 에 게 참고 가 되 기 를 바 랍 니 다.여러분 들 도 저 희 를 많이 응원 해 주시 기 바 랍 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Keycloak이 Active Directory에 등록된 사용자로 인증할 수 있도록 합니다.사내 시스템을 출시함에 있어서, 전회사에서는 Web시스템마다 로그인하고 있어 혐오가 있었으므로, 꼭 싱글 사인온으로 하고 싶다고 생각했다. 그 실현에, 옛날 조금만 평가한 OpenAM라든지의 정보를 구구어 낚시하기 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.