2

I have an application using hibernate/JPA for persistence. It uses Spring.
Some of the persisted beans depend on external objects that I retrieve from a REST service.

The client stub of this REST service is a registered Spring service.

I would like to wrap the load of those external objects in the process of the hibernate load. This way, I know for sure that my objects will always be valid after the load, even when I get those objects via complex HQL queries.

The problem is that, whatever method I use, I have hard time obtaining the Spring application context (and thus the REST client) in my persisted beans.

I have tried the following:

  • Use UserType to fetch my object from REST via their ID :
    the CustomUserType is instanciated by Hibernate, and thus, no Spring injection can occur.
  • Use @AfterLoad JPA annotation :
    This one is worse, no EntityManager, Session or Spring context available
  • User LifeCycle interface, onLoad(Session s, Serializable id) method :
    I have access to the session here. But I don't know how to make a custom Session that would be ApplicationContext aware.

For the time being, I am using a dirty workaround : An ApplicationHolder Spring service, that provides a static getter, for objects out of the Spring wolrd to have access to it.

Do you have any best practive on how to make hibernate or the persisted beans context aware ?

THks

EDIT

Doing it in my DAO was my first approach, but actually I have many sub objects that need fetching, like so :

LocalObject
* - localSubObject1
    - refToExternalObject ----------> externalObject1
* - localSubObject2 
    - refToExternalObject ----------> externalObject2
    - refToExternalObject ----------> externalObject3

I would like my LocalObject to have a consistent, clean load.

This way, I can write Complex HQL in my DAO and not bother about external object fetching anymore.

4

2 回答 2

1

A quick sketch of a solution to explain my comment:

@Component
public class HibernateDao {

    @Resource
    private SessionFactory sessionFactory;
    @Resource
    private RestClient restClient;


    public LocalObject loadLocalObject(Serializable id) {
        LocalObject localObject = sessionFactory.getCurrentSession().load(id);
        ExternalObject externalObject = restClient.getExternalObject(id);

        localObject.setVal(externalObject.getVal())
        // ... more of this ...

        return localObject;
    }
}
于 2013-01-04T16:24:27.070 回答
1

If you don't want to do it in the Dao then maybe this could work:

@Component
public class MyPostLoadEventListener implements PostLoadEventListener {

    @Resource
    private SessionFactoryImpl sessionFactoryImpl;
    @Resource
    private RestClient restClient;

    @PostConstruct
    public void installAsEventListener() {
        sessionFactoryImpl.getServiceRegistry()
                              .getService(EventListenerRegistry.class)
                              .getEventListenerGroup(EventType.POST_LOAD)
                              .appendListener(this);
    }

    @Override
    public void onPostLoad(PostLoadEvent event) {
        if (event.getEntity() instanceof LocalObject) {
            // fill with data from RestClient
        }
    }
}

This is a little bit messy, but unfortunately the alternative ways of registering Hibernate EventListeners (in configuration or via Integrators) can't be used with Spring beans as they are instantiated directly (as mentioned on this abandoned JIRA entry).

Hope that helps.

于 2013-01-04T17:19:30.790 回答