| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java EE (J2EE) и Spring > Взаимодействие приложений внутри контейнера |
| Автор: Stampede 8.2.2006, 19:36 |
| Всем привет! Взываю к коллективной мудрости. Есть такая задачка. Дано: имеется вебсайт, внутри которого развернуто несколько контекстов == независимых приложений. Вопрос: как с минимальными затратами усилий организовать доступ одного приложения к данным другого, используя тот факт, что они хоть и не видят друг дружку напрямую, но находятся, так сказать, на расстоянии вытянутой руки: то есть на одном физическом боксе, внутри одного контейнера, на одном диске, и т. д. Навскидку в голову приходит:
Первое не нравится по ряду причин: необходимость синзронизации, разработка формата хранения и пр. По поводу JNDI - никогда вплотную не работал; не знаю, насколько сложно будет реализовать провайдера. Про третье вообще не представляю, возможно ли такое. У кого какие будут предложения? |
| Автор: ivg 9.2.2006, 01:08 |
| Можно я тоже предложу ещё пару вариантов... Первое что приходит в голову - взаимодействие через сокеты. Один контекст может быть клиентом другого, и наоборот. Конечно с "мин. затратами " тут сложно, но зато такой вариант "абсолютно" не зависит от контейнера. Подходит видимо для простых вариантов взаимодействия. Ещё можно посмотреть в сторону JMS. Вот тут мне кажется с минимальными усилиями получше. Доступ из разных контекстов можно через общий JNDI ресурс, вроде есть поддержка транзакций и т. д. http://java.sun.com/products/jms/ |
| Автор: tux 9.2.2006, 03:30 |
| Еще один вариант - embedded database как улучшенный вариант хранения в файле. Я был предпочел хранить разделяемые ресурсы в JNDI, собственно для того он и предназначен, но этот вариант не всегда подходит. Например, в Tomcat JNDI - readonly. |
| Автор: Stampede 9.2.2006, 12:56 |
| Через базу данных - это вообще не вопрос. Тут даже не обязательно использовать embedded. Хотелось чего-нибудь попроще. По поводу JNDI. Посмотрел в доке по томкату, там приводится пример реализации кастомного провайдера. Как-то показалось муторно. В таком случае я бы уж лучше забурлапил, простите за выражение Очень жаль, что нет какой-то стандартной реализации простейшего JNDI-сервиса, типа распределеного мапа: положил что хочешь по ключу, взял что хочешь по ключу. Ну и все-таки надеюсь, что может быть есть какой-то внутриконтейнерный программный механизм, пусть даже и нестандартный. Буду смотреть дальше. |
| Автор: tux 9.2.2006, 13:25 |
По-моему JNDI в данном случае все-таки то, что надо. Такой геморрой с ним насколько я знаю только у кота Тома, в других серверах приложений реализации JNDI вполне приемлемы для использования. Еще парочка вариантов:
|
| Автор: chief39 9.2.2006, 18:36 |
| Может я не понимаю сути проблемы.... Но чем не подходят локальные интерйфейсы для бинов? Насколько я понимаю, ограничения в "пределах приложения" - нет, ограничение - в пределах одной jvm. И затраты гораздо меньше чем для удалённых(То есть то, что требуется) Или суть где-то не тут? |
| Автор: Stampede 9.2.2006, 20:32 |
| О каких бинах речь? EJB? Нет, спасибо, я лучше постою Второе: тот факт, что приложения сидят в одной JVM, еще не означает, что они могут свободно общаться по локальному интерфейсу, поскольку в общем случае загружаются разными загрузчиками и о друг дружкиных классах ничего не знают. Так-так-так... Пожождите секундочку... Пытаюсь ухватить мысль за хвост. А что если... Что если ту часть функциональности, которая должна быть доступна извне, выполнить в виде отдельного модуля (jar), положить его в директорию common и описать в виде статического JNDI ресурса? Тогда второе приложение в одну строчку получает ссылку на него и дальше работает с модулем как со своим родным! Фсе, щас буду пробовать. Stay tuned! |
| Автор: Nobody 10.2.2006, 15:20 | ||||
Кажется кто-то противоречит самому себе. |
| Автор: 3,14 10.2.2006, 15:50 |
| Может через RMI? поднять RMI сервер, зарегистрировать на нём общие для контекстов классы, и вызывать их методы, когда возникает в этом надобность... |
| Автор: Stampede 11.2.2006, 01:25 | ||
| Все, обошелся малой кровью. Рассказываю. Ту часть функциональности, что должна быть доступна из другого приложения, вынес в отдельный проект. Получившиеся в результате скомпилированные классы запаковал в архив и задеплоил в директорию томката shared. Подключил его как внешнюю библиотеку к проектам обоих приложений. Доступ к модулю из обоих приложений происходит через синглтон. Чтобы не тащить в модуль кучу зависимостей из основного приложения, пришлось описать функциональность модуля в виде интерфейсов и предусмотреть явную инициализацию экземпляров конкретными классами из кода основного приложения. Попробовал - все работает. И слава богу. Так я в очередной раз нашел лазейку, чтобы не связываться с JNDI - не знаю уж, хорошо это или плохо. Ну не понимаю я, что это за штука и как ей пользоваться. А особенно убивает невнятность терминологии. Когда я вижу в примерах:
В этот момент мои мозги полностью теряют нить и дальше я вообще уже ничего не соображаю. Какой в задницу инишиал контекст??? Контекст чего? О чем это вообще? Как в принципе можно запомнить java:comp/env? Что это должно означать? Короче, ну его нафиг... до следующего раза |
| Автор: tux 11.2.2006, 06:35 | ||||||||||||||||||||
| Почему-то мне всегда казалось, что JNDI - вещь довольно простая, поэтому решил накидать небольшую статейку для FAQ. Сам по себе JNDI - просто набор интерфейсов, что в общем-то обычная практика - Sun определяет интерфейс, множество производителей пишут свои реализации. То же самое касается таких технологий, как JDBC, JMS и иже с ними. Более того, за интерфейсом JNDI могут скрываться такие сервисы как LDAP, DNS и т.п., а провайдер JNDI в этом случае обеспечивает единый интерфейс к любому сервису каталогов, хоть к файловой системе. С большинством реализаций JNDI можно работать удаленно, помещая в каталоги различные объекты и получая их оттуда. С чего начинается работа с JNDI? Все просто - получаем InitialContext (затрудняюсь с точным переводом, поэтому назову этот объект начальным контекстом). Вообще говоря, спецификация JNDI не определяет понятия абсолютного корня в дереве, зато у нас есть начальный контекст с которого и можно начать работу с каталогами. Получаем этот начальный контекст так:
Возникает вопрос - а чего же все так просто если сервис сетевой? На самом деле каждый производитель может реализовать свой класс javax.naming.InitialContext, который, во-первых, знает как этот удаленный сервис найти и, во-вторых, работать такая конструкция будет только внутри сервера приложений, который и предоставляет свою реализацию и где JNDI-сервис работает в той же JVM. Если есть необходимость поработать с сервисом удаленно или из другой java-машины, способ немного усложнится. Тогда нам нужен файл jndi.properties, в котором будут указаны параметры подключения к сервису. Например, для JNDI от сервера приложений Orion параметры могу выглядеть так:
Здесь задаются:
Как альтернативу можно рассматривать передачу параметров непосредственно в начальный контекст:
Какие операции нам теперь доступны? Основные - это поместить объект в каталог и получить его из каталога. Публикация объекта в дерево каталогов выполняется следующим образом:
Выборку объекта можно выполнить так:
Большинство реализаций могут публиковать объекты, реализующие интерфейсы java.io.Serializable и java.rmi.Remote, что дает большие возможности для обмена данными между приложениями, находящимися в разных JVM или даже на разных компьютерах. Интерфейс JNDI предоставляет множество других возможностей, подробное описание которых займет много места, поэтому просто их перечислю:
Теперь о том, что такое java:comp:/env. Сложно сказать что Sun этим подразумевает, думаю что Java Component Environment. Если JNDI вообще может использоваться в любом Java-приложении, то понятие java:comp:/env тесно связано с приложением J2EE. Я уже говорил, что в JNDI нет четко заданного корня. Так вот, все что находится в JNDI в каталогах, начинающихся с такой строки относится только (!) к тому приложению J2EE (веб-приложению или EJB-компоненту), в котором выполняется работа с деревом каталогов. Можно положить, например, в узел java:comp:/env/jdbc/DS какой-нибудь источник данных и он будет доступен только из данного приложения. Ресурсы, доступные внутри пространства имен приложения, можно задавать декларативно в web.xml или ejb-jar.xml для EJB-компонентов. Далее пара примеров. В следующем помещаем в пространство имен приложения два объекта:
web.xml:
Получение объекта источника данных, который хранится в JNDI:
web.xml:
Существует соглашение (не обязательное для исполнения) насчет начального контекста для различных типов объектов в пространстве имен приложения:
В веб-контейнере Tomcat для приложений существует только локальный контекст, при этом доступный только для чтения, поэтому возможно только декларативное размещение ресурсов. Большинство остальных реализаций JNDI вполне функциональны. Ну и в завершении. JNDI является мощным средством обмена данными между приложениями. Более того, J2EE-приложения, использующие в работе EJB или JMS, не могут обойтись без использования JNDI, который хранит ссылки на другие используемые компоненты, очереди сообщений и т.п. |
| Автор: batigoal 11.2.2006, 23:39 |
| Статья добавлена в FAQ. Огромное спасибо, tux. |
| Автор: Stampede 14.2.2006, 02:50 | ||||||
tux, большое спасибо за подробную статью. Кое-что стало проясняться, но остается ряд непонятных моментов. Буду очень признателен, если сможешь растолковать.
Кажется, я начинаю догонять, что именно меня смущало сильнее всего: инициализация контекста JNDI - это по сути задача для фабрики, а они взяли и скрыли это за фасадом POJO, каковым внешне выглядит класс InitialContext. Правильно ли я понял? Но тогда непонятно звучит следующая фраза:
Это же класс, а не интерфейс, как его можно подменить? И потом, я так и не понял, есть ли дефолтная локальная реализация сервиса JNDI. Я было сейчас попытался написать самую простую программку:
А оно пишет: "javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file: java.naming.factory.initial". То есть дефолтной фабрики нет? А что, так трудно было сделать? И зачем в таком случае было предоставлять беспараметрный конструктор InitialContext()? Типа чтобы можно было в проперях указывать класс фабрики? Ну ладно, хорошо если прога работает в контейнере - там есть какая-никакая реализация. А если сервер standalone? Кстати, когда ты говоришь, что в томкате JNDI сервис readonly, что значит readonly? Что я не могу вызывать bind()? Ну и толку тогда от него, кроме как получать датабазные DataSource? Кстати, посмотрел на их http://tomcat.apache.org/tomcat-4.1-doc/jndi-resources-howto.html. они поддерживают выдачу бинов только в режиме new instance, но не разделяемой (синглтонной) копии. Но ведь пойнт-то как раз в том, чтобы иметь централизованный репозитарий разделяемых объектов! Создать новый экземпляр бина я ведь могу и просто конструктором. Ну да, я согласен, что в случае с JNDI они заодно еще и централизованно присвоят параметры инициализации, но хотелось бы большего. Теперь что касается практического использования. Допустим, с фабриками мы как-то разобрались, и у нас есть более-менее полноценный сервис. Предположим, я хочу хранить в JNDI конфигурацию. Вот я получил по lookup() объект этой самой конфигурации - для простоты скажем HashMap. А если я теперь что-нибудь туда добавлю? Оно ведь отразится только в моей локальной копии мапа? Значит, чтобы все остальные проги увидели мои изменения, я должен сделать rebind()? Я понимаю, что если я хочу к чему-то обращаться удаленно, то я должен сначала запрограммировать его как удаленный ресурс. Например, в случае с конфигурацией предусмотреть Remote интерфейс для добавления/модификации параметров. Но если я это сделаю, то я и обращаться к нему смогу просто по RMI, безо всяких JNDI. Ах, да, JNDI ведь в первую очередь предоставляет naming сервисы. Вы не обращайте внимания: это я просто пишу и по ходу пытаюсь что-то для себя прояснить - вроде как мысли вслух. В общем, мне кажется, я начинаю что-то понимать: очевидно, JNDI задумывался как механизм, на базе которрого можно было бы строить распределенные системы - и в первую очередь серверы приложений EJB. Вот только опять в погоне за универсальностью забыли про нужды простых парней, в результате чего попытка использования этого механизма вне J2EE окружения превращается в сплошной геморрой, что наглядно продемонстрировал мой опыт поиска решения проблемы, описанный в первых постах этого топика. А всего-то делов было:
Если бы это было сделано, я бы, вполне возможно, решил вопрос средствами JNDI и сейчас спал бы спокойно, зная, что решение будет работать и из теста, и в томкате, и поперек любых других контейнеров. Да вот, блин, не судьба. |
| Автор: tux 14.2.2006, 06:33 | ||||||||||
Это я несколько неправильно выразился. Процесс выглядит так:
Здесь обрадовать нечем - дефолтной нет. Есть несколько реализаций от Sun:
Если сервер standalone, можно в принципе запустить сервис JNDI из JVM. Несколько ссылок на реализации я давал, еще обнаружил что сервис JBoss может работать независимо.
Вот это и значит. Зачем он нужен мне тоже не ясно, кроме DataSource и каких-нить MailFactory ничего в голову не приходит. Так ведь еще и обратиться напрямую к имени не удается, только через java:comp:/env. У меня есть системка, связанная с отчетами. Так вот описания отчетов я храню в JNDI. Тестил на нескольких контейнерах - Orion, Jetty, JBoss, все распрекрасно работало до тех пор пока я не решил потестить на Tomcat. Вот тут и вылезла его гнилая сущность.
Думаю все-таки не совсем так. Это в первую очередь универсальный интерфейс для любого сервиса каталогов и лишь одно из его назначений - это организация связи между компонентами в распределенных системах. Чтобы использовать JNDI вне J2EE всего-то надо - задать пару-тройку свойств. Раньше часто тестил EJB внешними клиентами. Задал памаметры подключения к JNDI, получил ссылку на удаленный интерфейс EJB и тести сколько влезет. А EJB при этом на удаленном сервере задеплоен, сервер приложений ресурсы не жрет на локальной машине. Красота
Да, есть такая проблема, но, по-моему, вызов rebind() - небольшая плата за сервис, в котором объект можно положить в каталог или получить из него удаленно. В общем если бы не Tomcat, я бы вообще не сомневался, что JNDI в данном случае - лучшее решение. То, что одна единственная реализация (причем эталонная!!!) подкладывает такую свинью мне кажется неправильным. |
| Автор: Stampede 14.2.2006, 08:14 |
| tux, дружище, спасибо за подробные ответы. Пробел с JNDI в моем арсенале можно считать ликвидированным Сверлите дырочку на мундире |
| Автор: 3x3 1.10.2006, 19:28 | ||||||
Как ваши изыскания на эту тему, chief39? Очень любопытно, ходят ли вызовы между приложениями из одного и/или разных контекстов одного и того же контейнера друг к другу напрямую или как удаленные вызовы. |
| Автор: chief39 3.10.2006, 13:32 | ||||
Это взято http://java.sun.com/products/ejb/2.0.html Насчёт
так и осталось слухом. Не искал подтверждения. Скорее всего утка. Хотя... кто знает... кроме самих производителей |
| Автор: w1nd 3.10.2006, 13:53 | ||||
WebLogic точно поддерживает. |
| Автор: tux 3.10.2006, 13:56 |
| Могу еще подтвердить насчет Orion (и, видимо, Oracle Application Server). А вообще реализовать не очень сложно, думаю многие AS поддерживают. |
| Автор: chief39 3.10.2006, 14:48 | ||
Спасибо 3x3, собсссно, ответ |
| Автор: 3x3 4.10.2006, 01:21 |
| М-да.. Весь день пытаюсь понять - радоваться мне или огорчаться от такого ответа.. С одной стороны - классно, что это где-то реализовано. С другой - грустно, что не везде. |
| Автор: chief39 5.10.2006, 13:12 | ||
А что случилось-то? |