Чи найкращим способом ініціалізації реєстраторів log4j є Logger.getLogger (MyClass.class)?


13

Цей підручник Мкхьонг пропонує інціалізувати реєстратори таким чином:

@Controller
public class WelcomeController {

    private static final Logger logger = Logger.getLogger(WelcomeController.class);

   // etc

}

Тепер, мабуть, кожен інший клас, який ви використовуєте, який має реєстратор, буде ініціалізувати свої реєстратори таким же чином.

Моє запитання - це найкращий спосіб зробити це? Здається ... повторюється.


2
Що ви вважаєте багатослівним щодо цього (відміняючи синтаксис Java) ?. Ви повинні створити змінну для зберігання реєстратора, і ви повинні сказати getLogger()ім'я реєстратора, щоб отримати.
kdgregory

2
@kdgregory факт, що я роблю те саме в кожному класі.
dwjohnston


3
Занадто стара міграція, але це питання тут поза темою і більше підходить для StackOverflow.
Андрес Ф.

1
@AndresF. Я думаю, що я висловлю це тут, тому що це більше питання щодо стилю коду / моделей дизайну, ніж технічного питання.
dwjohnston

Відповіді:


16

Ваш коментар говорить про те, що "багатослівний" посилається на необхідність повторення цього рядка коду в кожному класі. Моя перша відповідь полягає в тому, що у великій картині додавання двох рядків коду (змінне визначення плюс заява про імпорт) до кожного класу не така вже й велика справа. Тим більше, що вам потрібно лише додати їх до класів, які мають поведінку і тому потрібно робити журнал. При цьому специфічний рядок коду, який ви використовуєте, схильний до помилок копіювання та вставки (докладніше про це пізніше).

Але, оскільки ви хочете альтернативи, ось декілька причин, через які ви можете або не хочете їх використовувати.

Використовуйте єдиний реєстратор для всього додатка

Якщо вам не байдуже про те, який клас звітує, або ви готові вкласти весь необхідний контекст у повідомлення, ніж простий одиночний реєстратор виконає цю роботу:

LoggerSingleton.getInstance().debug("MyController is running")

На мою думку, однією з найбільших переваг системи ведення журналів є те, що контекст надається окремими екземплярами реєстратора - якщо тільки направити повідомлення журналу на різні пункти призначення. Я б не відмовився від цього, щоб зберегти один рядок коду (імпорт все ще потрібен).

Плюс це збільшує багатослівність у точці використання, що закінчиться набагато більшими натисканнями клавіш.

Створіть свої реєстратори на місці використання

Я викидаю це лише тому, що воно виключає змінну. Я не думаю, що мені це потрібно коментувати. Хоча це і показує мою бажану техніку отримання екземпляра реєстратора.

Logger.getLogger(getClass()).debug("blah blah blah");

Використовуйте післяпроцесорний квасоля для введення лісоруба

У вашому прикладі використовується Spring, а Spring дозволяє підключити код ініціалізації бобів. Ви можете створити постпроцесор, який перевіряє bean для loggerзмінної члена і створює Loggerекземпляр, коли він знаходить його.

Хоча такий постпроцесор - це лише кілька десятків рядків коду, це ще одна рухома частина у вашій програмі, а отже, ще одне потенційне джерело помилок. Я вважаю за краще мати якомога менше таких.

Використовуйте міксин

Scala та Groovy забезпечують риси , які дозволяють вам інкапсулювати поведінку. Типовою схемою Scala є створення Loggingознаки, а потім додати її до класу, який потребує реєстрації:

class MyController with Logging

На жаль, це означає, що вам доведеться перемикати мови. Якщо ви не використовуєте Java 8, тоді ви можете створити Loggingінтерфейс "методом за замовчуванням":

public interface Logging {
    default Logger getLogger() {
        return Logger.getLogger(getClass());
    } 
}

Тепер у коді класу ви можете просто використовувати

getLogger().debug("blah blah blah");

Хоча це легко, але це має кілька недоліків. З одного боку, це забруднює інтерфейс кожного класу, який ним користується, оскільки всі методи інтерфейсу є загальнодоступними. Можливо, не так вже й погано, якщо ви використовуєте його лише для класів, які інстанціюються та вводяться Spring, особливо якщо ви дотримуєтесь розділення інтерфейсу / реалізації.

Більша проблема полягає в тому, що він повинен шукати фактичний екземпляр реєстратора під час кожного виклику. Що швидко, але непотрібно.

І вам ще потрібна заява про імпорт.

Перемістіть реєстратор до суперкласу

Повторюся: я не знаходжу багаторазових визначень реєстраторів, але якщо ви вважаєте, це найкращий підхід до їх усунення.

public abstract class AbstractController {
    protected Logger logger = Logger.getLogger(getClass());
}

Тепер ваші класи контролерів успадковують AbstractControllerі вони мають доступ до loggerзмінної. Пам’ятайте, що @Controllerанотацію потрібно ставити на конкретний клас.

Деякі люди вважають це збоченням спадщини. Я намагався їх узагальнити, називаючи клас, AbstractControllerа не AbstractProjectClass. Ви можете вирішити, чи є стосунки чи ні.

Інші люди будуть заперечувати проти використання змінної екземпляра, а не статичної змінної. Статичні реєстратори IMO схильні до помилок копіювання та вставки, тому що ви повинні чітко вказати ім'я класу; getClass()гарантує, що ваш реєстратор завжди правильний.


Я думаю, вам слід бути обережними щодо getClass () у класі спадкування, MethodHandles.lookup (). LookupClass () краще після jdk 7
yuxh

@luxh - у тебе є пояснення до цього?
kdgregory

перевірте тут: stackoverflow.com/a/6653577/4652536
yuxh

@yuxh - єдина згадка про MethodHandles у тому запитанні (яке не було у відповіді, яку ви зв'язали), є аналогічним непідтримуваним твердженням із коментарем із проханням пояснити. Чи є у вас авторитетна підтримка твердження, яке MethodHandles.lookup().lookupClass()краще, ніж Object.getClass()?
kdgregory

MethodHandles.lookup().lookupClass()може використовуватися для статичних змінних, не схильний до помилок копіювання та вставки, і це швидко: stackoverflow.com/a/47112323/898747 Це означає додатковий вклад, але мені дуже подобається, що мої реєстратори стають статичними, тому принаймні варто згадка :)
FableBlaze

0

Щоб розширити відповідь, надану @kdgregory, Groovy надає @Slf4j( groovy.util.logging.Slf4j) поза полем як анотацію, яка виконує перетворення AST в класі, щоб приєднати його до реєстратора, який приймає ім'я змінної logза замовчуванням, якщо її не вказано.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.