#java #spring #spring-boot #autowired
#java #весна #пружинный ботинок #автозаполнение
Вопрос:
Существует ли весной механизм или прослушиватель для определения того, когда компонент, аннотированный определенной аннотацией, получает @Autowired
и запускает на нем какую-либо пользовательскую логику? Что-то похожее на то, что @ConfigurationProperties
уже делает, автоматически вводит поля до того, как они будут автоматически подключены.
У меня есть требование, в котором мне нужно вводить значения в поля определенных компонентов, аннотированных @ExampleAnnotation
до их создания. В идеале, в этом слушателе я бы:
- Спросите, аннотируется ли текущий создаваемый экземпляр компонента
@ExampleAnnotation
- Если это не так, верните. Если это так, я бы использовал отражение, чтобы получить имена полей из этого компонента и заполнить их с помощью репозитория.
Возможно ли что-то подобное?
Ответ №1:
Вы можете достичь этого с помощью следующего кода:
@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) {
}
}
Комментарии:
1. Это выглядит многообещающе, однако
this.applicationContext.findAnnotationOnBean(beanName, MyAnnotation.class);
вызывает всевозможные проблемы во время сборки. Трассировка стека слишком велика, чтобы поместить ее здесь, но она связанаCannot create inner bean...
с зависимостями и не выполняется. Есть лиfindAnnotationOnBean
какие-либо побочные эффекты, которые могут быть причиной этого? Когда я комментирую эту строку, проект строится правильно.2. Это работает для меня. Вам не нужно использовать контекст приложения для поиска аннотаций к классам. Существуют и другие служебные классы, такие как
org.springframework.core.annotation.AnnotationUtils
.3. Вероятно, вызвано какой-то магией из Spring Data JPA. Я использовал
getClass().getAnnotation(MyAnnotation.class)
вместо этого, и это работает. Это именно то, что я хотел. Спасибо!
Ответ №2:
Я думаю, если это похоже на ConfigurationProperties
, то класс ConfigurationPropertiesBindingPostProcessor
, который связывает свойства с beans, может служить примером. Он реализует BeanPostProcessor
и выполняет привязку в postProcessBeforeInitialization
методе. Этот метод имеет следующие Javadocs:
«Примените этот BeanPostProcessor к данному новому экземпляру bean перед любыми обратными вызовами beaninitialization (например, afterpropertiesetor от InitializingBean или пользовательский init-метод). Компонент уже будет заполнен значениями свойств.Возвращаемый экземпляр компонента может быть оболочкой вокруг оригинала «.
Комментарии:
1. Как Spring узнает, что нужно запускать
ConfigurationPropertiesBindingPostProcessor
всякий раз, когда он сталкивается с аннотированным классом@ConfigurationProperties
?2. Он
ConfigurationPropertiesBindingPostProcessor
проверит компонент, чтобы узнать, аннотирован ли онConfigurationProperties
. Если да, то выполняется привязка. Что касается того, как он зарегистрирован, Javadoc ofBeanPostProcessor
говорит, что «anApplicationContext
может автоматическиBeanPostProcessor
определять bean-компоненты в своих определениях bean и применять эти постпроцессоры к любым впоследствии созданным bean-компонентам» . Его также можно зарегистрировать с помощьюEnableConfigurationProperties
. В этом руководстве показан пример.
Ответ №3:
Одним из возможных решений является написание пользовательского сеттера и аннотирование его с помощью @Autowired, например:
@Autowired
public void setExample(Example example)
{
// Do your stuff here.
this.example = example;
}
Однако я не рекомендую эту практику изменения bean перед автозапуском, поскольку это может привести к ухудшению управляемости кода, и это может быть нелогичным для других людей, которым тоже нужно работать над вашим кодом.