Внедрение пружинного боба в JPA Entity Listener
Я пытаюсь сделать JPA Entity Listener осведомленным о весеннем контексте, пометив его как @Configurable. Но введенные весенние бобы являются нулевыми. Могу сделать объекты JPA осведомленными о контексте Spring, используя ту же технику. Использую Spring(core и data-jpa) в качестве инфраструктуры. Любые идеи о том, как добиться этого с помощью JPA Entity Listeners или Spring Data-JPA?
@Configurable
@Scope("singleton")
public class AggregateRootListener {
private static Logger log = LoggerFactory.getLogger(AggregateRootListener.class);
@Autowired
private EventHandlerHelper eventHandlerHelper;
@PostPersist
@PostUpdate
public void publishEvents(BaseAggregateRoot aggregateRoot){
log.info(aggregateRoot.getEvents().toString());
aggregateRoot.getEvents().stream()
.forEach(event -> {
eventHandlerHelper.notify(event, aggregateRoot);
log.info("Publishing " + event + " " + aggregateRoot.toString());
});
}
}
и код BaseAggregateRoot
@Configurable
@Scope("prototype")
@MappedSuperclass
@EntityListeners(AggregateRootListener.class)
public abstract class BaseAggregateRoot extends BaseDomain{
public static enum AggregateStatus {
ACTIVE, ARCHIVE
}
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "aggregateId", column = @Column(name = "ID", nullable = false))})
protected AggregateId aggregateId;
@Version
private Long version;
}
2 ответа
Механизм прослушивания событий является концепцией JPA и реализуется поставщиком JPA. Я не думаю, что Spring создает экземпляры класса слушателя событий - они скорее создаются провайдером JPA (Hibernate, EclipseLink и т. Д.). Поэтому обычное внедрение Spring не будет работать с экземплярами класса слушателя событий. Автор этого поста, похоже, пришел к такому же выводу.
Тем не менее, я использую управляемые bean-компоненты Spring в обработчиках событий JPA. Решение, которое я использую, было разработано, чтобы получить экземпляры bean-компонентов Spring во всех классах, которые не управляются Spring. Это предполагает создание следующего класса:
@Component
public class SpringApplicationContext implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
public void setApplicationContext(final ApplicationContext context)
throws BeansException {
CONTEXT = context;
}
public static <T> T getBean(Class<T> clazz) { return CONTEXT.getBean(clazz); }
}
Этот класс кэширует контекст приложения Spring при начальной загрузке. Затем контекст используется для поиска управляемых компонентов Spring.
Использование класса тогда так же просто, как SpringApplicationContext.getBean(FooService.class)
,
Все обычные семантики Spring, такие как жизненный цикл бина, область действия бина и транзитивные зависимости, позаботились.
Я знаю, что этот вопрос старый, но он может помочь любому, кто хочет решить ту же проблему. Недавно у меня возникла та же проблема, и я обнаружил, что начиная с Spring V5.1 (и Hibernate V5.3) он должен работать «из коробки», поскольку Spring регистрируется как поставщик этих классов. Ссылка на документацию https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/orm/hibernate5/SpringBeanContainer.html
Итак, если вы используете Springv5.1 с Springboot, просто объявите EntityListener как @comComponent и autowire Spring bean-компоненты.