자바 로그 프레임 워 크 slf4j 역할 및 구현 원리
SLF4J 를 사용 하려 면'org.slf4j:slf4j-api'에 대한 의존 도 를 포함해 야 합 니 다.
단순 회고 외관 모드
slf4j 는 외관 모델 의 전형 적 인 응용 이기 때문에 slf4j 를 말 하기 전에 우 리 는 먼저 외관 모델 을 간단하게 살 펴 보 자.
외관 모델 은 그 핵심 은 외부 와 하나의 서브 시스템 의 통신 이 반드시 통 일 된 외관 대상 을 통 해 이 루어 져 야 서브 시스템 이 더욱 쉽게 사용 할 수 있다 는 것 이다.한 장의 그림 으로 외관 모델 의 구 조 를 나타 낸다.
외관 모델 의 핵심 은 Facade 즉 외관 대상 이 고 외관 대상 의 핵심 은 몇 가지 이다.
모든 하위 캐릭터 의 기능 과 책임 을 알 고 있다.
클 라 이언 트 가 보 낸 요청 을 서브 시스템 에 위임 하고 실제 업무 논리 가 없습니다4.567917.서브 시스템 내 업무 논리의 실현 에 참여 하지 않 는 다.
대체로 겉치레 패턴 에 대한 회 고 는 여기까지 하고 다음 SLF4J 에 대한 공 부 를 시작 하면 된다.
우리 가 왜 slf4j 를 사용 해 야 합 니까?
우 리 는 왜 slf4j 를 사용 해 야 합 니까?예 를 들 어:
저희 시스템 에 logback 로그 시스템 을 사 용 했 습 니 다.
우리 시스템 은 A.jar,A.jar 에서 사용 하 는 로그 시스템 을 log4j 로 사 용 했 습 니 다.
우리 시스템 은 B.jar,B.jar 에서 사용 하 는 로그 시스템 을 slf4j-simple 로 사 용 했 습 니 다.
이렇게 되면 우리 시스템 은 logback,log4j,slf4j-simple 세 가지 로그 프레임 워 크 를 동시에 지원 하고 유지 해 야 하기 때문에 매우 불편 합 니 다.
이 문 제 를 해결 하 는 방식 은 어댑터 를 도입 하여 어댑터 가 어떤 로그 시스템 을 사용 할 지 결정 하 는 것 이다.호출 단 이 해 야 할 일 은 로 그 를 인쇄 하 는 것 이지 로 그 를 어떻게 인쇄 하 는 지 에 관심 을 가 질 필요 가 없다.slf4j 나 comons-logging 은 바로 이러한 어댑터 이 고 slf4j 는 본 연구 의 대상 이다.
위의 설명 에서 우 리 는 한 가 지 를 분명히 알 아야 한다.slf4j 는 로그 표준 일 뿐 로그 시스템 의 구체 적 인 실현 이 아니다.이 말 을 이해 하 는 것 은 매우 중요 하 다.slf4j 는 두 가지 일 만 한다.
로그 인터페이스 제공
구체 적 인 로그 대상 을 얻 는 방법 을 제공 합 니 다slf4j-simple,logback 은 모두 slf4j 의 구체 적 인 실현 이다.log4j 는 slf4j 를 직접적 으로 실현 하지 않 지만 전문 적 인 브리지 slf4j-log4j 12 로 slf4j 를 실현 한다.
slf4j 를 더욱 이해 하기 위해 우 리 는 먼저 예 를 보고 소스 코드 를 읽 으 며 독자 친구 들 이 slf4j 에 대해 더욱 깊 은 인식 을 가지 게 될 것 이 라 고 믿는다.
slf4j 응용 예
위 에서 말 했 듯 이 slf4j 의 직접/간접 실현 은 slf4j-simple,logback,slf4j-log4j 12 가 있 습 니 다.우 리 는 먼저 pom.xml 를 정의 하여 관련 jar 패 키 지 를 도입 합 니 다.
<!-- : http://www.cnblogs.com/xrq730/p/8619156.html -->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.xrq.log</groupId>
<artifactId>log-test</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<name>log-test</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.21</version>
</dependency>
</dependencies>
</project>
간단 한 자바 코드 쓰기:
@Test
public void testSlf4j() {
Logger logger = LoggerFactory.getLogger(Object.class);
logger.error("123");
}
이 어 우 리 는 먼저 위의 pom.xml 의 30 번 째 줄~49 번 째 줄 을 주석 합 니 다.즉,어떠한 slf4j 의 실현 류 도 도입 하지 않 고 Test 방법 을 실행 합 니 다.콘 솔 의 출력 을 살 펴 보 겠 습 니 다.로그 의 출력 이 없 는 것 을 보 았 습 니 다.이것 은 우리 의 관점 을 검 증 했 습 니 다.slf4j 는 로그 의 구체 적 인 실현 을 제공 하지 않 고 slf4j 만 로 그 를 인쇄 할 수 없습니다.
이 어 logback-classic 의 설명 을 열 고 Test 방법 을 실행 합 니 다.콘 솔 의 출력 을 살 펴 보 겠 습 니 다.
slf4j 의 구체 적 인 실현 클래스 를 도입 하면 로그 프레임 워 크 출력 로 그 를 사용 할 수 있 습 니 다.
마지막 으로 테스트 를 합 니 다.우 리 는 모든 로 그 를 열 고 logback-classic,slf4j-simple,log4j 를 도입 하여 Test 방법 을 실행 합 니 다.콘 솔 출력 은:
위의 차이 점 은 로 그 를 출력 할 수 있 지만 경고 로 그 를 출력 합 니 다.여러 slf4j 의 실현 을 동시에 도입 한 다음 에 그 중 하 나 를 우리 가 사용 하 는 로그 시스템 으로 선택 하 는 것 을 알려 줍 니 다.
예 를 들 어 우 리 는 중요 한 결론 을 얻 을 수 있다.즉,slf4j 의 역할 이다.모든 코드 가 외관 대상 인 slf4j 를 사용 하면 우 리 는 구체 적 인 실현 에 관심 을 가 질 필요 가 없다.최종 적 으로 모든 곳 에서 구체 적 인 실현 을 사용 하면 되 고 교체,유지 가 매우 편리 하 다.
slf4j 실현 원리
위 에서 slf4j 의 예 시 를 보 았 습 니 다.다음은 slf4j 의 실현 을 연구 하고 우 리 는 중점 코드 에 만 관심 을 가 집 니 다.
slf4j 의 용법 은 일년 내 내 변 하지 않 는"Logger logger=Logger Factory.getLogger(Object.class)"입 니 다.이 를 통 해 알 수 있 듯 이 Logger Factory 를 통 해 slf4j 가 제공 하 는 Logger 인터페이스 의 구체 적 인 실현 일 뿐 입 니 다.Logger Factory 의 getLogger 방법 은 다음 과 같 습 니 다.
public static Logger getLogger(Class<?> clazz) {
Logger logger = getLogger(clazz.getName());
if (DETECT_LOGGER_NAME_MISMATCH) {
Class<?> autoComputedCallingClass = Util.getCallingClass();
if (autoComputedCallingClass != null && nonMatchingClasses(clazz, autoComputedCallingClass)) {
Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
autoComputedCallingClass.getName()));
Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
}
}
return logger;
}
두 번 째 줄 부터 코드 를 따라 Logger Factory 의 bid()방법 까지 따라 갑 니 다.
private final static void bind() {
try {
Set<URL> staticLoggerBinderPathSet = null;
// skip check under android, see also
// http://jira.qos.ch/browse/SLF4J-328
if (!isAndroid()) {
staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
}
// the next line does the binding
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(staticLoggerBinderPathSet);
fixSubstituteLoggers();
replayEvents();
// release all resources in SUBST_FACTORY
SUBST_FACTORY.clear();
} catch (NoClassDefFoundError ncde) {
String msg = ncde.getMessage();
if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
Util.report("Defaulting to no-operation (NOP) logger implementation");
Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
} else {
failedBinding(ncde);
throw ncde;
}
} catch (java.lang.NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if (msg != null && msg.contains("org.slf4j.impl.StaticLoggerBinder.getSingleton()")) {
INITIALIZATION_STATE = FAILED_INITIALIZATION;
Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
Util.report("Your binding is version 1.5.5 or earlier.");
Util.report("Upgrade your binding to version 1.6.x.");
}
throw nsme;
} catch (Exception e) {
failedBinding(e);
throw new IllegalStateException("Unexpected initialization failure", e);
}
}
이곳 의 일곱 번 째 줄 이 관건 입 니 다.코드 를 보 세 요.
static Set<URL> findPossibleStaticLoggerBinderPathSet() {
// use Set instead of list in order to deal with bug #138
// LinkedHashSet appropriate here because it preserves insertion order
// during iteration
Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration<URL> paths;
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
이곳 의 포 인 트 는 바로 12 번 째 줄 의 코드 입 니 다.getLogger 는 classpath 에서 STATIC 을 찾 습 니 다.LOGGER_BINDER_PATH,STATIC_LOGGER_BINDER_PATH 값 은"org/slf4j/impl/staticLoggerBinder.class"입 니 다.즉,모든 slf4j 의 실현 입 니 다.제 공 된 jar 패키지 경로 에"org/slf4j/impl/staticLoggerBinder.class"가 존재 합 니 다.다음 을 볼 수 있 습 니 다.우 리 는 시스템 에서 여러 개의 slf4j 를 동시에 도입 하 는 것 을 피 할 수 없 기 때문에 받 는 곳 은 set 이다.상부 에서 logback,slf4j-simple,log4j 를 동시에 도입 할 때 경고 가 있 음 을 주의해 야 한다.
이것 은 바로 세 개의'org/slf4j/impl/static LoggerBinder.class'가 존재 하 는 이유 입 니 다.이때 report Multiple Binding Ambiguity 방법 콘 솔 출력 문 구 는 다음 과 같 습 니 다.
private static void reportMultipleBindingAmbiguity(Set<URL> binderPathSet) {
if (isAmbiguousStaticLoggerBinderPathSet(binderPathSet)) {
Util.report("Class path contains multiple SLF4J bindings.");
for (URL path : binderPathSet) {
Util.report("Found binding in [" + path + "]");
}
Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
}
}
그 네티즌 은'org/slf4j/impl/static LoggerBinder.class'세 개가 동시에 존재 하면 어 떡 하 냐 고 물 을 수도 있다.우선,이것 은 시작 보 고 를 잘못 하지 않 을 것 이 확실 합 니 다.그 다음 에 이러한 상황 에서 컴 파일 하 는 동안 컴 파일 러 는 그 중의 StaticLoggerBinder.class 를 선택 하여 연결 합 니 다.마지막 으로 StaticLoggerBinder 는 비교적 간단 합 니 다.서로 다른 StaticLoggerBinder 는 getLoggerFactory 가 다 릅 니 다.ILoggerFactory 를 받 은 후에 getLogger 를 호출 하면 구체 적 인 Logger 를 받 을 수 있 습 니 다.Logger 를 사용 하여 로그 출력 을 할 수 있 습 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
JPA + QueryDSL 계층형 댓글, 대댓글 구현(2)이번엔 전편에 이어서 계층형 댓글, 대댓글을 다시 리팩토링해볼 예정이다. 이전 게시글에서는 계층형 댓글, 대댓글을 구현은 되었지만 N+1 문제가 있었다. 이번에는 그 N+1 문제를 해결해 볼 것이다. 위의 로직은 이...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.