API за регистриране на платформата Java 9

1. Въведение

В този урок ще изследваме нововъведения API за регистриране в Java 9 и ще приложим някои примери, за да обхванем най-често срещаните случаи.

Този API е въведен в Java, за да осигури общ механизъм за обработка на всички регистрационни файлове на платформата и за излагане на сервизен интерфейс, който може да бъде персонализиран от библиотеки и приложения. По този начин регистрационните файлове на платформата JDK могат да използват същата рамка за регистриране като приложението и зависимостите от проекта могат да бъдат намалени.

2. Създаване на персонализирана реализация

В този раздел ще покажем основните класове на API за регистриране, които трябва да приложим, за да създадем нов регистратор. Ще направим това, като внедрим обикновен регистратор, който отпечатва всички регистрационни файлове на конзолата.

2.1. Създаване на регистратора

Основният клас, който трябва да създадем, е Logger . Този клас трябва да реализира интерфейса System.Logger и тези четири метода поне:

  • getName () : връща името на регистратора. Той ще се използва от JDK за създаване на регистратори по име
  • isLoggable () : показва за какви нива е активиран регистраторът
  • log () : това е методът, който отпечатва дневника към каквато и да е основната система, която приложението използва - конзолата в нашия случай. Има 2 метода log () за внедряване, всеки от които получава различни параметри

Нека да видим как ще изглежда нашето внедряване:

public class ConsoleLogger implements System.Logger { @Override public String getName() { return "ConsoleLogger"; } @Override public boolean isLoggable(Level level) { return true; } @Override public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) { System.out.printf("ConsoleLogger [%s]: %s - %s%n", level, msg, thrown); } @Override public void log(Level level, ResourceBundle bundle, String format, Object... params) { System.out.printf("ConsoleLogger [%s]: %s%n", level, MessageFormat.format(format, params)); } }

Нашият клас ConsoleLogger отменя четирите споменати метода. Методът getName () връща String, докато методът isLoggable () връща true във всички случаи. И накрая, имаме метода 2 log () , който извежда към конзолата.

2.2. Създаване на LoggerFinder

След като създадем нашия регистратор, трябва да внедрим LoggerFinder, който създава екземпляри на нашия ConsoleLogger .

За целта трябва да разширим абстрактния клас System.LoggerFinder и да приложим метода getLogger () :

public class CustomLoggerFinder extends System.LoggerFinder { @Override public System.Logger getLogger(String name, Module module) { return new ConsoleLogger(); } }

В този случай ние винаги връщаме нашия ConsoleLogger .

И накрая, трябва да регистрираме LoggerFinder като услуга, за да може да бъде открит от JDK . Ако не предоставим изпълнение, SimpleConsoleLogger ще се използва по подразбиране.

Механизмът, използван от JDK за зареждане на реализациите, е ServiceLoader . Можете да намерите повече информация за това в този урок.

Тъй като използваме Java 9, ще опаковаме класа си в модул и ще регистрираме нашата услуга във файла module-info.java :

module com.baeldung.logging { provides java.lang.System.LoggerFinder with com.baeldung.logging.CustomLoggerFinder; exports com.baeldung.logging; }

За повече информация относно модулите Java вижте този друг урок.

2.3. Тестване на нашия пример

За да тестваме нашия пример, нека създадем друг модул, който ще действа като приложение. Това ще съдържа само основния клас, който използва нашата реализация на услугата.

Този клас ще получи екземпляр на нашия ConsoleLogger, като извика метода System.getLogger () :

public class MainApp { private static System.Logger LOGGER = System.getLogger("MainApp"); public static void main(String[] args) { LOGGER.log(Level.ERROR, "error test"); LOGGER.log(Level.INFO, "info test"); } }

Вътрешно JDK ще вземе нашата реализация на CustomLoggerFinder и ще създаде екземпляр на нашия ConsoleLogger.

След това нека създадем файл с информация за модула за този модул:

module com.baeldung.logging.app { }

На този етап структурата на нашия проект ще изглежда така:

├── src │   ├── modules │   │   ├── com.baeldung.logging │   │   │   ├── com │   │   │   │   └── baeldung │   │   │   │   └── logging │   │   │   │   ├── ConsoleLogger.java │   │   │   │   └── CustomLoggerFinder.java │   │   │   └── module-info.java │   │   ├── com.baeldung.logging.app │   │   │   ├── com │   │   │   │   └── baeldung │   │   │   │   └── logging │   │   │   │   └── app │   │   │   │   └── MainApp.java │   │   │   └── module-info.java └──

Накрая ще компилираме нашите два модула и ще ги поставим в директория за модове :

