Использование динамических прокси для централизации кода JPA - PullRequest
0 голосов
/ 06 апреля 2010

На самом деле, это не вопрос, но мне действительно нужно ваше мнение по этому вопросу ... Я разместил его пост здесь, потому что я знаю, что вы всегда активны, поэтому, пожалуйста, не считайте это плохим вопросом и поделитесь со мной своим мнением.

Я использовал динамические прокси Java для централизации кода JPA, который я использовал в автономном режиме, и вот код динамического прокси:

<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());
 *        }
 *
* @author Мухаммед Хьюди * * / открытый класс DAOProxy реализует InvocationHandler { частный объект Object; private Logger logger = Logger.getLogger (this.getClass (). getSimpleName ()); private DAOProxy (Объектный объект) { this.object = object; } public static Object newInstance (Объектный объект) { вернуть Proxy.newProxyInstance (object.getClass (). getClassLoader (), object.getClass (). getInterfaces (), новый DAOProxy (объект)); } @Override public Object invoke (Object proxy, Метод метода, Object [] args) throws Throwable { EntityManagerFactory emf = null; EntityManager em = null; EntityTransaction et = null; Результат объекта = ноль; пытаться { emf = Persistence.createEntityManagerFactory (Constants.UNIT_NAME); em = emf.createEntityManager () ;; Метод entityManagerSetter = object.getClass (). getDeclaredMethod (Constants.ENTITY_MANAGER_SETTER_METHOD, EntityManager.class); entityManagerSetter.invoke (object, em); et = em.getTransaction (); et.begin (); результат = method.invoke (объект, аргументы); et.commit (); вернуть результат; } catch (Exex ex) { et.rollback (); Выбрасываемая причина = ex.getCause (); logger.log (Level.SEVERE, причина.getMessage ()); если (вызвать instanceof DAOException) бросить новое DAOException (reason.getMessage (), причина); еще бросить новое RuntimeException (reason.getMessage (), причина); }в конце концов { em.close (); emf.close (); } } }

А вот ссылка, которая содержит дополнительную информацию (http://m -hewedy.blogspot.com / 2010/04 / using-dynamic-proxies-to-centralize-jpa.html )

Итак, пожалуйста, дайте мне свое мнение.

Спасибо.

Ответы [ 2 ]

1 голос
/ 12 мая 2010

Итак, вы инкапсулировали логику разграничения транзакций в одном месте и используете динамический прокси-сервер для улучшения существующих служб с помощью управления транзакциями и сокращения стандартного кода, верно?

Звучит довольно неплохо для меня.На самом деле то, что делают контейнеры, такие как Spring или EJB, когда мы говорим о декларативном разграничении транзакций , очень похоже.С точки зрения реализации вы можете сделать это с помощью динамического прокси или инструментария байт-кода, или даже использовать AspectJ.Однажды я сделал нечто очень похожее для крошечной тестовой среды.Вот сообщение в блоге об этом.

Хитрые части, которые я вижу:

1) Только откат ,Согласно спецификации JPA, транзакция объекта может быть помечена как « только откат ».Такая транзакция никогда не может совершить.Поэтому я чувствую, что вы должны проверить это между этими двумя строками:

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

2) Повторный вход .Большинство систем с декларативной транзакцией реализуют семантику, в которой транзакция запускается, только если она еще не активна (см. «Обязательно» в этом списке аннотаций EJB ).Похоже, вам следует проверить это с помощью isActive в вашей логике.

3) Обработка исключений .Будьте очень осторожны с распространением исключений в динамическом прокси.Предполагается, что прокси должен быть максимально прозрачным для клиента.Если из DAO просачивается исключение, отличное от DAOException, прокси преобразует его в RuntimeException.Не кажется оптимальным для меня.Также не путайте исключение, потому что invoke не удалось, и исключение, заключенное в вызове, которое, я думаю, вы должны перебросить как есть:

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

Заключение :Идея использовать динамический прокси в этом сценарии звучит хорошо для меня.Но я подозреваю, что есть несколько вещей, которые нужно перепроверить в вашем коде (я не помню всех деталей спецификаций JPA и обработки исключений с помощью динамического прокси, но есть некоторые сложные случаи).Этот вид кода может скрывать скрытые ошибки, поэтому стоит потратить время, чтобы сделать его пуленепробиваемым.

0 голосов
/ 07 мая 2010

В прошлом я использовал что-то похожее, но закодировано в hibernate API (это было до JPA). Доступ к данным для большинства типов DAO осуществлялся через интерфейс, названный в честь типа объекта, например, g. CustomerPersistence для управления клиентскими экземплярами. Такие методы, как findXXX, сопоставляются с именованными запросами, а имена параметров в методе сопоставляются с параметрами в запросе.

Реализация интерфейсов представляла собой прокси, которые использовали имя интерфейса, имена методов, имена параметров и т. Д. Для вызова соответствующих методов в hibernate API.

Это экономит много стандартного кодирования, с интуитивно понятным отображением базовой структуры доступа к данным, и делает для очень легкого моделирования уровня доступа к данным.

Итак, я определенно "одобряю" использование прокси.

...