实际上,这不是一个问题,但我真的需要你的意见...... 我把他的帖子放在这里,因为我知道你一直很活跃,所以请不要认为这是一个糟糕的问题,并与我分享你的意见。
我使用Java动态代理集中化我在独立模式下使用的JPA代码,这是动态代理代码:
package com.forat.service;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
import com.forat.service.exceptions.DAOException;
/**
* Example of usage :
* <pre>
* OnlineFromService onfromService =
* (OnlineFromService) DAOProxy.newInstance(new OnlineFormServiceImpl());
* try {
* Student s = new Student();
* s.setName("Mohammed");
* s.setNationalNumber("123456");
* onfromService.addStudent(s);
* }catch (Exception ex) {
* System.out.println(ex.getMessage());
* }
*</pre>
* @author mohammed hewedy
*
*/
public class DAOProxy implements InvocationHandler{
private Object object;
private Logger logger = Logger.getLogger(this.getClass().getSimpleName());
private DAOProxy(Object object) {
this.object = object;
}
public static Object newInstance(Object object) {
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(), new DAOProxy(object));
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
EntityManagerFactory emf = null;
EntityManager em = null;
EntityTransaction et = null;
Object result = null;
try {
emf = Persistence.createEntityManagerFactory(Constants.UNIT_NAME);
em = emf.createEntityManager();;
Method entityManagerSetter = object.getClass().
getDeclaredMethod(Constants.ENTITY_MANAGER_SETTER_METHOD, EntityManager.class);
entityManagerSetter.invoke(object, em);
et = em.getTransaction();
et.begin();
result = method.invoke(object, args);
et.commit();
return result;
}catch (Exception ex) {
et.rollback();
Throwable cause = ex.getCause();
logger.log(Level.SEVERE, cause.getMessage());
if (cause instanceof DAOException)
throw new DAOException(cause.getMessage(), cause);
else
throw new RuntimeException(cause.getMessage(), cause);
}finally {
em.close();
emf.close();
}
}
}
这是包含更多信息(http://m-hewedy.blogspot.com/2010/04/using-dynamic-proxies-to-centralize-jpa.html)
的链接所以,请告诉我你的意见。
感谢。
答案 0 :(得分:1)
因此,您已将事务划分逻辑封装在一个位置,并使用动态代理通过事务管理增强现有服务并减少样板代码,对吧?
听起来对我来说还算不错。实际上,当我们谈到declarative transaction demarcation时,诸如Spring或EJB之类的容器是非常相似的。在实现方面,您可以使用动态代理或字节代码检测,甚至使用AspectJ。对于一个小小的测试框架,我做过一次非常相似的事情。这是关于它的blog post。
我看到的棘手部分是:
1) 仅回滚 。根据JPA规范,实体交易可以标记为“rollback only”。这样的交易永远不会提交。所以我觉得你应该检查这两行:
result = method.invoke(object, args);
et.commit();
2) Re-entrancy 。大多数具有声明性事务的系统都实现了一种语义,只有在没有一个事件处于活动状态时才启动事务(参见EJB annotations列表中的“必需”)。看起来您应该在逻辑中查看isActive
。
3) 异常处理 。对动态代理中的异常传播要非常小心。代理应尽可能对客户端透明。如果除DAOException
之外的其他异常泄露出DAO,则代理会将其转换为RuntimeException
。对我来说听起来不是最理想的。也不要混淆异常,因为invoke
失败,调用包含的异常,我认为你应该按原样重新抛出:
catch ( InvocationTargetException e )
{
Throwable nested = e.getTargetException();
throw nested;
}
结论:在这种情况下使用动态代理的想法听起来不错。但我怀疑有一些东西可以仔细检查你的代码(我不记得JPA规范的所有细节和动态代理的异常处理,但有一些棘手的情况)。这种代码可以隐藏微妙的错误,因此值得花时间让它成为防弹。
答案 1 :(得分:0)
我过去使用过类似的东西,但编码为hibernate API(这是JPA之前的版本)。大多数类型的DAO的数据访问由以对象类型命名的接口来管理,例如。 CustomerPersistence用于管理客户实例。 findXXX等方法映射到命名查询,方法中的参数名称映射到查询中的参数。
接口的实现是代理,它使用接口名称,方法名称,参数名称等来调用hibernate API中的适当方法。
它节省了大量的样板编码,直观地映射到底层数据访问框架,并且非常容易模拟数据访问层。
所以,我对使用代理肯定是“赞许”。