Wie komme ich in Spring Logger

    Bei der Entwicklung von Anwendungen mit dem Spring-IoC-Container haben sich alle gefragt, wie ein Logger „korrekter und schöner“ erstellt werden kann. In dieser Veröffentlichung möchte ich einige Beispiele zur Lösung dieses Problems geben.

    Lösung 1


    Wir bekommen den Logger direkt über LoggerFactory:
    @Component
    public class MyBean {
        private static final Logger log = LoggerFactory.getLogger("application");
        ...
    }
    

    Diese Lösung ist klassisch, funktioniert sicherlich, verstößt jedoch gegen die IoC-Ideologie selbst, da der Container selbst die Arbeit an der Erstellung des Loggers abschließen soll.

    Entscheidung 2


    Wir holen den Logger mit Autowired aus dem Container:
    @Component
    public class MyBean {
        @Autowired
        private Logger log;
        ...
    }
    

    Dazu deklarieren Sie eine Bean in der Spring-Konfiguration:
    @EnableAutoConfiguration
    @ComponentScan
    public class ApplicationConfiguration {
        @Bean
        public Logger logger(){
            return LoggerFactory.getLogger("application");
        }
    ...
    }
    

    In dieser Lösung wird die Aufgabe zum Erstellen eines Protokollierers dem Container selbst zugewiesen und passt zur Ideologie von IoC. Was sollten Sie jedoch tun, wenn die Anwendung mehr als einen Protokollierer enthalten sollte?

    Entscheidung 3


    Wir deklarieren jeden Logger als separate Bean:
    @EnableAutoConfiguration
    @ComponentScan
    public class ApplicationConfiguration {
        @Bean
        @Primary
        public Logger logger(){
            return LoggerFactory.getLogger("application");
        }
        @Bean(name = "loggerBean")
        public Logger loggerBean(){
            return LoggerFactory.getLogger("loggerBean");
        }
    ...
    }
    

    Wir erhalten den gewünschten Logger mit dem entsprechenden Qualifier:
    @Component
    public class MyBean {
        @Autowired
        private Logger log;
        @Autowired
        @Qualifier("loggerBean")
        private Logger log2;
        ...
    }
    

    Diese Lösung ist in den meisten Fällen ausreichend und verwendet nur die fertigen Mittel des Behälters. Einer der Nachteile dieser Lösung ist, dass Sie beim Hinzufügen eines neuen Loggers immer eine neue Bean deklarieren müssen. Gibt es einen universelleren Weg?

    Entscheidung 4


    Wir holen den Logger mit einer speziellen Annotation aus dem Container, nennen wir ihn Logging:
    @Component
    public class MyBean {
        @Logging
        private Logger log;
        @Logging("loggerBean")
        private Logger log2;
        ...
    }
    

    Dazu ist es eigentlich notwendig, eine Anmerkung zu deklarieren:
    @Target({ElementType.FIELD})
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Logging {
        String value();
    }
    

    Diese Annotation zeigt dem Container an, dass ein Logger mit dem an den value-Parameter übergebenen Namen erforderlich ist. Wenn dieser Parameter nicht angegeben wird, wird der Logger von der Komponentenklasse abgerufen, in unserem Fall MyBean.
    Großartig, aber der Container kann unsere Anmerkung nicht verarbeiten. Lassen Sie uns ihm beibringen, wie man einen Prozessor erstellt:
    public class LoggingAnnotationProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) {
            Class clazz = bean.getClass();
            do {
                for (Field field : clazz.getDeclaredFields()) {
                    Logging annotation = field.getAnnotation(Logging.class); 
                    if (annotation!= null) {
                        boolean accessible = field.isAccessible();
                        field.setAccessible(true);
                        try {
                            if(!annotation.value().isEmpty()){
                                field.set(bean, LoggerFactory.getLogger(annotation.value()));
                            } else {
                                field.set(bean, LoggerFactory.getLogger(clazz));
                            }
                        } catch (IllegalAccessException e) {
                            LoggerFactory.getLogger(this.getClass()).error(e.getMessage(), e);
                        }
                        field.setAccessible(accessible);
                    }
                }
                clazz = clazz.getSuperclass();
            } while (clazz != null);
            return bean;
        }
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) {
            return bean;
        }
    }
    

    Und deklarieren Sie den Prozessor in der Spring-Konfiguration:
    @EnableAutoConfiguration
    @ComponentScan
    public class ApplicationConfiguration {
        @Bean
        public LoggingAnnotationProcessor loggingAnnotationProcessor(){
            return new LoggingAnnotationProcessor();
        }
    ...
    }
    

    Diese Lösung ist universeller, aber Sie müssen zusätzlich eine Anmerkung deklarieren und einen Prozessor dafür schreiben.

    Fazit


    Freunde, schlagen Sie in den Kommentaren Ihre Möglichkeiten zur Lösung dieses Problems vor, ich werde mich sehr freuen!

    Beispielquellcode auf GitHub verfügbar

    Jetzt auch beliebt: