【问题标题】:Spring - Inject fields to bean before it gets @AutowiredSpring - 在获得@Autowired之前将字段注入bean
【发布时间】:2021-04-24 02:23:00
【问题描述】:

在 Spring 中,是否有一种机制或侦听器来检测带有特定注解的 bean 何时获得 @Autowired 并在其上运行一些自定义逻辑?类似于 @ConfigurationProperties 已经做的事情,它会在自动连接之前自动注入字段。

我有一个要求,我需要在实例化之前将值注入到带有 @ExampleAnnotation 注释的某些 bean 的字段中。理想情况下,在这个听众中,我会:

  1. 询问当前正在实例化的 bean 是否用 @ExampleAnnotation 注释
  2. 如果不是,请返回。如果是,我会使用反射从这个 bean 中获取字段的名称并使用存储库填充它们。

这样的事情可能吗?

【问题讨论】:

    标签: java spring spring-boot autowired


    【解决方案1】:

    我猜如果它类似于ConfigurationProperties,那么将属性绑定到bean 的类ConfigurationPropertiesBindingPostProcessor 可以作为示例。它实现BeanPostProcessor 并在postProcessBeforeInitialization 方法中进行绑定。此方法具有以下 Javadocs:

    "在任何 beaninitialization 回调之前将此 BeanPostProcessor 应用于给定的新 bean 实例(如 InitializingBean 的 afterPropertiesSetor 自定义 init 方法)。bean 将已填充属性值。返回的 bean 实例可能是一个包装器原件。"

    【讨论】:

    • Spring 如何知道在遇到带有@ConfigurationProperties 注释的类时运行ConfigurationPropertiesBindingPostProcessor
    • ConfigurationPropertiesBindingPostProcessor 将检查 bean 以查看它是否带有 ConfigurationProperties 注释。如果是,它会进行绑定。至于它是如何注册的,BeanPostProcessor 的 Javadoc 说 ApplicationContext 可以在其 bean 定义中自动检测 BeanPostProcessor bean 并将这些后处理器应用于随后创建的任何 bean”。也可以使用EnableConfigurationProperties 注册。 This tutorial 显示了一个示例。
    【解决方案2】:

    一种可能的解决方案是编写一个自定义设置器并使用@Autowired 对其进行注释,如下所示:

    @Autowired
    public void setExample(Example example)
    {
    
        // Do your stuff here.
    
        this.example = example;
    }
    

    但是,我不推荐这种在自动装配之前修改 bean 的做法,因为它会导致代码的可维护性差,并且对于其他需要处理您的代码的人来说可能是违反直觉的。

    【讨论】:

      【解决方案3】:

      您可以使用以下代码实现它:

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

      【讨论】:

      • 这看起来很有希望,但是,this.applicationContext.findAnnotationOnBean(beanName, MyAnnotation.class); 在构建过程中会引起各种麻烦。 stacktrace 太大,无法放在这里,但它与Cannot create inner bean... 相关,并且依赖项不满足。 findAnnotationOnBean 是否有任何可能导致这种情况发生的副作用?当我评论该行时,项目会正确构建。
      • 它对我有用。您不必使用应用程序上下文来查找类上的注释。还有其他实用程序类,例如org.springframework.core.annotation.AnnotationUtils
      • 可能是由 Spring Data JPA 的一些魔法引起的。我改用getClass().getAnnotation(MyAnnotation.class) 并且它有效。这正是我想要的。谢谢!
      猜你喜欢
      • 2019-08-11
      • 2019-04-26
      • 2011-04-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      • 2015-08-02
      相关资源
      最近更新 更多