Урок 3: Работа с ресурсами
Этот урок освещает работу с ресурсами и основан на оригинальной документации §6. Resources.
Что вам потребуется
- Любимый текстовый редактор или IDE
- JDK 7 и выше
- Maven 3.0+
- Исходный код предыдущего урока
Настройка проекта
Прежде чем вы начнете изучать этот урок, вам необходимо создать класс
lessons.starter.ResourceStarter
.
Введение
Стандартный Java-класс java.net.URL
и стандартные обработчки различных URL префиксов
к сожалению не во всём достаточно пригодны для доступа к низкоуровневым ресурсам. К примеру, нет
стандартизированных реализаций URL
, которые могут быть использованы для доступа к
ресурсам, которые необходимо получить из classpath, либо ServletContext
. Можно
зарегистрировать новые обработчики для конкретных URL
префиксов, но это довольно
сложная задача, а интерфейс URL
все ещё недостаточно функционален.
Spring предоставляет интерфейс Resource
, более совместимый для низкоуровнего доступа.
public interface Resource extends InputStreamSource {
boolean exists();
boolean isOpen();
URL getURL() throws IOException;
File getFile() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
//...
}
public interface InputStreamSource {
InputStream getInputStream() throws IOException;
}
Интерфейс Resource
используется и в самом Spring в качестве типа аргументов во многих
методах, где необходимы ресурсы. Другие методы принимают в качестве аргументов строковые значения,
которые в конечном счете используются для получения ресурсов. Важно понимать, что реализации
интерфейса Resource
не заменяют функциональность, а являются "оберткой". Например,
URLResource
является "оберткой" для URL
.
Встроенные реализации
Из реализаций интерфейса Resource
, которые входят в состав Spring, стоит выделить следующие:
-
UrlResource
- является оберткой дляjava.net.URL
и может быть использован для доступа к любому объекту по его URL, например, файлы, HTTP или FTP ресурс и др., либо через строковое представление с соответветствующими префиксамиclasspath:
,file:
,http:
,ftp:
и др. -
ClassPathResource
- представляет ресурс, который может быть получен из classpath и поддерживает ресурсы какjava.io.File
, если они расположены в файловой системе, а не в jar -
FileSystemResource
- реализация для обработкиjava.io.File
. Поддерживает какFile
, так иURL
-
ServletContextResource
- реализация для обработкиServletContext
ресурсов относительно корневой директории web-приложения. Поддерживает потоковый и к URL доступ. Доступ кjava.io.File
возможен, когда web-приложение развернуто и ресурс физически находится в файловой системе -
InputStreamResource
- реализация для обработкиInputStream
. Должен использоваться только тогда, когда нет доступных соответствующих реализаций интерфейсаResource
или нет возможности использовать более предпочтительный вариантByteArrayResource
-
ByteArrayResource
- реализация для обработки массива байтов. Полезен для загрузки контента из любого массива байтов, не прибегая к использованиюInputStreamResource
Получение ресурсов
ResourceLoader
Интерфейс ResourceLoader
предназначен для реализации возврата, т.е. загрузки, экземпляров
Resource
.
public interface ResourceLoader {
Resource getResource(String location);
}
Все контексты приложения реализуют данный интерфейс. Когда вы вызываете метод getResource()
в определенном контексте приложения без указания префикса, то вы получите тот тип Resource
,
который соответствует контексту. В качестве демонстрации, можно запустить метод
src/main/java/lessons/starter/ResourceStarter#printClassResourcesByContextNoPrefix()
.
В методе src/main/java/lessons/starter/ResourceStarter#printClassResourcesByContextWithPrefix()
на консоль отбражаются подобные результаты, но ресурс передается уже с префиксом.
src/main/lessons/starter/ResourceStarter.java
public class ResourceStarter {
public static final Logger LOGGER = LogManager.getLogger(ResourceStarter.class);
public static void main(String[] args) throws IOException {
LOGGER.info("Starting resources...");
ResourceStarter starter = new ResourceStarter();
starter.printClassResourcesByContextNoPrefix();
starter.printClassResourcesByContextWithPrefix();
}
public void printClassResourcesByContextNoPrefix() {
LOGGER.info("*******printClassResourcesByContextNoPrefix**********");
ApplicationContext context = new AnnotationConfigApplicationContext();
Resource resource = context.getResource("resources/log4j.properties");
LOGGER.info("AnnotationConfigApplicationContext: " + resource.getClass().getSimpleName());
context = new ClassPathXmlApplicationContext();
resource = context.getResource("resources/log4j.properties");
LOGGER.info("ClassPathXmlApplicationContext: " + resource.getClass().getSimpleName());
context = new FileSystemXmlApplicationContext();
resource = context.getResource("resources/log4j.properties");
LOGGER.info("FileSystemXmlApplicationContext: " + resource.getClass().getSimpleName());
LOGGER.info("****************************************************");
}
public void printClassResourcesByContextWithPrefix() {
LOGGER.info("*******printClassResourcesByContextWithPrefix*******");
ApplicationContext context = new AnnotationConfigApplicationContext();
Resource resource = context.getResource("file:resources/log4j.properties");
LOGGER.info("file: " + resource.getClass().getSimpleName());
resource = context.getResource("http://spring.io/img/favicon.png");
LOGGER.info("http: " + resource.getClass().getSimpleName());
resource = context.getResource("classpath:resources/log4j.properties");
LOGGER.info("classpath: " + resource.getClass().getSimpleName());
LOGGER.info("****************************************************");
}
}
ResourceLoaderAware
Интерфейс ResourceLoaderAware
обеспечивает объект ссылкой на ResourceLoader
.
public interface ResourceLoaderAware {
void setResourceLoader(ResourceLoader resourceLoader);
}
Если класс реализует интерфейс ResourceLoaderAware
и развернут в контексте приложения,
например, как бин, то при его сборке контекст приложения будет вызывать метод setResourceLoader()
и передавать соответствующий ResourceLoader
, в зависимости от типа контекста.
Получение ресурса по его пути
Если ваш контекст ClassPathXmlApplicationContext
, то вы можете получить ресурс по его
пути с указанием префикса classpath:
или без него с учетом его местоположения в classpath.
Если же вам необходимо получить ресурс по его полному пути, то вам необходимо указать префикс
file:
, либо ваш контекст должен быть типа FileSystemXmlApplicationContext
.
В качестве демонстрации, можно запустить метод
src/main/java/lessons/starter/ResourceStarter#resourcePath()
.
src/main/lessons/starter/ResourceStarter.java
public class ResourceStarter {
public static final Logger LOGGER = LogManager.getLogger(ResourceStarter.class);
public static void main(String[] args) throws IOException {
//...
starter.resourcePath();
}
public void resourcePath() throws IOException {
LOGGER.info("*****************resourcePath()*********************");
LOGGER.info("context = new ClassPathXmlApplicationContext()");
ApplicationContext context = new ClassPathXmlApplicationContext();
Resource resource = context.getResource("log4j.properties");
LOGGER.info("log4j.properties exist: " + resource.getFile().exists());
// resource = context.getResource("src/main/resources/log4j.properties");
// LOGGER.info("log4j.properties exist: " + resource.getFile().exists()); //IOException
resource = context.getResource("file:src/main/resources/log4j.properties");
LOGGER.info("file:src/main/resources/log4j.properties exist: " + resource.getFile().exists());
resource = context.getResource("log/log.txt");
LOGGER.info("log/log.txt exist: " + resource.getFile().exists());
resource = context.getResource("classpath:log/log.txt");
LOGGER.info("classpath:log/log.txt exist: " + resource.getFile().exists());
resource = context.getResource("file:log.txt");
LOGGER.info("file:log.txt exist: " + resource.getFile().exists());
resource = context.getResource("file:log/log.txt");
LOGGER.info("file:log/log.txt exist: " + resource.getFile().exists());
resource = context.getResource("file:src/main/resources/log/log.txt");
LOGGER.info("file:src/main/resources/log/log.txt exist: " + resource.getFile().exists());
LOGGER.info("context = new FileSystemXmlApplicationContext()");
context = new FileSystemXmlApplicationContext();
resource = context.getResource("log4j.properties");
LOGGER.info("log4j.properties exist: " + resource.getFile().exists());
resource = context.getResource("src/main/resources/log4j.properties");
LOGGER.info("src/main/resources/log4j.properties exist: " + resource.getFile().exists());
resource = context.getResource("log/log.txt");
LOGGER.info("log/log.txt exist: " + resource.getFile().exists());
resource = context.getResource("classpath:log/log.txt");
LOGGER.info("classpath:log/log.txt exist: " + resource.getFile().exists());
resource = context.getResource("file:log.txt");
LOGGER.info("file:log.txt exist: " + resource.getFile().exists());
resource = context.getResource("file:log/log.txt");
LOGGER.info("file:log/log.txt exist: " + resource.getFile().exists());
LOGGER.info("****************************************************");
}
}
Итог
Несмотря на небольшой объем урока, вы познакомились с основами доступа к ресурсам встроенными в Spring средствами. В соответствии с тем, что уроки не предусматривают работу с XML-конфигурациями, а только c Java-конфигурациями, не были рассмотрены варианты указания различных шаблонов в конструктор XML-конфигурациии, но вам ничто не мешает при необходимости ознакомиться с соответствующими разделами документации.
comments powered by Disqus