Spring Dependency Injection into JPA entity listen

2020-02-11 16:34发布

I need to have a Spring dependency injected into a JPA entity listener. I know I can solve this using @Configurable and Spring's AspectJ weaver as javaagent, but this seems like a hacky solution. Is there any other way to accomplish what I'm trying to do?

3条回答
Luminary・发光体
2楼-- · 2020-02-11 16:43

Another trick is to implement an utility class with static method that helps you to use Spring beans everywhere, not only in managed classes:

@Component
public final class BeanUtil {

    private static ApplicationContext context;

    private BeanUtil(ApplicationContext context) {
        BeanUtil.context = context;
    }

    public static <T> T getBean(Class<T> clazz) throws BeansException {

        Assert.state(context != null, "Spring context in the BeanUtil is not been initialized yet!");
        return context.getBean(clazz);
    }
}
查看更多
贪生不怕死
3楼-- · 2020-02-11 16:50

Since Hibernate 5.3 org.hibernate.resource.beans.container.spi.BeanContainer and Spring 5.1 org.springframework.orm.hibernate5.SpringBeanContainer you do not need to extra autowiring effort any more. See details of this feature in https://github.com/spring-projects/spring-framework/issues/20852

Simply annotate your EntityListener class with @Component, and do any autowiring like so:

@Component
public class MyEntityListener{

  private MySpringBean bean;

  @Autowired
  public MyEntityListener(MySpringBean bean){
    this.bean = bean;
  }

  @PrePersist
  public void prePersist(final Object entity) {
    ...
  }

}

In Spring Boot the configuration of LocalContainerEntityManagerFactoryBean is done automatically in org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaConfiguration.

Outside of Spring Boot, you have to register SpringBeanContainer to Hibernate:

LocalContainerEntityManagerFactoryBean emfb = ...
 emfb.getJpaPropertyMap().put(AvailableSettings.BEAN_CONTAINER, new SpringBeanContainer(beanFactory));
查看更多
等我变得足够好
4楼-- · 2020-02-11 16:54

You can try this solution

import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;


public final class AutowireHelper implements ApplicationContextAware {

private static final AutowireHelper INSTANCE = new AutowireHelper();
private static ApplicationContext applicationContext;

private AutowireHelper() {
}

/**
 * Tries to autowire the specified instance of the class if one of the specified beans which need to be autowired
 * are null.
 *
 * @param classToAutowire        the instance of the class which holds @Autowire annotations
 * @param beansToAutowireInClass the beans which have the @Autowire annotation in the specified {#classToAutowire}
 */
public static void autowire(Object classToAutowire, Object... beansToAutowireInClass) {
    for (Object bean : beansToAutowireInClass) {
        if (bean == null) {
            applicationContext.getAutowireCapableBeanFactory().autowireBean(classToAutowire);
            return;
        }
    }
}

/**
 * @return the singleton instance.
 */
public static AutowireHelper getInstance() {
    return INSTANCE;
}

@Override
public void setApplicationContext(final ApplicationContext applicationContext) {
    AutowireHelper.applicationContext = applicationContext;
}

}

and then

 @Autowired
SomeService thatToAutowire;

  AutowireHelper.autowire(this, this.thatToAutowire);//this in the method
查看更多
登录 后发表回答