简体   繁体   English

Spring - 在获得 @Autowired 之前将字段注入 bean

[英]Spring - Inject fields to bean before it gets @Autowired

In Spring, is there a mechanism or listener to detect when a bean annotated with a specific annotation is getting @Autowired and run some custom logic on it?在 Spring 中,是否有一种机制或侦听器来检测带有特定注释的 bean 何时获得@Autowired并在其上运行一些自定义逻辑? Something similar to what @ConfigurationProperties already does that automatically injects fields before it gets autowired.类似于@ConfigurationProperties已经做的事情,它会在自动装配之前自动注入字段。

I have a requirement in which I need to inject values to fields of certain beans annotated with @ExampleAnnotation before they get instantiated.我有一个要求,我需要在实例化之前将值注入到使用@ExampleAnnotation注释的某些 bean 的字段中。 Ideally, in this listener, I would:理想情况下,在这个听众中,我会:

  1. Ask if current bean being instantiated is annotated with @ExampleAnnotation询问当前被实例化的 bean 是否用@ExampleAnnotation注释
  2. If it isn't, return.如果不是,请返回。 If it is, I'd use reflection to get the names of the fields from this bean and populate them using a repository.如果是,我会使用反射从这个 bean 中获取字段的名称,并使用存储库填充它们。

Is something like this possible?这样的事情可能吗?

You can achive it with the following code:您可以使用以下代码实现它:

@Component
class MyBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {

    private ApplicationContext applicationContext;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
      // Every spring bean will visit here

      // Check for superclasses or interfaces
      if (bean instanceof MyBean) {
        // do your custom logic here
        bean.setXyz(abc);
        return bean;
      }
      // Or check for annotation using applicationContext
      MyAnnotation myAnnotation = this.applicationContext.findAnnotationOnBean(beanName, MyAnnotation.class);
      if (myAnnotation != null) {
        // do your custom logic here
        bean.setXyz(myAnnotation.getAbc());
        return bean;
      }
      return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
    
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = applicationContext;
    }

    // Optional part. If you want to use Autowired inside BeanPostProcessors 
    // you can use Lazy annotation. Otherwise they may skip bean processing
    @Lazy
    @Autowired
    public MyBeanPostProcessor(MyLazyAutowiredBean myLazyAutowiredBean) {
    }
}

I guess if it's similar to ConfigurationProperties , then the class ConfigurationPropertiesBindingPostProcessor that binds properties to beans may serve as an example.我猜如果它类似于ConfigurationProperties ,那么将属性绑定到 bean 的 class ConfigurationPropertiesBindingPostProcessor可以作为示例。 It implements BeanPostProcessor and does the binding in the postProcessBeforeInitialization method.它实现BeanPostProcessor并在postProcessBeforeInitialization方法中进行绑定。 This method has the following Javadocs:此方法具有以下 Javadocs:

" Apply this BeanPostProcessor to the given new bean instance before any beaninitialization callbacks (like InitializingBean's afterPropertiesSetor a custom init-method). The bean will already be populated with property values.The returned bean instance may be a wrapper around the original. " 在任何 beaninitialization 回调之前将此 BeanPostProcessor 应用于给定的新 bean 实例(如 InitializingBean 的 afterPropertiesSetor 自定义 init 方法)。bean 将已填充属性值。返回的 bean 实例可能是原始的包装器。

One possible solution is to write a custom setter and annotate it with @Autowired, like this:一种可能的解决方案是编写一个自定义设置器并使用@Autowired 对其进行注释,如下所示:

@Autowired
public void setExample(Example example)
{

    // Do your stuff here.

    this.example = example;
}

However, I don't recommend this practice of modifying a bean before autowiring since it can lead to poor code mantainability and it may be counter-intuitive for other people that need to work on your code too.但是,我不推荐这种在自动装配之前修改 bean 的做法,因为它会导致代码的可维护性差,并且对于其他需要处理您的代码的人来说,这可能是违反直觉的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM