Комментарии 29
Способ интресен.
Но я не очень люблю reflection из-за некоторых просадок по перфомансу (http://stackoverflow.com/questions/435553/java-reflection-performance). Так что лучше использовать исходя из потребностей.
Но я не очень люблю reflection из-за некоторых просадок по перфомансу (http://stackoverflow.com/questions/435553/java-reflection-performance). Так что лучше использовать исходя из потребностей.
+2
В данном конкретном случае была использована парадигма «Преждевременная оптимизация — корень всех зол» :)
И действительно, ни одна проблема, которая у нас возникала в продукте не имела корнем систему проксирования. Проблемы производительности сводились к частым обращениям на сервер, к непониманию предметной области и т.п. И, даже если в какой-то ситуации проблема будет вызвана рефлексией, то всегда можно это решить специальной обработкой. Причем не с помощью «костыля», а расширив соответствующим образом систему проксирования.
И действительно, ни одна проблема, которая у нас возникала в продукте не имела корнем систему проксирования. Проблемы производительности сводились к частым обращениям на сервер, к непониманию предметной области и т.п. И, даже если в какой-то ситуации проблема будет вызвана рефлексией, то всегда можно это решить специальной обработкой. Причем не с помощью «костыля», а расширив соответствующим образом систему проксирования.
0
По-моему, как-то очень громоздко.
Если уж у нас все равно имеет место быть такой момент, когда данные нужно «заполнить и отправить», то почему (нет, правда, почему?) этот момент нельзя контролировать? Ну то есть, вовремя заполнить и отправить на клиент DTO/ViewModel. При этом на сервере использовать в зависимости от задачи либо Dynamic Proxy для Hibernate (для Hibernate, кстати, ведь есть Proxy, как и для NHibernate, верно?), либо вообще просто проекции.
Если уж у нас все равно имеет место быть такой момент, когда данные нужно «заполнить и отправить», то почему (нет, правда, почему?) этот момент нельзя контролировать? Ну то есть, вовремя заполнить и отправить на клиент DTO/ViewModel. При этом на сервере использовать в зависимости от задачи либо Dynamic Proxy для Hibernate (для Hibernate, кстати, ведь есть Proxy, как и для NHibernate, верно?), либо вообще просто проекции.
+1
Для использования это совершенно не громоздко. Просто нужно написать интерфейс и все. Буквально.
Имплементация тоже достаточно простая. Насчет средств Hibernate — не скажу, что считаю себя большим специалистом в этой технологии. В основном я работал на уровне JPA. Но по-моему там нет ничего, что позволяло бы делать прокси методом «написал интерфейс и готово».
А что за проекции?
Имплементация тоже достаточно простая. Насчет средств Hibernate — не скажу, что считаю себя большим специалистом в этой технологии. В основном я работал на уровне JPA. Но по-моему там нет ничего, что позволяло бы делать прокси методом «написал интерфейс и готово».
А что за проекции?
0
Ну, в Hibernate я не знаток деталей, поскольку работаю с .NET и NHibernate, и вот в последнем есть как раз что-то типа плагина Dynamic Proxy (на базе Castle и LinFu), так что про прокси даже думать не приходится, можно просто использовать и все.
Проекция — это выборка сразу определенного набора данных, полей (но обычно не всех) под конкретную ситуацию, скажем так, «в обход сущности». Т.е., например, объект Person нигде не материализуется, а выбирается напрямую PersonViewModel, который и является проекцией. Это особенно удобно в .NET, поскольку и LINQ позволяет их очень легко создавать, и NHibernate их понимает. Но суть не поменяется, если использовать «старый добрый» NHibernate Criteria API и SetProjection().
Проекция — это выборка сразу определенного набора данных, полей (но обычно не всех) под конкретную ситуацию, скажем так, «в обход сущности». Т.е., например, объект Person нигде не материализуется, а выбирается напрямую PersonViewModel, который и является проекцией. Это особенно удобно в .NET, поскольку и LINQ позволяет их очень легко создавать, и NHibernate их понимает. Но суть не поменяется, если использовать «старый добрый» NHibernate Criteria API и SetProjection().
0
Смущает, что при таком подходе кроме основных сущностей (у меня их 20 + контроллеры отдельно), мне еще придется иметь туеву хучу прокси-объектов.
+1
а чем плох способ догружать данные только по мере необходимости их на клиенте? ведь уровни вложенности могут быть глубокими, и заранее все подгружать не всегда эффективно.
0
Почему плох? Все зависит от контекста использования. В определенных ситуациях постепенная подгрузка — это единственный вариант vs выгружать пол базы.
Насчет глубоких уровней вложенности — так данный подход как раз позволяет регулировать с точностью до поля уровень вложенности:
Допустим, есть интерфейсы IItem и IStrippedItem:
Если запроксировать сущность к IItem, то дети детей проксироваться не будут.
Насчет глубоких уровней вложенности — так данный подход как раз позволяет регулировать с точностью до поля уровень вложенности:
Допустим, есть интерфейсы IItem и IStrippedItem:
public interface IItem {
int getId();
void setId(int);
List<IStrippedItem> getChildren();
void setChildren(List<IStrippedItem> items);
}
public interface IStrippedItem {
int getId();
void setId(int);
}
Если запроксировать сущность к IItem, то дети детей проксироваться не будут.
0
Хм… по тексту у меня сложилось ощущение что классы сущностей отображаются на интерфейсы и обратно без изменений? (Person IPerson)
Если это так — то возможнбудет удобней Person Implements IPerson? тогда можно использовать extract interface/superclass + pull up methods. Пустячек а удобно. + шажок к ортодоксальному ООП)
И ещё — почему вы всёже не остановились на DTO(как упоминалось выше подмножество полей сущности/сущностей в зависимости от задачи)? Ведь если в Person есть связь многие- ко-многим — то прямая проекция создаст дополнительную (возможно значительную) нагрузках даже на простых операциях. Хотя с другой стороны прямая проекция + прокси может быть просто «частным случаем» традиционной кухни с DTO.
Если это так — то возможнбудет удобней Person Implements IPerson? тогда можно использовать extract interface/superclass + pull up methods. Пустячек а удобно. + шажок к ортодоксальному ООП)
И ещё — почему вы всёже не остановились на DTO(как упоминалось выше подмножество полей сущности/сущностей в зависимости от задачи)? Ведь если в Person есть связь многие- ко-многим — то прямая проекция создаст дополнительную (возможно значительную) нагрузках даже на простых операциях. Хотя с другой стороны прямая проекция + прокси может быть просто «частным случаем» традиционной кухни с DTO.
0
На первый взгляд красиво (интерфейс, магический класс), но писать POJO с нужными полями и конструктором от Person ничем не хуже, а даже немного лучше за счет производительности (без рефлексии), простоты кода (особенно, если геттеры и сеттеры генерируются Roo) и прямолинейности использования (передается параметр в конструктор, а не неочевидный класс для получения IPerson).
Что-то вроде:
Т.е. относительно интерфейса добавляется только конструктор, зато не нужно использовать сторонние классы. В IDE такой конструктор так же полуавтоматически создается.
Что-то вроде:
@RooJavaBean
public class PersonView {
private long id;
private String firstName;
private String lastName;
private List<PersonView> children;
public PersonView(Person p){
id = p.getId();
firstName = p.getFirstName();
lastName = p.getLastName();
//считаем, что children != null или добавляем проверки
children = new ArrayList<PesonView>(p.getChildren().size());
//for
}
}
Т.е. относительно интерфейса добавляется только конструктор, зато не нужно использовать сторонние классы. В IDE такой конструктор так же полуавтоматически создается.
0
Проще (вместо
ProxyFactory
) было бы написать аннотацию для Roo, которая бы создавала подобный конструктор (если руками по какой-то причине не хочется писать). Что-то вроде @RooProxyConstructor(Person.class)
. Не очень понятно какие проверки в ант-билдере, возможно он бы и не понадобился (или его достаточно просто адаптировать). Плюс Roo в том, что он срабатывает в момент компиляции, а не выполнения (как рефлексии). 0
Важное преимущество данного способа — эстетичность. Он не нарушает процесса понимания системы. Не портит и не усложняет восприятие. Реализовывал такое в одном из проектов: начитавшись, выбрал именно этот способ… «За красивые глаза», как говорится.
+1
Вот вариант с использованием кастомного генератора
Мне кажется, что это учитывает все ваши плюсы + генерация кода во время компиляции, а не во время выполнения (строго там не генерация кода, но нечто подобное).
RooProxyConstructor
для Roo (вместо написания ProxyFactory
и проверки для анта):@RooJavaBean
@RooProxyConstructor(Person.class)
public class PersonView {
private long id;
private String firstName;
private String lastName;
private List<PersonView> children;
}
Мне кажется, что это учитывает все ваши плюсы + генерация кода во время компиляции, а не во время выполнения (строго там не генерация кода, но нечто подобное).
0
НЛО прилетело и опубликовало эту надпись здесь
Секундочку, а что, OpenSessionInView уже отменили?
0
В распределенной архитектуре (бекенд-сервера и фронтенд-сервера) не поможет, а так да, еще есть :).
0
А, невнимательно прочитал пост. Сущности по проводам отправляются в другую JVM, ясно.
Понимаю, что сильно оффтопик, но из личного опыта знаю, что требования к содержимому этих сущностей на сервере и на клиенте очень сильно разные. В текущем проекте у нас веб-приложение (Spring+Hibernate, rich domain), REST API, и командная строка как один из потребителей этого REST API. Плюс флэшевый клиент, который по нашему недосмотру не работает через REST, а через BlazeDS Remoting работает с сервисами бизнес-логики.
Минусы — параллельные иерархии сущностей, хотя клиентские — намного проще, меньше подробностей, меньше заморочек с их взаимодействием.
Плюсы — изучил Скалу, пока писал парсеры для REST API, все действия проходят через сервисы, не нужно заморачиваться с проблемами, описаными в посте.
Честно говоря, я бы ни за что не подписался посылать хайбернейтовские/JPA сущности по проводам никуда. Уж больно много потенциальных проблем.
Но если бы пришлось — стал бы смотреть в сторону распределенных кэшей, или оригинальной Терракоты.
Понимаю, что сильно оффтопик, но из личного опыта знаю, что требования к содержимому этих сущностей на сервере и на клиенте очень сильно разные. В текущем проекте у нас веб-приложение (Spring+Hibernate, rich domain), REST API, и командная строка как один из потребителей этого REST API. Плюс флэшевый клиент, который по нашему недосмотру не работает через REST, а через BlazeDS Remoting работает с сервисами бизнес-логики.
Минусы — параллельные иерархии сущностей, хотя клиентские — намного проще, меньше подробностей, меньше заморочек с их взаимодействием.
Плюсы — изучил Скалу, пока писал парсеры для REST API, все действия проходят через сервисы, не нужно заморачиваться с проблемами, описаными в посте.
Честно говоря, я бы ни за что не подписался посылать хайбернейтовские/JPA сущности по проводам никуда. Уж больно много потенциальных проблем.
Но если бы пришлось — стал бы смотреть в сторону распределенных кэшей, или оригинальной Терракоты.
0
Секундочку, а как всё-таки вы решаете проблему с ленивой инициализацией?
Прокси, создавая объект по переданному ей интерфейсу, заполняет его всеми данными из
переданного ей объекта examplePerson? То есть examplePerson загружается из базы целиком, даже если в этом нет особой необходимости? В этом случае можно было использовать EAGER.
По-моему что-то опять не так в консерватории.
Прокси, создавая объект по переданному ей интерфейсу, заполняет его всеми данными из
переданного ей объекта examplePerson? То есть examplePerson загружается из базы целиком, даже если в этом нет особой необходимости? В этом случае можно было использовать EAGER.
По-моему что-то опять не так в консерватории.
0
Хибернейтовские сущности в прокси не попадают. Entity-поля заменяются прокси.
0
И какие действия осуществляет прокси при обращении к её полям?
0
У прокси внутри лежит Map [имя поля -> значение]. Значения в нем — это или примитивные типы или другие прокси. Прокси, при обращении к полям возвращает или записывает значение из мэпа.
0
То есть из базы вытаскивается всё, в случае вложенности? И до какого предела? Или прокси поддерживает соединение?
А в случае изменения сущности что прокси делает?
Давайте код прокси этой, спрашивать тут вечно можно.
А в случае изменения сущности что прокси делает?
Давайте код прокси этой, спрашивать тут вечно можно.
0
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.
Способ проксирования JPA сущностей для клиента (борьба с lazy initialization)