SLF4J记录仪的弹簧构造器注入 - 如何获得注入目标类?

2022-09-02 19:46:33

我正在尝试使用Spring将SLF4J记录器注入到这样的类中:

@Component
public class Example {

  private final Logger logger;

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

我找到了我实现的类。但问题是我无法获得有关注射目标的任何信息:FactoryBean

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? */);
    }
}   

FactoryBean是正确的选择吗?当使用微量容器工厂注射时,您可以获得传递的目标。在guice中,它有点棘手。但是,如何在春季实现这一目标呢?Type


答案 1

下面是解决方案的替代方法。您可以通过BeanFactoryPostProcessor实现您的目标。

假设您希望有一个带有日志记录的类。在这里:

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

  @Loggable
  public class MyBean {

     private Logger logger;
  }

正如你所看到的,这个类不执行任何操作,只是为了简单起见而创建一个记录器容器。这里唯一值得注意的事情是@Loggable注释。这是它的源代码:

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

此注释只是进一步处理的标记。这是一个最有趣的部分:

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

它搜索所有 bean,如果一个 bean 被标记为@Loggable,则使用 name logger 初始化其私有字段。您可以更进一步,在注释@Loggable传递一些参数。例如,它可以是与记录器对应的字段名称。

我在此示例中使用了Log4j,但我想它应该与slf4j的工作方式完全相同。


答案 2

要使您的代码更加具有Spring意识,请使用来定义记录器,即:InjectionPoint

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

@Scope("prototype")这里需要每次调用方法时创建“记录器”Bean 实例。


推荐