使用动态代理集中JPA代码 [英] Using Dynamic Proxies to centralize JPA code

查看:137
本文介绍了使用动态代理集中JPA代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Actually, This is not a question but really I need your opinions in a matter... I put his post here because I know you always active, so please don't consider this a bad question and share me your opinions.

我使用Java动态代理来集中化我在独立模式下使用的JPA代码,这里是动态代理代码:

I've used Java dynamic proxies to Centralize The code of JPA that I used in a standalone mode, and Here's the dynamic proxy code:

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

And here's the link that contains more info (http://m-hewedy.blogspot.com/2010/04/using-dynamic-proxies-to-centralize-jpa.html)

所以,请给我你的意见。

So, Please give me your opinions.

谢谢。

推荐答案

所以你已经封装了事务划分逻辑在一个地方,并使用动态代理通过事务管理增强现有服务并减少样板代码,对吧?

So you've encapsulated the transaction demarcation logic in one place and use dynamic proxy to enhance existing services with transaction management and reduce boilerplate code, right?

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

The sounds a rather OK to me. Actually what containers such as Spring, or EJB do when we speak of declarative transaction demarcation is very similar. Implementation-wise, you can do it with dynamic proxy, or byte code instrumentation, or even use AspectJ. I did something very similar once for a tiny testing framework once. Here is a blog post about it.

我看到的棘手部分是:

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

1) Rollback only. As per JPA spec, an entity transaction can be flagged as "rollback only". Such a transaction can never commit. So I feel like you should check that between these two lines:

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

2) Re-entrancy 。大多数具有声明性事务的系统都实现了一种语义,只有在没有一个事件处于活动状态时才启动事务(参见 EJB注释)。看起来您应该在逻辑中查看 isActive

2) Re-entrancy. Most system that have declarative transaction implement a semantics in which a transaction is started only if there isn't one already active (See "Required" in this list of EJB annotations). Looks like you should maybe check with isActive that in your logic.

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

3) Exception handling. Be very careful with the exception propagation in dynamic proxy. The proxy is supposed to be transparent for the client as much as possible. If an exception other than DAOException leaks out of the DAO, the proxy will transform it into a RuntimeException. Doesn't sound optimal to me. Also don't confuse the exception because invoke failed, and the exception wrapped by the invocation, that I think you should re-throw as-is:

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

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

Conclusion: the idea to use dynamic proxy in this scenario sounds OK to me. But I suspect there are a few stuffs to double-check in your code (I don't remember all the details of the JPA specs and exception handling with dynamic proxy, but there are some tricky cases). This kind of code can hide subtle bugs, so it's worth taking time to make it bullet-proof.

这篇关于使用动态代理集中JPA代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