扩展Hibernate Envers的实现 [英] Extending Hibernate Envers Implementation

查看:68
本文介绍了扩展Hibernate Envers的实现的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有2个Maven项目在他们各自的POM中作为一个依赖项共享一个JPA项目. JPA项目在2.1版上,并且成功实现了休眠envers. 但是,我现在需要创建一个自定义的RevisionEntity,因为我需要审核其他属性,例如登录的用户ID.问题是:

i.我无法在JPA项目中直接实现

ii.父maven项目的检索登录用户的实现不同.

真正的挑战实际上是实现RevisionListener.我尝试在JPA项目本身中创建一个抽象类的修订侦听器,我可以在每个父Maven项目中扩展和实现它.哈哈!这没用!

无论如何,我将不胜感激.有出路吗?

解决方案

我无法在JPA项目中直接实现

如果要收集的每个修订的信息是相同的,而与使用JPA应用程序的两个应用程序无关,那么在通用JPA中实现修订实体和侦听器功能应该没有问题.项目.您无法执行此操作的唯一原因是信息,换句话说,表结构不同.

要实现此目的,我们需要一个抽象层.而不是像您尝试的那样扩展RevisionListener,而是具有另一个接口,该接口代表侦听器将需要的服务,然后在子项目中实现该服务.

/**
 * Interface that implementations should extend to provider revision
 * information to the Envers revision listener.
 */
public interface RevisionInfoProvider {
  String getUserName();
}

/**
 * A class that holds a RevisionInfoProvider as a ThreadLocal.
 */
public class RevisionInfoProviderHolder {
   public static RevisionInfoProvider getProvider() {
     // impl details here to get a RevisionInfoProvider.
   }
}

然后,您的修订版侦听器实现可能类似于以下内容:

public class RevisionListenerImpl implements RevisionListener {
  @Override
  public void newRevision(Object revisionEntity) {
    if ( CustomRevisionEntity.class.isInstance( revisionEntity ) ) {
      CustomRevisionEntity entity = (CustomRevisionEntity) revisionEntity;
      // get provider from thread local and set user details
      RevisionInfoProvider provider = RevisionInfoProviderHolder.getProvider();
      entity.setUserName( provider.getUserName() );          
    }
    // todo: may want to assert in case you change entity types?
  }
}

这时,只需创建您的CustomRevisionEntity,并正确注释即可,包括将其指向Envers应该使用的侦听器实现所指向的RevisionListenerImpl类.

现在在每个子项目中,您所需要做的就是:

  1. 实施RevisionInfoProvider
  2. 填充RevisionInfoProviderHolder

第一个只是通往JPA项目如何从每个子项目中获取详细信息的网关.在spring Web应用程序中,例如,可能只是一些spring service bean.

第二个只是每个线程在调用任何JPA内容之前需要做的事情.同样在Spring Web应用程序中,这可能是某种类型的Web过滤器,该过滤器在调用用户代码以确保正确设置ThreadLocal之前在过滤器链的顶部执行.

父maven项目的检索登录用户的实现不同.

回到上面,如上所示,使用RevisionInfoProvider的抽象层可以很好地处理此问题.您为Envers建立了一个通用框架,以使其发挥作用,同时又使其具有足够的灵活性,以便每个父项目可以根据需要进行分叉.

如果每个父项目存储不同的结构化信息怎么办?

如果确实遇到这种情况,则需要在每个父项目中分别实现修订实体和侦听器遵循我上面提到的内容,但使用满足要求的修订实体都是 父模块.

您只需要确保在检查实体的引导阶段就可以通过JPA模块选择修订实体.

希望这会有所帮助.

I have 2 maven projects that share a JPA project as a dependency in their individual POMs. The JPA project is on ver 2.1 and has hibernate envers implemented successfully. However I now need to create a custom RevisionEntity as I need to audit extra properties such as the logged in user id. Problems are:

i. I cant implement this directly in the JPA project

ii. The implementation for retrieving the logged in user differs for the parent maven projects.

The real challenge is actually in implementing the RevisionListener. I tried creating an abstract class revisionlistener within the JPA project itself which I can extend and implement within each parent maven project. Lol! This didnt work!

I would appreciate any help whatsoever that gets me through this. Is there a way out?

解决方案

I cant implement this directly in the JPA project

If the information you want to collect about each revision is identical regardless of the two applications that use your JPA application, then there should be no problem implementing the revision entity and listener functionality in the common JPA project. The only reason you wouldn't be able to do this is if the information, in other words the table structure differed.

To accomplish this, we'll need a layer of abstraction. Rather than extending the RevisionListener as you were attempting, you would have another interface that represents a service the listener will require and then implement that service in your subprojects.

/**
 * Interface that implementations should extend to provider revision
 * information to the Envers revision listener.
 */
public interface RevisionInfoProvider {
  String getUserName();
}

/**
 * A class that holds a RevisionInfoProvider as a ThreadLocal.
 */
public class RevisionInfoProviderHolder {
   public static RevisionInfoProvider getProvider() {
     // impl details here to get a RevisionInfoProvider.
   }
}

Then your revision listener implementation may look something like the following:

public class RevisionListenerImpl implements RevisionListener {
  @Override
  public void newRevision(Object revisionEntity) {
    if ( CustomRevisionEntity.class.isInstance( revisionEntity ) ) {
      CustomRevisionEntity entity = (CustomRevisionEntity) revisionEntity;
      // get provider from thread local and set user details
      RevisionInfoProvider provider = RevisionInfoProviderHolder.getProvider();
      entity.setUserName( provider.getUserName() );          
    }
    // todo: may want to assert in case you change entity types?
  }
}

At this point, just create your CustomRevisionEntity, annotated it correctly, including pointing it to the RevisionListenerImpl class as the listener implementation Envers should use.

Now in each of your subprojects, all you need to do is:

  1. Implement RevisionInfoProvider
  2. Populate RevisionInfoProviderHolder

The first is simply the gateway to how the JPA project can get the details from each subproject. In a spring web application, this may likely just be some spring service bean for example.

The second is just something that each thread needs to do before calling into any JPA stuff. Again in a spring web application, this would likely be some type of web filter that executes at the top of the filter chain before user code is invoked that makes sure the ThreadLocal is set appropriately.

The implementation for retrieving the logged in user differs for the parent maven projects.

Coming back to this point, as you can see above, the layer of abstraction with the RevisionInfoProvider handles this problem nicely. You build out a common framework for Envers to do it's job while leaving it flexible enough so that each of the parent projects can diverge as necessary.

What if each parent project stores differing structured information?

If you do find yourself in this case, you'll need to implement both the revision entity and listener in each parent project separately or follow what I mentioned above but use a revision entity that satisfies requirements of both parent modules.

You just need to make sure the revision entity can be picked up by the JPA module during the bootstrap phase when entities are being examined.

Hope this helps.

这篇关于扩展Hibernate Envers的实现的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