Как уровень интеграции взаимодействует с бизнес-уровнем?

#java #rest #jakarta-ee #ejb #n-tier-architecture

#java #rest #джакарта-ee #ejb #n-tier-architecture

Вопрос:

Мне нужен совет по проектированию «Уровня интеграции» N-уровневой системы на Java. Этот уровень отвечает за сохранение и извлечение данных для «Бизнес-уровня» (расположенного на отдельном сервере). Я новичок в J2EE и прочитал несколько книг и блогов. Алфавитный набор технологических сокращений сбивает меня с толку, поэтому у меня есть несколько вопросов.

Во-первых, что у меня есть на данный момент: я использую JPA (через Hibernate) для сохранения и извлечения данных в базу данных. Я создал свои объекты доступа к данным EJB и планирую развертывание на сервере приложений (JBoss), что упрощает транзакции (они находятся на функциональном уровне моего DAO), и мне не нужно беспокоиться о получении дескриптора EntityManager (внедрение зависимостей). Вот пример того, как все выглядит:

 @Entity
class A{
  @Id
  Long id;
  @OneToMany
  List<B> setOfBs = new ArrayList<B>;
}

@Entity
class B{
  @Id
  Long id;
}

@Remote
public interface ADAO{
  public A getAById(Long id);
}

@Stateless
class ADAOImpl implements ADAO{
  @PersistenceContext
  EntityManager em;

  public A getAById(Long id){ ... }
}
  

Мой вопрос: Как бизнес-уровень должен обмениваться данными с уровнем интеграции. Я прочитал о службах RESTful, и они кажутся достаточно простыми. Меня беспокоит производительность, когда увеличивается частота получения и установки (HTTP-связь не кажется особенно быстрой). Другой вариант — RMI. Мои DAO уже являются EJB. Могу ли я просто предоставить бизнес-уровню доступ к ним напрямую (через JNDI)? Если да, то что произойдет, если ссылка @OneToMany в приведенном выше примере загружается лениво?

Например, если бизнес-уровень выполняет что-то вроде следующего:

 Context context = new InitialContext(propertiesForIntegrationTierLookup);
ADAOImpl aDao = (ADAOImpl) context.lookup("something");
A myA = aDao.getAById(0);
int numberOfBs = myA.setOfBs.size();
  

Если список setOfBs загружается медленно, когда бизнес-уровень (на отдельном сервере) обращается к списку, правильный ли размер? Список каким-то образом правильно загружается с помощью магии EJBs? Если нет (чего я ожидаю), то каково решение?

Извините за длинный пост. Как я уже сказал, я новичок в J2EE, и я прочитал достаточно, чтобы получить общее представление, но мне нужна помощь в сборке частей вместе.

Ответ №1:

Когда вы вызываете size () в lazy collection, он инициализируется, поэтому вы всегда получите правильный размер, независимо от того, какой интерфейс вы используете — удаленный или локальный.

Другая ситуация заключается в том, что вы пытаетесь использовать классы JPA в качестве объектов передачи данных (DTO) и запрашивать их через удаленный интерфейс. Я не помню здесь никаких проблем с отложенной инициализацией, потому что перед передачей все объекты должны быть сериализованы (с инициализацией отложенных коллекций) на стороне сервера. В результате весь объектный граф передается по сети, что может привести к серьезным перегрузкам процессора и сети. Кроме того, чтобы десериализация была возможной, вам придется совместно использовать классы JPA с удаленным приложением. И на этом «магия EJB» заканчивается 🙂

Итак, как только станут возможны удаленные вызовы, я бы предложил начать думать о стратегии передачи данных и объектах передачи данных, отличных от JPA, в качестве дополнительного уровня данных. В моем случае я аннотировал классы DTO для привязки XML (JAXB) и повторно использовал их в веб-сервисах.

Комментарии:

1. Я воспользовался вашим мнением и провел последние несколько дней, изучая шаблоны проектирования EE. Похоже, у меня есть два варианта передачи данных между уровнем интеграции и бизнес-уровнем: DTO или REST. Кажется, что использование DTO приведет к появлению большого количества дополнительного кода на уровне интеграции (преобразование из класса A Doman в DTO B и т.д.), Но DTO могут быть повторно использованы на бизнес-уровне. REST было бы легко для уровня интеграции, но бизнес-уровень должен был бы выполнять основную работу по синтаксическому анализу, и производительность может быть проблемой. Ни одно из решений не кажется идеальным. Есть ли третий вариант?

2. Упс, я не имел в виду REST. Двумя вариантами могут быть либо DTO, либо какой-либо текстовый метод, например XML.

Ответ №2:

Краткий ответ: Если вы используете подход «Уровня интеграции», то то, что вы должны интегрировать, должно быть слабосвязанными сервисами, следующими принципам SOA.

Это означает, что вы не должны разрешать удаленные вызовы методов в объектах, которые могли бы выполнять вызовы фреймворка под прикрытием на другом сервере. Если вы сделаете это, вы действительно создадите тесно связанное распределенное приложение, и вам придется беспокоиться о проблемах с отложенной загрузкой и области действия контекста сохранения. Если вы хотите этого, вы могли бы рассмотреть расширенные контексты сохраненияhttp://docs.jboss.org/ejb3/docs/tutorial/extended_pc/extended.html .

Вы говорили о «бизнес-уровне», но JPA не предоставляет бизнес-уровень. Он предоставляет сущности и допускает операции CRUD, но обычно это не бизнес-операции. операция «registerUser» — это не просто вопрос сохранения объекта «User». Ваш уровень DAO может предлагать более высокий уровень работы, но DAO обычно используются для размещения тонкого слоя поверх базы данных, но он по-прежнему очень ориентирован на данные.

Лучший подход — определить операции типа бизнес-сервиса и сделать их сервисами, которые вы предоставляете. Возможно, вам нужен другой уровень поверх вашего DAO или вы можете захотеть иметь один уровень (преобразовать ваш уровень DAO).

Ваш бизнес-уровень должен вызывать flush и обрабатывать любые исключения JPA и скрывать все это от вызывающего.

Остается вопрос о том, как передавать ваши данные. Во многих случаях параметры ваших запросов на бизнес-сервис будут похожи на ваши объекты JPA, но я думаю, вы заметите, что часто существуют достаточные различия, из-за которых требуется определить новые DTO. Например, бизнес-операция «registerUser» может обновлять таблицу «User» и «EmailAddresses». Пользовательская таблица может включать свойство «CreatedDate», которое не является частью операции «registerUser», но установлено на текущую дату.

Для создания DTO вам, возможно, захочется взглянуть на Project Lombok.

Чтобы скопировать DTO в объект, вы можете использовать Apache Commons BeanUtils (например, PropertyUtils.copyProperties), чтобы выполнить большую часть работы, которая работает, если имена свойств совпадают.

Лично я не вижу смысла в XML в этом случае, если вы не хотите полностью отделить свои реализации.