| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > Java: Общие вопросы > Пути к конфигурационным файлам |
| Автор: jah2 8.5.2013, 22:20 |
| Такой параметр приложения, например, как строка соединения, в виду удобства изменения, рекомендуется хранить в отдельном файле. Вопрос в том, где лучше хранить этот файл и как получать к нему доступ? Что имеется в виду. В конечном итоге, приложение будет запаковано, например, в war- или ear-архив и будет помещено (развернуто) в рабочую директорию сервера приложений. Насколько я сейчас понимаю, из кода мы можем получать доступ к файлам только по абсолютным или относительным путям по отношению к доступным для сервера приложений дискам. То есть, условно говоря, если архив приложения лежит в директории D:\upload\ , то относительный путь ../ выведет нас в корень диска D, другими словами, используемые в коде относительные пути никак не связаны со структурой каталогов приложения в его архиве. Не знаю, как это обычно делается, поэтому предполагаю, что было бы удобным хранить конфигурационный файл со строкой соединения в самом архиве приложения, оттуда и считывать, тогда при необходимости модификации, открываешь этот архив, изменяешь этот файл, приложение начинает работать с другой строкой соединения, то есть приложение и его конфигурационный файл в одном месте (в архиве приложения). Иначе пришлось бы иметь на руках как архив приложения, так и конфигурационный файл, архив деплоить на сервер приложений, конфигурационный файл дополнительно размещать в какой-нибудь директории диска. Если так, то непонятно как получать доступ к этом файлу. Наилучшим способом видится использование относительных путей, наподобие того, как если page1.jsp и page2.jsp имеют одно расположение в архиве, то <%@ include file="page2.jsp" %> позволит включить page2 в page1, но при работе с файлами такие относительные пути не прокатывают. В общем, прошу направить в нужном направлении как это всё делается. |
| Автор: batigoal 8.5.2013, 23:32 |
| Это действительно несколько неловкий момент. Дело в том, что разные сервера приложений по-разному формируют свои classpath'ы и, соответственно, по-разному разрешают относительные пути. Например, у JBoss можно положить конфиг в server/your_configuration/config/ и доступаться к нему через путь ./my_config.properties. А вот в Glassfish 2, например, мы клали конфиги в my_domain/lib/classes, чтобы они были доступны по аналогичному пути. Держать же конфиги в архиве - плохой путь, слишком велико неудобство модификации и вероятность ошибки юзера (запакует war zip-архиватором со сжатием - и сгорим в кислороде). |
| Автор: jah2 8.5.2013, 23:58 |
| может тогда выделять отдельную директорию на диске и туда класть все конфиги, не завязываясь на директории сервера приложений хотя я не совсем представляю такой момент: каждый сервер приложений предоставляет некоторое местоположение для хранения конфигурационных файлов развёртываемых на нём приложений и способ доступа к этим файлам, так это нужно понимать? |
| Автор: COVD 10.5.2013, 22:47 | ||
Проблема, наверное не в месте хранения настроек, а в желании их редактировать "на лету".
Откуда приложение знает, что файл изменился? А если узнает, оно умеет корректно переключаться, т.е. завершать все текущие задачи со старым соединением, а потом продолжать с новым соединением? Стандартным конфигурационным файлом является web.xml (по крайней мере, в Томкате). Чтобы изменить настройки, надо удалить war из webapps (undeploy), отредактировать web.xml внутри war, положить war в webapps (deploy). В этот момент новые настройки вступят в силу. Это неудобно, но контейнер (Томкат) сам может сделать корректный undeploy, т.е. дождаться когда текущие запросы к приложению обработаются (а новые не принимать), и только после этого выключить приложение. |
| Автор: jah2 10.5.2013, 23:12 |
| COVD, в данном случае я рассматриваю более простые изменения например, даёшь админу war-архив и говоришь, что вот здесь в отдельном файле пропишешь строку соединения (приложение соответственно подхватит эту строку из этого файла и для того, чтобы поменять эту строку, не нужно будет лезть в приложение) Добавлено через 4 минуты и 56 секунд была мысль дать возможность настройки при входе с админскими правами, но всё равно придётся сохранять их где-то во внешнем файле по отношению к архиву приложения, то есть это жёстко привяжет приложение к выбранному расположению этого настроечного файла |
| Автор: jah2 10.5.2013, 23:28 |
| хотя я собственно этот вариант и имел в виду сначала: хранить настройки в самом архиве (batigoal, сказал, что не стоит и если говоришь, как-то можно взять данные из web.xml (я думал там размещаются только некие стандартные заранее определённые настройки), то это хорошо, прогуглю эту тему, спасибо |
| Автор: LSD 13.5.2013, 12:49 |
А что не так со сжатием? |
| Автор: jah2 14.5.2013, 18:09 |
| Кто-нибудь знает и может намекнуть как взять данные из xml-файла, находящегося в архиве приложения (например, из того же web.xml)? Прогугливаю эту тему, пока не могу найти ничего похожего, поосвоился даже с xml-парсерами, но в них также используются пути, завязанные на расположение на самом диске, но не в архиве приложения. Обращаться к самому архиву, как он расположен на диске в рабочей директории сервера приложений, не вижу смысла, так как это привяжет приложение к расположению самого сервера приложений. |
| Автор: jah2 14.5.2013, 18:55 |
| LSD, их смотрел (кроме jaxb) + jdom, но там пути также указываются не по отношению к тому как они располагаются в архиве приложения. Например, у меня есть war-архив и мне нужно в index.jsp получить данные из web.xml в том же архиве, путь WEB-INF/web.xml не укажет мне на этот файл. |
| Автор: LSD 14.5.2013, 18:57 | ||||
|
| Автор: jah2 14.5.2013, 19:16 |
| LSD, может я что-то принципиальное не понимаю в InputStream сейчас для того, чтобы обратиться к файлу я бы стал использовать FileInputStream, передав ему, например, путь к файлу, но опять же это путь по отношению к диску, а не к тем расположениям, которые есть в архиве приложения какой момент я здесь не догоняю, что нужно использовать у InputStream, чтобы получить доступ к файлу в архиве? |
| Автор: LSD 14.5.2013, 19:22 | ||
это если он в classpath, если нет то смотреть в сторону ZipFile (можно и ZipInputStream, но это сложнее). |
| Автор: jah2 14.5.2013, 19:35 |
| так про то и речь, что смысла обращаться к архиву приложения по его расположению на диске смысла нет, так как при переносе на другой сервер приложений путь изменится и обратиться по этому пути к файлу уже не будет возможности хотя бы если этот архив разворачивался в реальные директории на диске, тогда стандартные .. позволили бы выйти на уровень вверх, но, например, на weblogic они выведут в основную директорию домена экземпляра сервера приложений, то есть совсем не туда, куда хотелось бы |
| Автор: COVD 14.5.2013, 21:13 | ||||
| jah2 Если вы пытаетесь извлечь параметры из web.xml, то надо там описать параметры и класс - лисенер.
Класс, который получит сообщения на deploy и undeploy
|
| Автор: jah2 14.5.2013, 21:31 |
| COVD, спасибо, это уже шаг вперёд то есть существует некий встроенный механизм для извлечения данных чисто из web.xml буду смотреть, может отсюда и до произвольного xml-файла в архиве приложения удастся достучаться |
| Автор: Mirkes 15.5.2013, 11:06 | ||
| Если я правильно понимаю LSD иммел в виду доступ к любому файлу в архиве приложения стандартным для Java путем. Пусть у меня в архиве приложения есть специальная папка resource, где я храню разные нужные файлы (картинки, конфигураторы и т.п.) Причем папка resource хранится в корне архива. Тогда доступ к файлу chtoto.fil легко получить
А дальше делайте с ним что хотите. Причем где физически лежит архив вас не касается. |
| Автор: LSD 15.5.2013, 12:00 | ||
Про файлы это ты постоянно упоминаешь, я говорю про ресурс. У ресурса есть некий путь, но это путь относительно classpath, никаких "расположений на диске", "на уровень вверх" у ресурсов нет. Единственный момент, это поместить ресурсы в classpath, но это несложная задача для любого вменяемого сервера приложений. |
| Автор: jah2 15.5.2013, 20:25 |
| Mirkes, LSD, спасибо за пояснения, буду разбираться, скорее всего я как раз и недопонимал эту абстракцию с ресурсом в официальной документации пока не нашёл (их терминология, у них наверное и должно быть точно определено что это такое и с чем это едят), но эта статья вроде проясняет о чём речь http://skipy-ru.livejournal.com/5343.html про то, что говорил COVD, нашёл неплохое описание здесь http://docs.oracle.com/cd/E13222_01/wls/docs81/webapp/web_xml.html http://docs.oracle.com/cd/E13222_01/wls/docs81/webapp/app_events.html |
| Автор: jah2 17.5.2013, 18:23 | ||
| Вроде удалось освоится с classpath и ресурсами (и даже словил некоторую эйфорию от этих знаний http://docs.oracle.com/javase/1.3/docs/guide/resources/resources.html http://docs.oracle.com/javase/tutorial/essential/environment/paths.html ....... На данном этапе хотелось бы ответить ещё на несколько важных для понимания вопросов, которые возникли при изучении этой темы: 1. конструкция MyClass.class - позволяет получить ссылку на объект класса Class, который автоматически создаётся при загрузке класса MyClass в память виртуальной java-машины (JVM). Под загрузкой класса MyClass в память JVM, как я понимаю, понимается загрузка байт-код класса MyClass из файла MyClass.class, сам объект класса MyClass ещё не создан. class - это свойство этого объекта типа Class, то есть пишем MyClass.class, на самом деле имеется в виду объект_типа_Class_для_класса_MyClass.class Я правильно понял? 2. System.getProperty("java.class.path") - возвращает строку, состоящую из всех classpath в системе, в том числе в Windows туда в качестве подстроки попадает значение переменной среды (окружения) CLASSPATH. Так? 3. Как получить доступ к ресурсу из сервлета, не создавая дополнительных классов? Например, код страницы index.jsp
При трансляции страницы index.jsp в класс сервлета эти две строчки скриптлета попадут в метод service() класса этого сервлета. При первом запросе страницы index.jsp класс сервлета будет загружен в память JVM, будет создан объект этого класса и произойдёт инициализация (считаются параметры конфигурации из дескриптора развёртывания и т.п.) Далее будет вызван метод service() у этого объекта (последующие запросы к index.jsp также приведут к вызову метода service()) и соответственно вызов этих двух строчек внутри него. getClass() вернёт Class-объект для класса сервлета. То что, ресурс не будет найден, понятно, так как class-файл сервлета имеет другое расположение нежели страница index.jsp На weblogic server, если я правильно понял (нашёл), они хранятся (то есть weblogic всё-таки разворачивает приложение в реальные директории), например, при использовании war домен\servers\имя_сервера\tmp\_WL_user\...\jsp_servlet\ а само содержание домен\servers\имя_сервера\tmp\_WL_user\...\war\ Тут ещё есть, конечно, над чем поэкспериментировать, и возможно найти ответ конкретно для weblogic, но не факт, что это подойдёт для других серверов приложений. Поэтому вопрос: как быть? (В том смысле что подключение к странице некоторого класса через <jsp:useBean и вызов getClass() оттуда даст результат, но единственное ли это решение или всё-таки можно как-то получить ресурс из сервлета, не создавая дополнительный класс, есть ли какой-нибудь другой универсальный способ?) |
| Автор: jah2 18.5.2013, 22:58 | ||||
| по первому вопросу я погорячился со свойством, так как явно такого свойства у Class не отмечено http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html отсюда ищем в спецификации class literal
http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.8.2
В общем, слово class является частью выражения под названием class literal (литерал класса), которое (выражение) вычисляется для объекта типа Class .... Так очевидно и стоит это воспринимать, не более (не ведя речь ни о каких свойствах, хотя, так как оно пишется через точку, хотелось бы По двум другим вопросам (особенно интересует третий) у кого-нибудь есть соображения? |
| Автор: LSD 20.5.2013, 14:26 | ||
Нет. Это classpath с которым запущена JVM, подробнее http://docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html. |
| Автор: jah2 7.6.2013, 19:15 | ||||||||
спасибо
к сожалению никто не ответил на третий вопрос документация хоть и неплохая, но можно было сделать её гораздо сочнее из официальной документации на решение этого вопроса можно выйти отсюда http://docs.oracle.com/javaee/6/tutorial/doc/bnagl.html
То есть нужно использовать getResourceAsStream() не от Class-объекта сервлета, а от контекста, в котором он находится (контекстом является контейнер сервлета). Например, так можно получить доступ к файлу some.res в корне war-архива (то есть теперь слеш / действительно начинает отсчитывать путь от корня архива)
либо сразу использовать getServletContext(), так как он достаётся HttpServlet-у по наследству от GenericServlet-a |