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ą? 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.
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.");
}
}
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.
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>
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
Dlaczego tworzysz nowy rejestrator dla każdej instancji? Typowym wzorcem jest posiadanie jednego loggera na klasę (jako prywatnego członka statycznego).
-
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()); } }
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.
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);
}
}
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.
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