Ale*_*ing 15 java spring slf4j constructor-injection
我正在尝试使用Spring将SLF4J记录器注入类中,如下所示:
@Component
public class Example {
private final Logger logger;
@Autowired
public Example(final Logger logger) {
this.logger = logger;
}
}
Run Code Online (Sandbox Code Playgroud)
我找到了这个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? */);
}
}
Run Code Online (Sandbox Code Playgroud)
FactoryBean甚至是正确的方法吗?当使用picocontainers 工厂注入时,你会得到Type
传入的目标.在guice中它有点棘手.但是你如何在Spring中实现这一目标?
wax*_*wax 20
这是您的解决方案的替代方案.您可以使用BeanFactoryPostProcessor实现来实现您的目标.
假设你想要一个带日志的类.这里是:
package log;
import org.apache.log4j.Logger;
@Loggable
public class MyBean {
private Logger logger;
}
Run Code Online (Sandbox Code Playgroud)
正如你所看到的,这个类什么都不做,只是为了简单而创建了一个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 {
}
Run Code Online (Sandbox Code Playgroud)
此注释仅是进一步处理的标记.这是一个最有趣的部分:
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();
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
它搜索所有bean,如果bean被标记为@Loggable,它会使用名称logger初始化其私有字段.您可以更进一步,并在@Loggable注释中传递一些参数.例如,它可以是与记录器对应的字段的名称.
我在这个例子中使用了Log4j,但我想它应该与slf4j完全相同.
Ale*_*ing 10
我用自定义BeanFactory解决了它.如果有人想出更好的解决方案,我会很高兴听到它.无论如何,这是豆工厂:
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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
XML配置的示例用法:
CustomBeanFactory customBeanFactory = new CustomBeanFactory();
GenericApplicationContext ctx = new GenericApplicationContext(customBeanFactory);
XmlBeanDefinitionReader xmlReader = new XmlBeanDefinitionReader(ctx);
xmlReader.loadBeanDefinitions(new ClassPathResource("beans.xml"));
ctx.refresh();
Run Code Online (Sandbox Code Playgroud)
编辑:
您可以在下面找到Arend v.Reinersdorffs的改进版本(请参阅注释以获得解释).
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.");
}
}
Run Code Online (Sandbox Code Playgroud)
为了使你的代码更容易Spring知道使用InjectionPoint
定义记录器,即:
@Bean
@Scope("prototype")
public Logger logger(InjectionPoint ip) {
return Logger.getLogger(ip.getMember().getDeclaringClass());
}
Run Code Online (Sandbox Code Playgroud)
@Scope("prototype")
这里需要在每次调用方法时创建'logger'bean实例.
归档时间: |
|
查看次数: |
15832 次 |
最近记录: |