Wtrysk sprężynowy rejestratora SLF4J-jak uzyskać klasę docelową wtrysku?

Próbuję użyć Springa, aby wstrzyknąć Logger SLF4J do takiej klasy:

@Component
public class Example {

  private final Logger logger;

  @Autowired
  public Example(final Logger logger) {
    this.logger = logger;
  }
}

Znalazłem FactoryBean klasę, którą wdrożyłem. Ale problem polega na tym, że nie mogę uzyskać żadnych informacji o celu wstrzyknięcia:

public class LoggingFactoryBean implements FactoryBean<Logger> {

    @Override
    public Class<?> getObjectType() {
        return Logger.class;
    }  

    @Override
    public boolean isSingleton() {  
        return false;
    }

    @Override
    public Logger getObject() throws Exception {
        return LoggerFactory.getLogger(/* how do I get a hold of the target class (Example.class) here? */);
    }
}   
Czy FactoryBean jest w ogóle właściwą drogą? Podczas stosowania pikokontynentów wstrzyknięcie fabryczne , otrzymujesz Type celu przekazanego. W guice jest to nieco trudniejsze. Ale jak to osiągnąć wiosną?
Author: skaffman, 2010-06-14

8 answers

Oto alternatywa dla Twojego rozwiązania. Możesz osiągnąć swój cel z BeanFactoryPostProcessor wdrożenie.

Załóżmy, że chcesz mieć klasę z logowaniem. Tutaj jest:

  package log;
  import org.apache.log4j.Logger;

  @Loggable
  public class MyBean {

     private Logger logger;
  }

Jak widać ta klasa nic nie robi i została stworzona tylko po to, aby być kontenerem loggera dla uproszczenia. Jedyną niezwykłą rzeczą jest @Loggable adnotacja. Tutaj jego kod źródłowy:

package log;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Loggable {
}

Ta adnotacja jest tylko znacznikiem dla dalszych przetwarzam. A oto najciekawsza część:

package log;

import org.apache.log4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;

import java.lang.reflect.Field;

