Spring constructor injection of SLF4J logger - how to get injection target class?

后端 未结 8 2010
太阳男子
太阳男子 2020-12-25 15:20

I\'m trying to use Spring to inject a SLF4J logger into a class like so:

@Component
public class Example {

  private final Logger logger;

  @Autowired
  pu         


        
8条回答
  •  伪装坚强ぢ
    2020-12-25 15:34

    Here is an alternative to your solution. You could achieve your goal with BeanFactoryPostProcessor implementation.

    Let's assume you want to have a class with logging. Here it is:

      package log;
      import org.apache.log4j.Logger;
    
      @Loggable
      public class MyBean {
    
         private Logger logger;
      }
    

    As you could see this class does nothing and created just to be a logger container for simplicity. The only remarkable thing here is @Loggable annotation. Here its source code:

    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 {
    }
    

    This annotation is only a marker for further processing. And here is a most interesting part:

    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();
                    }
                }
            }
        }
    }
    

    It searches through all beans, and if a bean is marked as @Loggable, it initialize its private field with name logger. You could go even further and pass some parameters in @Loggable annotation. For example, it could be a name of field corresponding to logger.

    I used Log4j in this example, but I guess it should work exactly the same way with slf4j.

提交回复
热议问题