如何在RMI远程方法中自动化Hibernate样板

时间:2012-05-09 14:09:19

标签: java hibernate rmi

我有一个接受来自客户端的远程调用的RMI类。

该类使用Hibernate加载实体并执行一些业务逻辑,通常是只读的。

目前,大多数远程方法体都是这样的:

try {
    HibernateUtil.currentSession().beginTransaction();

    //load entities, do some business logic...

} catch (HibernateException e) {
   logger.error("Hibernate problem...", e);
   throw e;
} catch (other exceptions...) {
   logger.error("other problem happened...", e);
   throw e;
} finally {
   HibernateUtil.currentSession().getTransaction().rollback(); //this because it's read-only, we make sure we don't commit anything
   HibernateUtil.currentSession().close();
}

我想知道是否有一些我可以(相对容易)实现的模式,以便自动拥有这个“尝试打开session / catch hibernate异常/最终关闭hibernate资源”的行为而无需在每个方法。

类似于在webapps中使用的“在视图中打开会话”,但可以应用于remotr RMI方法调用而不是HTTP请求。

理想情况下,我希望能够直接调用方法,而不是使用一些反射方法名作为字符串。

2 个答案:

答案 0 :(得分:0)

我建议您使用 spring + hibernate 堆栈。这为我们节省了大量可重复的代码,我想你正在寻找。请检查this link。它实际上是Web应用程序的一个示例,但同样可以用于standalone application

答案 1 :(得分:0)

我想要的只是一个“快速而干净”的解决方案,如果可能的话,所以现在没有新的框架(我可能会稍后使用Spring + Hibernate堆栈)。

所以我最终使用了一个“快速且不那么脏”的解决方案,涉及“Command”模式的变体,其中hibernate调用封装在实现我的通用Command接口的匿名内部类中,并且命令执行器使用Hibernate会话和异常处理来包装调用。通用位是为了使execute方法具有不同的返回值类型。

我对这个解决方案并不是100%满意,因为它仍然意味着我的业务逻辑包含了一些样板代码(我对返回值所需的显式转换特别不满意)并且它使得理解和调试稍微复杂一些

然而重复代码的增益仍然很大(每个方法大约10行到3-4行),更重要的是Hibernate处理逻辑集中在一个类中,所以如果需要它可以在那里轻松更改它是不易出错。

以下是一些代码:

命令界面:

public interface HibernateCommand<T> {
    public T execute(Object... args) throws Exception; 
}

执行者:

public class HibernateCommandExecuter {

    private static final Logger logger = Logger.getLogger(HibernateCommandExecuter.class);

    public static Object executeCommand(HibernateCommand<?> command, boolean commit, Object... args) throws RemoteException{
        try {
            HibernateUtil.currentSession().beginTransaction();

            return command.execute(args);

        } catch (HibernateException e) {
            logger.error("Hibernate problem : ", e);
            throw new RemoteException(e.getMessage());
        }catch(Exception e){
            throw new RemoteException(e.getMessage(), e);
        }
        finally {
            try{
                if(commit){
                    HibernateUtil.currentSession().getTransaction().commit();
                }else{
                    HibernateUtil.currentSession().getTransaction().rollback();
                }
                HibernateUtil.currentSession().close();
            }catch(HibernateException e){
                logger.error("Error while trying to clean up Hibernate context :", e);
            }
        }
    }   
}

远程调用方法中的样本使用(但也可以在本地使用):

@Override
    public AbstractTicketingClientDTO doSomethingRemotely(final Client client) throws RemoteException {
        return (MyDTO) HibernateCommandExecuter.executeCommand(new HibernateCommand<MyDTO>() {
            public AbstractTicketingClientDTO execute(Object...args) throws Exception{
                MyDTO dto = someService.someBusinessmethod(client);
                return dto;
            }
        },false);
    }

注意客户端参数如何声明为final,因此可以在内部类中引用它。如果无法声明final,则可以将其作为参数传递给executeCommand方法。