0

我有一个接受来自客户端的远程调用的 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();
}

我想知道是否有一些我可以(相对容易地)实现的模式,以便自动实现这种“尝试打开会话/捕获休眠异常/最终关闭休眠资源”行为,而无需在每个方法中对其进行编码。

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

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

4

2 回答 2

0

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

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

我对这个解决方案不是 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 方法。

于 2012-05-10T13:37:48.940 回答
0

我建议你使用spring+hibernate堆栈。这为我们节省了很多我猜你正在寻找的可重复代码。请检查此链接。它实际上是 Web 应用程序的示例,但也可以用于独立应用程序

于 2012-05-09T15:00:06.573 回答