Разделяем обработку сложной логики IF/ELSE в Java
В этом выпуске мы поделимся обработкой логов в Java (Часть 1)
Каждый должен был использовать журнал.Хотя журнал кажется необязательным, при возникновении проблемы он пригодится.Поэтому то, хорошо ли написан журнал или не стандартизирован, напрямую влияет на разрешение сбоев производственной среды.Это может влияют на производительность среды и сложность устранения неполадок.Устранение неполадок может занять больше времени, чем написание кода.
Тогда давайте проанализируем первую статью Руководства по разработке Java для Alibaba — Log Protocol: [Обязательно] API в системе логирования (Log4j, Logback) нельзя использовать напрямую в приложении, но следует использовать API в фреймворке логирования SLF4J, а также использовать фреймворк логирования фасадного режима, что способствует унификация методов ведения и обработки журналов различных классов.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
структура регистрации
Фреймворк логирования в Java делится на следующие типы:
-
Log4jApache Log4j — это инструмент ведения журнала на основе Java. Он был разработан Ceki Gülcü и теперь является проектом Apache Software Foundation. -
Log4j 2Apache Log4j 2 — это обновленный продукт Log4j, разработанный apache. -
Commons LoggingПроект Apache Foundation представляет собой набор интерфейсов ведения журналов Java, ранее называвшихся Jakarta Commons Logging, а затем переименованных в Commons Logging. -
Slf4jПодобно Commons Logging, это набор простых фасадов ведения журнала Java, и в нем нет реализации журнала. (Простой фасад ведения журнала для Java, сокращенно Slf4j). -
LogbackРеализация набора компонентов логирования (лагерь slf4j). -
Jul(Java Util Logging), официальная реализация ведения журнала, начиная с Java 1.4.
Пример использования
- Jul
import java.util.logging.Logger;
private static final Logger logger = Logger.getLogger("name");
...
try {
...
} catch (Exception e) {
logger.error(".....error");
}
if(logger.isDebugEnabled()) {
logger.debug("....." + name);
}
- Log4j
import org.apache.log4j.Logger;
private static final Logger logger = Logger.getLogger(Abc.class.getNeme());
...
try {
...
} catch (Exception e) {
logger.error(".....error");
}
if(logger.isDebugEnabled()) {
logger.debug("....." + name);
}
- Commons Logging
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
private static final Log logger = LogFactory.getLogger(Abc.class);
...
try {
...
} catch (Exception e) {
logger.error(".....error");
}
if(logger.isDebugEnabled()) {
logger.debug("....." + name);
}
- Slf4j
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
private static final Logger logger = LoggerFactory.getLogger(Abc.class);
...
try {
...
} catch (Exception e) {
logger.error(".....error {}", e.getMessage(), e);
}
logger.debug(".....{}", name);
-
Jul
- Заполнители не поддерживаются
- Конкретная реализация журнала
-
Log4j
- Заполнители не поддерживаются
- Конкретная реализация журнала
-
Logback
- Заполнители не поддерживаются
- Конкретная реализация журнала
-
Commons Logging
- Заполнители не поддерживаются
- бревенчатый фасад
-
Slf4j
- Поддержка заполнителей
- бревенчатый фасад
В Slf4j есть очень важная особенность:
占位符, {} можно стыковать с любым字符串, по сравнению с преимуществами других фреймворков, которые не нужно использовать+Для сращивания строк не будут создаваться новые строковые объекты, поэтому, как и в log4j, вам нужно добавитьisDebugEnabled()Суждение есть истина, и нет необходимости добавлять суждение в slf4j.
узор фасада
Фасадный режим, также известный как внешний вид, скрывает сложность системы и предоставляет доступные интерфейсы для клиента.Преимущество фасадного режима заключается в слабой связи клиента и подсистемы, что облегчает расширение и обслуживание подсистемы.
Это характеристики режима фасада.Используя фасад Slf4j, независимо от того, использует ли компонент журнала log4j или logback и т. д., вызывающей стороне все равно, какой компонент журнала используется, и для замены или обновления компонента журнала, вызов Не вносите никаких изменений в место.
Анализ исходного кода
Здесь должен быть код (чжан) (шэн):
Во-первых, используйте статическую фабрику для получения объекта Logger. Входящий класс в конечном итоге будет преобразован в имя. Обработка журнала каждого класса может быть разной, поэтому реализация класса оценивается в соответствии с именем входящего класса.
public static Logger getLogger(Class clazz) {
return getLogger(clazz.getName());
}
public static Logger getLogger(String name) {
ILoggerFactory iLoggerFactory = getILoggerFactory();
return iLoggerFactory.getLogger(name);
}
Настоящее ядро находится в getILoggerFactory(), сначала определите состояние инициализации
INITIALIZATION_STATE, если не инициализированUNINITIALIZED, он изменит состояние на инициализациюONGOING_INITIALIZATION, и выполнить инициализациюperformInitialization(), после завершения инициализации определить статус инициализации, если инициализация прошла успешноSUCCESSFUL_INITIALIZATION, то пройдетStaticLoggerBinderполучить бревенчатый заводgetLoggerFactory(), снова здесь单例模式.
public static ILoggerFactory getILoggerFactory() {
if (INITIALIZATION_STATE == UNINITIALIZED) {
INITIALIZATION_STATE = ONGOING_INITIALIZATION;
performInitialization();
}
switch (INITIALIZATION_STATE) {
case SUCCESSFUL_INITIALIZATION:
return StaticLoggerBinder.getSingleton().getLoggerFactory();
case NOP_FALLBACK_INITIALIZATION:
return NOP_FALLBACK_FACTORY;
case FAILED_INITIALIZATION:
throw new IllegalStateException("org.slf4j.LoggerFactory could not be successfully initialized. See also http://www.slf4j.org/codes.html#unsuccessfulInit");
case ONGOING_INITIALIZATION:
return TEMP_FACTORY;
}
throw new IllegalStateException("Unreachable code");
}
Затем мы анализируем
performInitializationКак он инициализируется, первый - выполнитьbind()метод, а затем решить, успешно ли инициализирован статусSUCCESSFUL_INITIALIZATION, выполните проверку версии, в основном, чтобы проверить версию jdk и версию slf4j, чтобы увидеть, совпадают ли они.
private static final void performInitialization() {
bind();
if (INITIALIZATION_STATE == 3) {
versionSanityCheck();
}
}
Метод bind() сначала получает путь загрузки журнала реализации, проверяет, является ли путь допустимым, а затем инициализирует объект StaticLoggerBinder, чтобы найти подходящий метод реализации для использования.
private static final void bind() {
try {
Set staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
StaticLoggerBinder.getSingleton();
INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
reportActualBinding(staticLoggerBinderPathSet);
emitSubstituteLoggerWarning();
} 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 http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.");
} else {
failedBinding(ncde);
throw ncde;
}
} catch (NoSuchMethodError nsme) {
String msg = nsme.getMessage();
if ((msg != null) && (msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1)) {
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);
}
}
Видно, что самым важным методом в методе bind() является поиск метода реализации
findPossibleStaticLoggerBinderPathSet, конкретный метод реализован следующим образом:
private static Set findPossibleStaticLoggerBinderPathSet() {
Set staticLoggerBinderPathSet = new LinkedHashSet();
try {
ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
Enumeration paths;
Enumeration paths;
if (loggerFactoryClassLoader == null) {
paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
} else {
paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
}
while (paths.hasMoreElements()) {
URL path = (URL)paths.nextElement();
staticLoggerBinderPathSet.add(path);
}
} catch (IOException ioe) {
Util.report("Error getting resources from path", ioe);
}
return staticLoggerBinderPathSet;
}
Уведомление! ! Впереди высокая энергия! !
Прелесть Slf4j заключается в том, что загрузчик классов загружает класс, то есть ищет файл StaticLoggerBinder.class, а затем, пока компонент журнала этого класса реализован, его можно использовать как реализацию. есть несколько реализаций, кто будет первым Кто бы ни использовался при загрузке, это место включает
JVM的类加载机制
наведение мостов
- Мост между Slf4j и другими компонентами журнала
-
slf4j-log4j12-1.7.13.jar
- log4j 1.2 версия бриджа
-
slf4j-jdk14-1.7.13.jar
- Мост к java.util.logging
-
slf4j-nop-1.7.13.jar
- NOP-мост
-
slf4j-simple-1.7.13.jar
- Простая реализация моста
-
slf4j-jcl-1.7.13.jar
- Мост для ведения журналов Jakarta Commons.Этот мост делегирует все журналы SLF4j в JCL.
-
logback-classic-1.0.13.jar(requires logback-core-1.0.13.jar)
- Нативная реализация slf4j, logback напрямую реализует интерфейс slf4j, поэтому использование slf4j в сочетании с logback также означает меньшие затраты памяти и вычислительных ресурсов.
Slf4j ManualСуществует изображение, которое ясно показывает метод доступа, а именно:
- Объединение устаревших API
- log4j-over-slf4j-version.jar* перенаправить log4j на slf4j
-
jcl-over-slf4j-version.jar
- Перенаправить Simple Logger в ведение журнала commos на slf4j
-
jul-to-slf4j-version.jar
- Перенаправить ведение журнала Java Util на slf4j
- Сводные соображения
При использовании моста slf4j обратите внимание на то, чтобы избежать образования бесконечного цикла.В пакете jar, от которого зависит проект, не должно быть следующих ситуаций.
- И log4j-over-slf4j.jar, и slf4j-log4j12.jar существуют.
- Как видно из названия, первое перенаправляется на второе, а второе делегируется первому, что образует бесконечный цикл
-
И jul-to-slf4j.jar, и slf4j-jdk14.jar существуют
- Как видно из названия, первое перенаправляется на второе, а второе делегируется первому, что образует бесконечный цикл
Суммировать
-
Чтобы лучше понять Slf4j, вам нужно знать:
- Механизм загрузки классов JVM
- Шаблоны проектирования: шаблон фасада, шаблон моста
-
Кратко резюмируем принцип Slf4j:
- Через фабричный класс предоставляется интерфейс, и пользователи могут напрямую использовать API для записи журнала через этот фасад.
- Slf4j ищет и загружает конкретную реализацию, а процесс поиска заключается в загрузке через загрузку класса.org/slf4j/impl/StaticLoggerBinder.classфайл, если реализована система реализации журнала этого файла, его можно использовать в качестве метода реализации.
- Если вы найдете много способов, то ищите способ по умолчанию.
- Вот как работает интерфейс ведения журнала,Просто и эффективно, Ключполностью развязанный, часть реализации журнала не должна предоставлять какую-либо конфигурацию модификации, она должна только соответствовать загружаемым стандартам интерфейса,Способствует поддержанию и унификации методов обработки бревен различных классов.