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

后端 未结 8 2027
太阳男子
太阳男子 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:42

    I resolved it with a custom BeanFactory. If anyone comes up with a better solution, I would be happy to hear it. Anyway, here's the bean factory:

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

    Example usage with an XML config:

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

    EDIT:

    Below you can find Arend v. Reinersdorffs improved version (see the comments for an explanation).

    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 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.");
        }
    }
    

提交回复
热议问题