Spring Resource: контексты приложения и пути ресурсов, подстановочные знаки в путях ресурсов конструктора контекста приложения
Пути к ресурсам в значениях конструктора контекста приложения могут быть простыми путями (как показано ранее), каждый из которых имеет однозначное сопоставление с целевым ресурсом или, альтернативно, может содержать специальный префикс "classpath*:" или внутреннее регулярное выражение в Ant-стиле (сопоставлены с помощью утилиты Spring PathMatcher). Оба последних по сути являются подстановочными знаками.
Одно из применений этого механизма - когда вам нужно выполнить сборку приложения в компонентном стиле. Все компоненты могут "публиковать" фрагменты определения контекста по хорошо известному пути местоположения, и, когда конечный контекст приложения создается с использованием того же пути с префиксом classpath*:, автоматически выбираются все фрагменты компонентов.
Обратите внимание, что этот подстановочный знак специфичен для использования путей к ресурсам в конструкторах контекста приложения (или когда вы напрямую используете иерархию служебных классов PathMatcher) и разрешается во время построения. Это не имеет ничего общего с самим типом ресурса. Вы не можете использовать префикс classpath*: для создания фактического ресурса, поскольку ресурс указывает только на один ресурс за раз.
Шаблоны в Ant-стиле
Расположение путей может содержать шаблоны в Ant-стиле, как показано в следующем примере:
/WEB-INF/*-context.xml
com/mycompany/**/applicationContext.xml
file:C:/some/path/*-context.xml
classpath:com/mycompany/**/applicationContext.xml
Когда расположение пути содержит шаблон в Ant-стиле, преобразователь следует более сложной процедуре, пытаясь разрешить подстановочный знак. Он создает ресурс для пути до последнего сегмента без подстановочных знаков и получает из него URL. Если этот URL-адрес не является URL-адресом jar: или вариантом для конкретного контейнера (например, zip: в WebLogic, wsjar в WebSphere и т. д.), из него получается файл java.io.File, который используется для устранения подстановочного знака путем обхода файловой системы. В случае URL-адреса jar преобразователь либо получает от него java.net.JarURLConnection, либо вручную анализирует URL-адрес jar, а затем просматривает содержимое файла jar для разрешения подстановочных знаков.
Последствия для переносимости
Если указанный путь уже является URL-адресом файла (либо неявно, потому что базовый ResourceLoader является файловой системой, либо явно), подстановочные знаки гарантированно работают полностью переносимым способом.
Если указанный путь является местоположением пути к классам, преобразователь должен получить последний URL сегмента пути без подстановочного знака, выполнив вызов Classloader.getResource(). Поскольку это всего лишь узел пути (а не файл в конце), на самом деле не определено, какой именно тип URL возвращается в этом случае. На практике это всегда java.io.File, представляющий каталог (где ресурс пути к классам преобразуется в расположение файловой системы) или какой-либо URL-адрес jar (где ресурс пути к классам разрешается в расположение jar). Тем не менее, существует проблема переносимости этой операции.
Если URL-адрес jar получен для последнего сегмента без подстановочного знака, преобразователь должен иметь возможность получить от него java.net.JarURLConnection или вручную проанализировать URL-адрес jar, чтобы иметь возможность просматривать содержимое jar-файла и разрешать подстановочный знак. Это работает в большинстве сред, но не работает в других, и рекомендуется тщательно протестировать разрешение подстановочных знаков ресурсов, поступающих из jar-файлов, в вашей конкретной среде, прежде чем полагаться на него.
classpath*: префикс
При создании контекста приложения на основе XML строка местоположения может использовать специальный префикс classpath*:, как показано в следующем примере:
Java
ApplicationContext ctx =
new ClassPathXmlApplicationContext("classpath*:conf/appContext.xml");
Kotlin
val ctx = ClassPathXmlApplicationContext("classpath*:conf/appContext.xml")
Этот специальный префикс указывает, что все ресурсы пути к классам, которые соответствуют заданному имени, должны быть получены (внутренне, по сути, это происходит через вызов ClassLoader.getResources(…)), а затем объединены для формирования окончательного определения контекста приложения.
Путь к классам с подстановочными знаками основан на методе getResources() базового загрузчика классов. Поскольку большинство серверов приложений в настоящее время предоставляют свою собственную реализацию загрузчика классов, поведение может отличаться, особенно при работе с файлами jar. Простой тест, чтобы проверить, работает ли classpath*, - это использовать загрузчик классов для загрузки файла из jar в путь к классам: getClass().getClassLoader().getResources("<someFileInsideTheJar>"). Попробуйте этот тест с файлами с одинаковыми именами, но расположенными в двух разных местах. Если возвращается несоответствующий результат, проверьте в документации сервера приложений параметры, которые могут повлиять на поведение загрузчика классов.
Вы также можете комбинировать префикс classpath*: с шаблоном PathMatcher в остальной части пути расположения (например, classpath*:META-INF/*-beans.xml). В этом случае стратегия разрешения довольно проста: вызов ClassLoader.getResources() используется в последнем сегменте пути без подстановочных знаков, чтобы получить все соответствующие ресурсы в иерархии загрузчика классов, а затем для каждого ресурса такое же разрешение PathMatcher описанная ранее стратегия используется для подпути с подстановочными знаками.
Другие примечания, касающиеся подстановочных знаков
Обратите внимание, что classpath*: в сочетании с шаблонами в Ant-стиле надежно работает только с хотя бы одним корневым каталогом перед запуском шаблона, если только фактические целевые файлы не находятся в файловой системе. Это означает, что такой шаблон, как classpath*:*.xml, может извлекать файлы не из корня файлов jar, а только из корня расширенных каталогов.
Возможность Spring извлекать записи пути к классам исходит из метода JDK ClassLoader.getResources(), который возвращает только местоположения файловой системы для пустой строки (указывающей потенциальные корни для поиска). Spring оценивает конфигурацию среды выполнения URLClassLoader и манифест java.class.path в файлах jar, но это не гарантирует переносимого поведения.
Для сканирования пакетов пути к классам необходимо наличие соответствующих записей каталога в пути к классам. Когда вы создаете JAR с помощью Ant, не активируйте переключатель только файлы в задаче JAR. Кроме того, каталоги пути к классам могут не отображаться в зависимости от политик безопасности в некоторых средах - например, в автономных приложениях на JDK 1.7.0_45 и выше (что требует настройки 'Trusted-Library' в ваших манифестах.).
На пути к модулю JDK 9 (Jigsaw) сканирование пути к классам Spring обычно работает должным образом. Здесь также настоятельно рекомендуется разместить ресурсы в выделенном каталоге, чтобы избежать вышеупомянутых проблем переносимости при поиске на корневом уровне файла jar.
Шаблоны в Ant-стиле с classpath: не гарантируется нахождение подходящих ресурсов, если корневой пакет для поиска доступен в нескольких местах пути к классам. Рассмотрим следующий пример расположения ресурса:
com/mycompany/package1/service-context.xml
Теперь рассмотрим путь в Ant-стиле, который кто-то может использовать, чтобы попытаться найти этот файл:
classpath:com/mycompany/**/service-context.xml
Такой ресурс может находиться только в одном месте, но когда путь, такой как в предыдущем примере, используется для его разрешения, преобразователь обрабатывает (первый) URL-адрес, возвращаемый getResource("com/mycompany");. Если этот базовый узел пакета существует в нескольких местах загрузчика классов, фактического конечного ресурса там может не быть. Следовательно, в таком случае вы должны предпочесть использовать classpath*: с тем же шаблоном в стиле Ant, который ищет все места пути к классам, содержащие корневой пакет.
Читайте также:
- Spring Resource: контексты приложения и пути ресурсов, создание контекстов приложения
- Spring Resource: ресурсы как зависимости
- Spring Resource: интерфейс ResourceLoader
Комментарии
Отправить комментарий