我想注入的Spring依赖到JPA EntityListener。 这里是我的监听器类:
@Configurable(autowire = Autowire.BY_TYPE, dependencyCheck = true)
public class PliListener {
@Autowired
private EvenementPliRepository evenementPliRepository;
@PostPersist
void onPostPersist(Pli pli) {
EvenementPli ev = new EvenementPli();
ev.setPli(pli);
ev.setDateCreation(new Date());
ev.setType(TypeEvenement.creation);
ev.setMessage("Création d'un pli");
System.out.println("evenementPliRepository: " + evenementPliRepository);
evenementPliRepository.save(ev);
}
}
这里是我的实体类:
@RooJavaBean
@RooToString
@RooJpaActiveRecord
@EntityListeners(PliListener.class)
public class Pli implements Serializable{
...
然而,我的依赖(即evenementPliRepository
) 总是空 。
任何人都可以请帮助?
Answer 1:
注入的无状态bean依赖一个黑客,是定义为依赖“静态”,创建一个setter方法,使Spring能够注入的依赖(将其分配到静态依赖)。
声明依赖静态。
static private EvenementPliRepository evenementPliRepository;
创建一个方法,使Spring能够注入它。
@Autowired
public void init(EvenementPliRepository evenementPliRepository)
{
MyListenerClass.evenementPliRepository = evenementPliRepository;
logger.info("Initializing with dependency ["+ evenementPliRepository +"]");
}
:在更多细节http://blog-en.lineofsightnet.com/2012/08/dependency-injection-on-stateless-beans.html
Answer 2:
这实际上是一个老问题,但我找到了一个替代的解决方案:
public class MyEntityListener {
@Autowired
private ApplicationEventPublisher publisher;
@PostPersist
public void postPersist(MyEntity target) {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
publisher.publishEvent(new OnCreatedEvent<>(this, target));
}
@PostUpdate
public void postUpdate(MyEntity target) {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
publisher.publishEvent(new OnUpdatedEvent<>(this, target));
}
@PostRemove
public void postDelete(MyEntity target) {
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
publisher.publishEvent(new OnDeletedEvent<>(this, target));
}
}
也许不是最好的,但比静态变量更好的W / O AOP +编织。
Answer 3:
而这个解决方案是什么?
@MappedSuperclass
@EntityListeners(AbstractEntityListener.class)
public abstract class AbstractEntity {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private Long id;
@Column(name = "creation_date")
private Date creationDate;
@Column(name = "modification_date")
private Date modificationDate;
}
然后监听...
@Component
public class AbstractEntityListener {
@Autowired
private DateTimeService dateTimeService;
@PreUpdate
public void preUpdate(AbstractEntity abstractEntity) {
AutowireHelper.autowire(this, this.dateTimeService);
abstractEntity.setModificationDate(this.dateTimeService.getCurrentDate());
}
@PrePersist
public void prePersist(AbstractEntity abstractEntity) {
AutowireHelper.autowire(this, this.dateTimeService);
Date currentDate = this.dateTimeService.getCurrentDate();
abstractEntity.setCreationDate(currentDate);
abstractEntity.setModificationDate(currentDate);
}
}
和辅助...
/**
* Helper class which is able to autowire a specified class. It holds a static reference to the {@link org
* .springframework.context.ApplicationContext}.
*/
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);
}
}
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) {
AutowireHelper.applicationContext = applicationContext;
}
/**
* @return the singleton instance.
*/
public static AutowireHelper getInstance() {
return INSTANCE;
}
}
我的作品。
来源: http://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/
Answer 4:
我开始下井使用AOP到一个Spring bean注入到实体监听的路径。 一天的研究和尝试我碰到这个就不同的东西后半段的链接 ,其中指出:
这是不可能注入Spring管理豆成一个JPA EntityListener类。 这是因为JPA监听机制应基于一个无状态类,因此这些方法实际是静态的,和非情境感知。 ... AOP再多救你,没有东西注入到“对象”代表了听众,因为实现不实际创建实例,但使用类方法。
在这一点上我重新集结,在整个的EclipseLink跌跌撞撞DescriptorEventAdapter 。 使用这个信息,我创建了一个扩展的描述符适配器一个监听器类。
public class EntityListener extends DescriptorEventAdapter {
private String injectedValue;
public void setInjectedValue(String value){
this.injectedValue = value;
}
@Override
public void aboutToInsert(DescriptorEvent event) {
// Do what you need here
}
}
为了使用这个类,我可以用我的实体类的@EntityListeners注解。 不幸的是,这种方法不会允许Spring来控制我的听众的创建,因此不会允许依赖注入。 相反,我增加了以下“初始化”功能,我的课:
public void init() {
JpaEntityManager entityManager = null;
try {
// Create an entity manager for use in this function
entityManager = (JpaEntityManager) entityManagerFactory.createEntityManager();
// Use the entity manager to get a ClassDescriptor for the Entity class
ClassDescriptor desc =
entityManager.getSession().getClassDescriptor(<EntityClass>.class);
// Add this class as a listener to the class descriptor
desc.getEventManager().addListener(this);
} finally {
if (entityManager != null) {
// Cleanup the entity manager
entityManager.close();
}
}
}
加入少许Spring XML配置
<!-- Define listener object -->
<bean id="entityListener" class="EntityListener " init-method="init">
<property name="injectedValue" value="Hello World"/>
<property name="entityManagerFactory" ref="emf"/>
</bean>
现在我们这里春创建了一个实体的聆听者,无论是需要依赖注入它的情况,和听众对象本身与实体类注册到它打算听。
我希望这有帮助。
Answer 5:
我测试出来的办法,建议https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/和工作。 不是很干净,但做这项工作。 我略作修改AutowireHelper类是这样的:
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class AutowireHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
private AutowireHelper() {
}
public static void autowire(Object classToAutowire) {
AutowireHelper.applicationContext.getAutowireCapableBeanFactory().autowireBean(classToAutowire);
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) {
AutowireHelper.applicationContext = applicationContext;
}
}
然后把这种从这样的实体监听器:
public class MyEntityAccessListener {
@Autowired
private MyService myService;
@PostLoad
public void postLoad(Object target) {
AutowireHelper.autowire(this);
myService.doThings();
...
}
public void setMyService(MyService myService) {
this.myService = myService;
}
}
Answer 6:
我使用了@Component注解注释的监听器,然后创建一个非静态的setter所注入的Spring bean分配,它运作良好
我的代码如下所示:
@Component
public class EntityListener {
private static MyService service;
@Autowired
public void setMyService (MyService service) {
this.service=service;
}
@PreUpdate
public void onPreUpdate() {
service.doThings()
}
@PrePersist
public void onPersist() {
...
}
}
Answer 7:
我相信这是因为这个监听器bean没有受到春节的控制。 春天是不是将其实例化,春天怎么能知道如何找到豆,做注射?
我没有尝试过对,但目前看来,你可以用Spring的配置注释使用的AspectJ韦弗有弹簧控制非弹簧初始化bean。
http://static.springsource.org/spring/docs/3.1.2.RELEASE/spring-framework-reference/html/aop.html#aop-using-aspectj
Answer 8:
另外一个选项:
创建服务,使AplicationContext访问:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import lombok.Setter;
@Service
class ContextWrapper {
@Setter
private static ApplicationContext context;
@Autowired
public ContextWrapper(ApplicationContext ac) {
setContext(ac);
}
public static ApplicationContext getContext() {
return context;
}
}
用它:
...
public class AuditListener {
private static final String AUDIT_REPOSITORY = "AuditRepository";
@PrePersist
public void beforePersist(Object object){
//TODO:
}
@PreUpdate
public void beforeUpdate(Object object){
//TODO:
}
@PreRemove
public void beforeDelete(Object object) {
getRepo().save(getAuditElement("DEL",object));
}
private Audit getAuditElement(String Operation,Object object){
Audit audit = new Audit();
audit.setActor("test");
Timestamp timestamp = new Timestamp(System.currentTimeMillis());
audit.setDate(timestamp);
return audit;
}
private AuditRepository getRepo(){
return ContextWrapper.getContext().getBean(AUDIT_REPOSITORY, AuditRepository.class);
}
}
此类创建为从JPA监听器:
...
@Entity
@EntityListeners(AuditListener.class)
@NamedQuery(name="Customer.findAll", query="SELECT c FROM Customer c")
public class Customer implements Serializable {
private static final long serialVersionUID = 1L;
...
由于听众是不是Spring的控制之下,它无法访问上下文豆。 我曾尝试多种选择(@Configurable(...)),并没有一个工作,除了创建一个类的背景下,静态访问。 早在这一困境,我认为这是一个优雅的选择。
Answer 9:
与JPA听众的问题是:
它们不是由Spring管理(所以不打针)
他们是(或可能)创建之前 Spring的应用程序上下文已准备好(所以我们不能注入一个构造函数调用豆)
我的解决方法来处理这个问题:
1)创建Listener
公共静态类LISTENERS
领域:
public abstract class Listener {
// for encapsulation purposes we have private modifiable and public non-modifiable lists
private static final List<Listener> PRIVATE_LISTENERS = new ArrayList<>();
public static final List<Listener> LISTENERS = Collections.unmodifiableList(PRIVATE_LISTENERS);
protected Listener() {
PRIVATE_LISTENERS.add(this);
}
}
2)我们要添加到所有JPA听众Listener.LISTENERS
具有扩展这个类:
public class MyListener extends Listener {
@PrePersist
public void onPersist() {
...
}
...
}
3)现在,我们可以得到所有的听众和注入豆刚过Spring的应用程序上下文已准备就绪
@Component
public class ListenerInjector {
@Autowired
private ApplicationContext context;
@EventListener(ContextRefreshedEvent.class)
public void contextRefreshed() {
Listener.LISTENERS.forEach(listener -> context.getAutowireCapableBeanFactory().autowireBean(listener));
}
}
文章来源: Injecting a Spring dependency into a JPA EntityListener