Spring DI中与CDI的InjectionPoint相当的是什么?

16

我想创建一个Spring的bean生成方法,该方法能意识到调用它的对象,因此我已经编写了以下代码:

@Configuration
public class LoggerProvider {

    @Bean
    @Scope("prototype")
    public Logger produceLogger() {
        // get known WHAT bean/component invoked this producer 
        Class<?> clazz = ...

        return LoggerFactory.getLogger(clazz);
    }
}

如何获取想要注入bean的的信息?

我正在寻找Spring世界中类似于CDI的InjectionPoint的等效物。

2个回答

26

Spring 4.3.0使得bean生成方法可以使用InjectionPoint和DependencyDescriptor参数:

@Configuration
public class LoggerProvider {

    @Bean
    @Scope("prototype")
    public Logger produceLogger(InjectionPoint injectionPoint) {
        Class<?> clazz = injectionPoint.getMember().getDeclaringClass();

        return LoggerFactory.getLogger(clazz);
    }
}

顺便说一下,这个功能的问题 SPR-14033 链接到博客评论,该评论链接到此问题。


如果我将这个东西注入到另一个作用域也为 prototype 的 bean 中,那么这不会为该 bean 的每个实例创建一个日志记录器,而是共享一个单独的静态实例吗? - Rupert Madden-Abbott
1
@RupertMadden-Abbott 日志框架通常会缓存记录器。例如,可以查看有关SLF4J日志框架的此问题:在静态和非静态上下文中创建SLF4J记录器的开销是多少? - Arend v. Reinersdorff

8
据我所知,Spring框架中没有这样的概念。
那么唯一知道已处理点的东西就是BeanPostProcessor

例子:

@Target(PARAMETER)
@Retention(RUNTIME)
@Documented
public @interface Logger {}

public class LoggerInjectBeanPostProcessor implements BeanPostProcessor {   
    public Logger produceLogger() {
        // get known WHAT bean/component invoked this producer
        Class<?> clazz = ...    
        return LoggerFactory.getLogger(clazz);
    }


    @Override
    public Object postProcessBeforeInitialization(final Object bean,
            final String beanName) throws BeansException {
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(final Object bean,
            final String beanName) throws BeansException {

        ReflectionUtils.doWithFields(bean.getClass(),
                new FieldCallback() {
                     @Override
                     public void doWith(final Field field) throws IllegalArgumentException, IllegalAccessException {
                         field.set(bean, produceLogger());
                     }
                },
                new ReflectionUtils.FieldFilter() {
                     @Override
                     public boolean matches(final Field field) {
                          return field.getAnnotation(Logger.class) != null;
                     }
                });

        return bean;
    }
}

谢谢 Ralph!好的,所以这个 BeanPostProcessor 在任何地方注入任何 bean 时都会被调用。有没有办法我可以识别要注入的 哪个 bean?我的意思是,我得到了:postProcessBeforeInitialization(Object bean, String beanName),其中 bean 是想要进行注入的 bean(我在问题中提出的 who 部分),而 beanNamebean 的名称。现在我不知道 bean 中的哪个字段需要进行注入 - 换句话说,我不知道注入的 bean 是 LoggerProvider 还是其他什么东西。 - Piotr Nowicki
据我所了解,后置处理器是在创建bean之后调用的!(不会注入到任何地方)。这个想法是在bean后置处理器的基础上实现自己的小型注入框架。 - Ralph
好的,所以BeanPostProcessor实现者将在每次创建bean时被调用。因此,您的想法是实现postProcessBeforeInitialization并扫描具有我的自定义注释(比如说@Logger)的字段,并通过反射使用自己的自定义逻辑初始化这样的字段。这是您的方法还是我把它复杂化了?再次感谢! - Piotr Nowicki
1
@Piotr Nowicki:是的,但这真的很容易,而且工作量不大。请参阅我添加的示例。(我尚未测试过该代码,但它应该让您了解扩展Spring有多容易以及Spring Utils有多强大。) - Ralph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接