Spring - 在 bean 获取 @Autowired 之前将字段注入到 bean
Spring - Inject fields to bean before it gets @Autowired
在 Spring 中,是否有机制或侦听器来检测使用特定注释注释的 bean 何时获得 @Autowired
和 运行 一些自定义逻辑?类似于 @ConfigurationProperties
已经做的事情,它会在自动装配之前自动注入字段。
我有一个要求,我需要在实例化之前将值注入某些用 @ExampleAnnotation
注释的 bean 的字段。理想情况下,在这个听众中,我会:
- 询问当前被实例化的bean是否被注释为
@ExampleAnnotation
- 如果不是,return。如果是,我会使用反射从这个 bean 中获取字段的名称并使用存储库填充它们。
这样的事情可能吗?
我猜如果和ConfigurationProperties
类似,那bean绑定属性的classConfigurationPropertiesBindingPostProcessor
可以作为例子。它实现 BeanPostProcessor
并在 postProcessBeforeInitialization
方法中进行绑定。此方法具有以下 Javadoc:
"在任何 bean 初始化回调(如 InitializingBean 的 afterPropertiesSetor 自定义初始化方法)之前将此 BeanPostProcessor 应用于给定的新 bean 实例。bean 将已经填充 属性 values.The 返回的 bean 实例可能是原始实例的包装器。"
一个可能的解决方案是编写自定义 setter 并使用 @Autowired 对其进行注释,如下所示:
@Autowired
public void setExample(Example example)
{
// Do your stuff here.
this.example = example;
}
但是,我不推荐这种在自动装配之前修改 bean 的做法,因为它会导致代码的可维护性差,而且对于其他需要处理您的代码的人来说,这可能是违反直觉的。
您可以通过以下代码实现:
@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) {
}
}
在 Spring 中,是否有机制或侦听器来检测使用特定注释注释的 bean 何时获得 @Autowired
和 运行 一些自定义逻辑?类似于 @ConfigurationProperties
已经做的事情,它会在自动装配之前自动注入字段。
我有一个要求,我需要在实例化之前将值注入某些用 @ExampleAnnotation
注释的 bean 的字段。理想情况下,在这个听众中,我会:
- 询问当前被实例化的bean是否被注释为
@ExampleAnnotation
- 如果不是,return。如果是,我会使用反射从这个 bean 中获取字段的名称并使用存储库填充它们。
这样的事情可能吗?
我猜如果和ConfigurationProperties
类似,那bean绑定属性的classConfigurationPropertiesBindingPostProcessor
可以作为例子。它实现 BeanPostProcessor
并在 postProcessBeforeInitialization
方法中进行绑定。此方法具有以下 Javadoc:
"在任何 bean 初始化回调(如 InitializingBean 的 afterPropertiesSetor 自定义初始化方法)之前将此 BeanPostProcessor 应用于给定的新 bean 实例。bean 将已经填充 属性 values.The 返回的 bean 实例可能是原始实例的包装器。"
一个可能的解决方案是编写自定义 setter 并使用 @Autowired 对其进行注释,如下所示:
@Autowired
public void setExample(Example example)
{
// Do your stuff here.
this.example = example;
}
但是,我不推荐这种在自动装配之前修改 bean 的做法,因为它会导致代码的可维护性差,而且对于其他需要处理您的代码的人来说,这可能是违反直觉的。
您可以通过以下代码实现:
@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) {
}
}