使用动态代理集中JPA代码

时间:2010-04-06 19:33:48

标签: java dynamic-proxy

实际上,这不是一个问题,但我真的需要你的意见...... 我把他的帖子放在这里,因为我知道你一直很活跃,所以请不要认为这是一个糟糕的问题,并与我分享你的意见。

我使用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

的链接

所以,请告诉我你的意见。

感谢。

2 个答案:

答案 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中的适当方法。

它节省了大量的样板编码,直观地映射到底层数据访问框架,并且非常容易模拟数据访问层。

所以,我对使用代理肯定是“赞许”。