javac --module-path mods -d mods/com.baeldung.logging \ src/modules/com.baeldung.logging/module-info.java \ src/modules/com.baeldung.logging/com/baeldung/logging/*.java javac --module-path mods -d mods/com.baeldung.logging.app \ src/modules/com.baeldung.logging.app/module-info.java \ src/modules/com.baeldung.logging.app/com/baeldung/logging/app/*.java

И накрая, нека стартираме главния клас на модула на приложението :

java --module-path mods \ -m com.baeldung.logging.app/com.baeldung.logging.app.MainApp

Ако погледнем изхода на конзолата, можем да видим, че дневниците ни се отпечатват с помощта на ConsoleLogger :

ConsoleLogger [ERROR]: error test ConsoleLogger [INFO]: info test

3. Добавяне на външна рамка за регистриране

В предишния ни пример регистрирахме всичките си съобщения в конзолата, което е същото като това, което прави регистраторът по подразбиране. Едно от най-полезните приложения на API за регистриране в Java 9 е да позволи на приложенията да насочват регистрационните файлове JDK към същата система за регистриране, която приложението използва , и това ще направим в този раздел.

Ще създадем нов модул, който използва SLF4J като фасада за регистриране и Logback като рамка за регистриране.

Тъй като вече обяснихме основите в предишния раздел, сега можем да се съсредоточим върху това как да добавим външна рамка за регистриране.

3.1. Персонализирани реализации, използващи SLF4J

На първо място, ние ще приложи друг Logger , че ще създаде нова SLF4J дървар за всеки отделен случай:

public class Slf4jLogger implements System.Logger { private final String name; private final Logger logger; public Slf4jLogger(String name) { this.name = name; logger = LoggerFactory.getLogger(name); } @Override public String getName() { return name; } //... }

Забележете, че това Logger е org.slf4j.Logger .

За останалите методи ще разчитаме на внедряването на екземпляра на регистратор SLF4J . Затова нашата Logger ще бъде активирана, ако дървар SLF4J е разрешено:

@Override public boolean isLoggable(Level level) { switch (level) { case OFF: return false; case TRACE: return logger.isTraceEnabled(); case DEBUG: return logger.isDebugEnabled(); case INFO: return logger.isInfoEnabled(); case WARNING: return logger.isWarnEnabled(); case ERROR: return logger.isErrorEnabled(); case ALL: default: return true; } }

И методите на регистрацията ще извикат подходящия метод на регистратор SLF4J в зависимост от използваното ниво на регистрационния файл:

@Override public void log(Level level, ResourceBundle bundle, String msg, Throwable thrown) { if (!isLoggable(level)) { return; } switch (level) { case TRACE: logger.trace(msg, thrown); break; case DEBUG: logger.debug(msg, thrown); break; case INFO: logger.info(msg, thrown); break; case WARNING: logger.warn(msg, thrown); break; case ERROR: logger.error(msg, thrown); break; case ALL: default: logger.info(msg, thrown); } } @Override public void log(Level level, ResourceBundle bundle, String format, Object... params) { if (!isLoggable(level)) { return; } String message = MessageFormat.format(format, params); switch (level) { case TRACE: logger.trace(message); break; // ... // same as the previous switch } }

И накрая, нека създадем нов LoggerFinder, който използва нашия Slf4jLogger :

public class Slf4jLoggerFinder extends System.LoggerFinder { @Override public System.Logger getLogger(String name, Module module) { return new Slf4jLogger(name); } }

3.2. Module Configuration

Once we have all our classes implemented, let's register our service in our module and add the dependency of the SLF4J module:

module com.baeldung.logging.slf4j { requires org.slf4j; provides java.lang.System.LoggerFinder with com.baeldung.logging.slf4j.Slf4jLoggerFinder; exports com.baeldung.logging.slf4j; }

This module will have the following structure:

├── src │   ├── modules │   │   ├── com.baeldung.logging.slf4j │   │   │   ├── com │   │   │   │   └── baeldung │   │   │   │   └── logging │   │   │   │   └── slf4j │   │   │   │   ├── Slf4jLoggerFinder.java │   │   │   │   └── Slf4jLogger.java │   │   │   └── module-info.java └──

Now we can compile this module into the mods directory as we did in the previous section.

Notice that we have to place the slf4j-api jar in the mods directory to compile this module. Also, keep in mind to use a modularized version of the library. The latest version can be found in Maven Central.

3.3. Adding Logback

We're almost done, but we still need to add the Logback dependencies and configuration. To do so, place the logback-classic and logback-core jars in the mods directory.

As before, we have to make sure we're using a modularized version of the library. Again, the latest version can be found in Maven Central.

Finally, let's create a Logback configuration file and place it in our mods directory:

    %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} -- %msg%n       

3.4. Running Our Application

At this point, we can run our app using our SLF4J module.

In this case, we also need to specify our Logback configuration file:

java --module-path mods \ -Dlogback.configurationFile=mods/logback.xml \ -m com.baeldung.logging.app/com.baeldung.logging.app.MainApp

Finally, if we check the output we can see that our logs are printed using our Logback configuration:

2018-08-25 14:02:40 [main] ERROR MainApp -- error test 2018-08-25 14:02:40 [main] INFO MainApp -- info test

4. Conclusion

В тази статия показахме как да създадем потребителски регистратор в Java 9 с помощта на новия API за регистриране на платформа. Освен това внедрихме пример, използвайки външна рамка за регистриране, която е един от най-полезните случаи на използване на този нов API.

Както винаги, пълният изходен код на примерите е достъпен в GitHub.