0

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

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

所以,请给我你的意见。

谢谢。

4

2 回答 2

1

因此,您已经将事务划分逻辑封装在一个地方,并使用动态代理通过事务管理来增强现有服务并减少样板代码,对吗?

这听起来对我来说还不错。实际上,当我们谈到声明性事务划分时,Spring 或 EJB 等容器所做的事情非常相似。在实现方面,您可以使用动态代理或字节码检测,甚至使用 AspectJ 来实现。我曾经为一个小型测试框架做过非常相似的事情。这是一篇关于它的博客文章

我看到的棘手部分是:

1)仅回滚。根据 JPA 规范,实体事务可以标记为“仅回滚”。这样的事务永远不会提交。所以我觉得你应该在这两行之间检查:

result = method.invoke(object, args);
et.commit();

2)重入。大多数具有声明性事务的系统都实现了一种语义,其中仅当没有一个事务处于活动状态时才启动事务(请参阅此EJB 注释列表中的“必需” )。看起来你应该isActive在你的逻辑中检查一下。

3)异常处理。对动态代理中的异常传播要非常小心。代理应该对客户端尽可能透明。如果除DAOExceptionDAO 之外的异常泄漏,代理会将其转换为RuntimeException. 对我来说听起来不是最理想的。也不要因为invoke失败而混淆异常,以及调用包装的异常,我认为您应该按原样重新抛出:

catch ( InvocationTargetException e )
{
     Throwable nested = e.getTargetException();
     throw nested;
}

结论:在这种情况下使用动态代理的想法对我来说听起来不错。但我怀疑在您的代码中有一些东西需要仔细检查(我不记得 JPA 规范和使用动态代理处理异常的所有细节,但有一些棘手的情况)。这种代码可以隐藏细微的错误,因此值得花时间让它防弹。

于 2010-05-12T09:28:36.327 回答
0

我过去使用过类似的东西,但编码为休眠 API(这是 JPA 之前的版本)。大多数类型的 DAO 的数据访问由以对象类型命名的接口管理,例如用于管理客户实例的 CustomerPersistence。findXXX 等方法映射到命名查询,方法中的参数名称映射到查询中的参数。

接口的实现是代理,它使用接口名称、方法名称、参数名称等来调用 hibernate API 中的适当方法。

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

所以,我绝对对使用代理“赞不绝口”。

于 2010-05-07T14:14:29.413 回答