Внедрение пружинного боба в 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-компоненты.

Другие вопросы по тегам