public class LoggerBeanFactoryPostProcessor implements BeanFactoryPostProcessor{

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] names = beanFactory.getBeanDefinitionNames();
        for(String name : names){
            Object bean = beanFactory.getBean(name);
            if(bean.getClass().isAnnotationPresent(Loggable.class)){
                try {
                    Field field = bean.getClass().getDeclaredField("logger");
                    field.setAccessible(true);
                    field.set(bean, Logger.getLogger(bean.getClass()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
Jeśli fasola jest oznaczona jako @ Loggable , inicjalizuje swoje prywatne pole nazwą logger. Możesz pójść jeszcze dalej i przekazać niektóre parametry w adnotacji @ Loggable . Na przykład może to być nazwa pola odpowiadająca loggerowi.

Użyłem Log4j w tym przykładzie, ale myślę, że powinno działać dokładnie tak samo z slf4j.

 20
Author: wax,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 19:38:44

Rozwiązałem to za pomocą niestandardowej fabryki fasoli. Jeśli ktoś wymyśli lepsze rozwiązanie, chętnie to usłyszę. W każdym razie, tutaj jest fabryka fasoli:

import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;

public class CustomBeanFactory extends DefaultListableBeanFactory {

    public CustomBeanFactory() {
    }

    public CustomBeanFactory(DefaultListableBeanFactory delegate) {
        super(delegate);
    }

    @Override
    public Object resolveDependency(DependencyDescriptor descriptor,
            String beanName, Set<String> autowiredBeanNames,
            TypeConverter typeConverter) throws BeansException {
        //Assign Logger parameters if required      
        if (descriptor.isRequired()
                && Logger.class.isAssignableFrom(descriptor
                        .getMethodParameter().getParameterType())) {            
            return LoggerFactory.getLogger(descriptor.getMethodParameter()
                    .getDeclaringClass());
        } else {
            return super.resolveDependency(descriptor, beanName,
                    autowiredBeanNames, typeConverter);
        }
    }
}

Przykładowe użycie z konfiguracją XML:

        CustomBeanFactory customBeanFactory = new CustomBeanFactory();      
        GenericApplicationContext ctx = new GenericApplicationContext(customBeanFactory);
        XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
        xmlReader.loadBeanDefinitions(new ClassPathResource("beans.xml"));
        ctx.refresh();

EDIT:

Poniżej znajduje się ulepszona wersja Arend V. Reinersdorffs (wyjaśnienie w komentarzach).

import java.lang.reflect.Field;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.TypeConverter;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.core.MethodParameter;

public class CustomBeanFactory extends DefaultListableBeanFactory {

    public CustomBeanFactory() {
    }

    public CustomBeanFactory(DefaultListableBeanFactory delegate) {
        super(delegate);
    }

    @Override
    public Object resolveDependency(DependencyDescriptor descriptor,
            String beanName, Set<String> autowiredBeanNames,
            TypeConverter typeConverter) throws BeansException {
        //Assign Logger parameters if required      
        if (Logger.class == descriptor.getDependencyType()) {            
            return LoggerFactory.getLogger(getDeclaringClass(descriptor));
        } else {
            return super.resolveDependency(descriptor, beanName,
                    autowiredBeanNames, typeConverter);
        }
    }

    private Class<?> getDeclaringClass(DependencyDescriptor descriptor) {
        MethodParameter methodParameter = descriptor.getMethodParameter();
        if (methodParameter != null) {
            return methodParameter.getDeclaringClass();
        }
        Field field = descriptor.getField();
        if (field != null) {
            return field.getDeclaringClass();
        }
        throw new AssertionError("Injection must be into a method parameter or field.");
    }
}
 10
Author: Alexander Torstling,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-10-02 13:49:06

Aby zwiększyć świadomość kodu użyj InjectionPoint, Aby zdefiniować loggery, tzn.:

@Bean
@Scope("prototype")
public Logger logger(InjectionPoint ip) {
    return Logger.getLogger(ip.getMember().getDeclaringClass());
}

@Scope("prototype") jest tu potrzebny do utworzenia instancji' logger ' bean za każdym razem, gdy metoda jest wywoływana.

 4
Author: magiccrafter,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-01-16 16:48:59

Spróbuj czegoś takiego:

@Component
public class Example {

  @Autowired
  @Qualifier("exampleLogger")
  private final Logger logger;

}

I:

<bean id="exampleLogger" class="org.slf4j.LoggerFactory" factory-method="getLogger">
  <constructor-arg type="java.lang.Class" value="package.Example"/>        
</bean>
 2
Author: Adolfo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-24 14:34:11
  1. Dlaczego tworzysz nowy rejestrator dla każdej instancji? Typowym wzorcem jest posiadanie jednego loggera na klasę (jako prywatnego członka statycznego).

  2. Jeśli naprawdę chcesz to zrobić w ten sposób: może możesz napisać klasę logger factory i to wstrzyknąć? Coś w stylu:

    @Singleton 
    public class LogFactory { 
        public Logger getLogger(Object o) {  
            return LoggerFactory.getLogger(o.getClass());  
        }  
    }
    
 0
Author: Mike Baranczak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-14 23:27:11

Idziesz w złym kierunku. Na Twoim miejscu wstrzyknąłbym LoggerFactory. Jeśli chcesz ukryć, że jest to slf4j, zdefiniowałbym interfejs LoggerFactory i wstrzyknął klasę, która deleguje do loggera slf4j.

public interface LoggerFactory {
    public Logger getLogger(Class<?> clazz);
}
...
import org.slf4j.LoggerFactory;
public class Slf4jLoggerFactory implements LoggerFactory {
    public Logger getLogger(Class<?> clazz) {
        return org.slf4j.LoggerFactory.getLogger(clazz);
    }
}

Jednak zanim tam pójdziesz, To jest w przybliżeniu to, co org.Apacz.commons.logowanie jest dobre? http://commons.apache.org/logging/

Używasz logów zamiast loggerów:

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public class CLASS {
    private Log log = LogFactory.getLog(CLASS.class);
    ...

Apache następnie patrzy przez classpath, aby sprawdzić, czy masz log4j lub inne i deleguje do "najlepszego", który znajduje. Slf4j zastępuje log4j w ścieżce klasowej, więc jeśli masz go załadowanego (i Apache log4j wykluczony), logowanie commons będzie delegować do niego.

 0
Author: Gray,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-06-15 00:37:31

Od wiosny 4.3.0 można używać InjectionPoint lub DependencyDescriptor jako parametrów metod produkcji fasoli:

@Component
public class LoggingFactoryBean {
    @Bean
    public Logger logger(InjectionPoint injectionPoint) {
        Class<?> targetClass = injectionPoint.getMember().getDeclaringClass();
        return LoggerFactory.getLogger(targetClass);
    }
}
 0
Author: Arend v. Reinersdorff,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-11 15:06:32

Próbuję wprowadzić tę funkcję do oficjalnego API SLF4J. Proszę o wsparcie/głosowanie / wkład: https://issues.jboss.org/browse/JBLOGGING-62

(Ta funkcja jest już zaimplementowana przez JBoss Logging + Seam Solder, zobacz http://docs.jboss.org/seam/3/latest/reference/en-US/html/solder-logging.html )

11.4. Native logger API

Możesz również wprowadzić" zwykły stary " Logger (z interfejsu JBoss Logging API):

import javax.inject.Inject;
import org.jboss.logging.Logger;

public class LogService {

    @Inject
    private Logger log;

    public void logMessage() {
        log.info("Hey sysadmins!");
    }

}

Tworzenie logów od tego Loggera będzie miała kategorię (nazwa loggera) równą w pełni kwalifikowanej nazwie klasy implementacji bean. Kategorię można określić jawnie za pomocą adnotacji.

@Inject @Category("billing")
private Logger log;

Możesz również określić kategorię używając odniesienia do typu:

@Inject @TypedCategory(BillingService.class)
private Logger log;

Przepraszamy za Brak odpowiedzi.

 -2
Author: Hendy Irawan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-04-18 11:25:43