我有一个接受来自客户端的远程调用的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请求。
理想情况下,我希望能够直接调用方法,而不是使用一些反射方法名作为字符串。
答案 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方法。