Сообщения

Сообщения за август, 2020

Spring Resource

Изображение
Стандартный класс Java java.net.URL и стандартные обработчики различных префиксов URL, к сожалению, недостаточно для любого доступа к низкоуровневым ресурсам. Например, не существует стандартизованной реализации URL-адреса, которая может использоваться для доступа к ресурсу, который необходимо получить из пути к классам или относительно ServletContext. Хотя можно зарегистрировать новые обработчики для специализированных префиксов URL (аналогично существующим обработчикам для префиксов, таких как http:), это, как правило, довольно сложно, и в интерфейсе URL по-прежнему отсутствуют некоторые желательные функции, такие как метод проверки наличия ресурса, на который указывает. Интерфейс Resource Интерфейс Resource в Spring призван стать более функциональным интерфейсом для абстрагирования доступа к ресурсам низкого уровня. В следующем листинге показано определение интерфейса Resource: Java public interface Resource extends InputStreamSource { boolean exists(); boolean isO

Spring IoC контейнер: BeanFactory или ApplicationContext

Изображение
В этом посте объясняются различия между уровнями контейнеров BeanFactory и ApplicationContext и их влияние на загрузку. Вам следует использовать ApplicationContext, если у вас нет веских причин для этого, с GenericApplicationContext и его подклассом AnnotationConfigApplicationContext в качестве общих реализаций для настраиваемой начальной загрузки. Это основные точки входа в основной контейнер Spring для всех общих целей: загрузка файлов конфигурации, запуск сканирования пути к классам, программная регистрация определений компонентов и аннотированных классов и (начиная с версии 5.0) регистрация определений функциональных компонентов. Поскольку ApplicationContext включает в себя все функциональные возможности BeanFactory, его обычно рекомендуется использовать вместо простого BeanFactory, за исключением сценариев, где необходим полный контроль над обработкой bean-компонентов. Внутри ApplicationContext (например, реализации GenericApplicationContext) несколько видов bean-компонентов обн

Spring IoC контейнер: BeanFactory

Изображение
BeanFactory API обеспечивает базовую основу для функциональности Spring IoC. Его конкретные контракты в основном используются в интеграции с другими частями Spring и связанных сторонних фреймворков, а его реализация DefaultListableBeanFactory является ключевым делегатом в контейнере GenericApplicationContext более высокого уровня. BeanFactory и связанные интерфейсы (такие как BeanFactoryAware, InitializingBean, DisposableBean) являются важными точками интеграции для других компонентов инфраструктуры. Не требуя никаких аннотаций или даже отражения, они обеспечивают очень эффективное взаимодействие между контейнером и его компонентами. Компоненты уровня приложения могут использовать те же интерфейсы обратного вызова, но обычно вместо этого предпочитают декларативную инъекцию зависимостей либо через аннотации, либо через программную конфигурацию. Обратите внимание, что базовый уровень API BeanFactory и его реализация DefaultListableBeanFactory не делают предположений о формате конфигура

Spring IoC контейнер: дополнительные возможности ApplicationContext, развертывание Spring ApplicationContext как файла RAR Java EE

Изображение
Можно развернуть Spring ApplicationContext как файл RAR, инкапсулируя контекст и все необходимые ему классы компонентов и файлы JAR библиотеки в модуле развертывания Java EE RAR. Это эквивалент начальной загрузки автономного ApplicationContext (размещенного только в среде Java EE) с возможностью доступа к серверам Java EE. Развертывание RAR является более естественной альтернативой сценарию развертывания файла WAR без заголовка - по сути, файла WAR без каких-либо точек входа HTTP, который используется только для начальной загрузки Spring ApplicationContext в среде Java EE. Развертывание RAR идеально подходит для контекстов приложений, которым не нужны точки входа HTTP, а скорее состоят только из конечных точек сообщений и запланированных заданий. Компоненты в таком контексте могут использовать ресурсы сервера приложений, такие как диспетчер транзакций JTA и связанные с JNDI экземпляры JDBC DataSource и экземпляры JMS ConnectionFactory, а также могут регистрироваться на сервере JMX пла

Spring IoC контейнер: дополнительные возможности ApplicationContext, удобное создание экземпляра ApplicationContext для веб-приложений

Изображение
Вы можете создавать экземпляры ApplicationContext декларативно, используя, например, ContextLoader. Конечно, вы также можете создавать экземпляры ApplicationContext программно, используя одну из реализаций ApplicationContext. Вы можете зарегистрировать ApplicationContext с помощью ContextLoaderListener, как показано в следующем примере: <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml</param-value> </context-param> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> Слушатель проверяет параметр contextConfigLocation. Если параметр не существует, прослушиватель использует /WEB-INF/applicationContext.xml по умолчанию. Когда параметр действительно существует, прослушиватель разделяет строку с помощью предопределенных разделителей (запятая, точка с запятой и пробел)

Spring IoC контейнер: дополнительные возможности ApplicationContext, удобный доступ к низкоуровневым ресурсам

Изображение
Контекст приложения - это ResourceLoader, который можно использовать для загрузки объектов Resource. Resource - это, по сути, более функциональная версия класса JDK java.net.URL. Фактически, реализации Resource оборачивают экземпляр java.net.URL, где это необходимо. Resource может прозрачным образом получать ресурсы низкого уровня практически из любого места, включая путь к классам, расположение файловой системы, любое место, описываемое стандартным URL-адресом, и некоторые другие варианты. Если строка местоположения ресурса представляет собой простой путь без каких-либо специальных префиксов, то источник этих ресурсов является конкретным и соответствует фактическому типу контекста приложения. Вы можете настроить компонент, развернутый в контексте приложения, для реализации специального интерфейса обратного вызова, ResourceLoaderAware, который будет автоматически вызываться во время инициализации с самим контекстом приложения, переданным как ResourceLoader. Вы также можете предоставит

Spring IoC контейнер: дополнительные возможности ApplicationContext, асинхронные слушатели, упорядочивание слушателей

Изображение
Асинхронные слушатели Если вы хотите, чтобы конкретный слушатель обрабатывал события асинхронно, вы можете повторно использовать обычную поддержку @Async. В следующем примере показано, как это сделать: Java @EventListener @Async public void processBlockedListEvent(BlockedListEvent event) { // BlockedListEvent обрабатывается в отдельном потоке } Kotlin @EventListener @Async fun processBlockedListEvent(event: BlockedListEvent) { // BlockedListEvent обрабатывается в отдельном потоке } Помните о следующих ограничениях при использовании асинхронных событий: Если асинхронный прослушиватель событий выдает исключение, оно не передается вызывающей стороне. Методы асинхронного прослушивателя событий не могут публиковать последующее событие, возвращая значение. Если вам нужно опубликовать другое событие в результате обработки, введите ApplicationEventPublisher, чтобы опубликовать событие вручную. Упорядочивание слушателей Если вам нужно, чтобы один слушатель вызывалс

Spring IoC контейнер: дополнительные возможности ApplicationContext, слушатели событий на основе аннотаций

Изображение
Начиная с Spring 4.2, вы можете зарегистрировать прослушиватель событий для любого общедоступного метода управляемого bean-компонента с помощью аннотации @EventListener. BlockedListNotifier можно переписать следующим образом: Java public class BlockedListNotifier { private String notificationAddress; public void setNotificationAddress(String notificationAddress) { this.notificationAddress = notificationAddress; } @EventListener public void processBlockedListEvent(BlockedListEvent event) { // уведомляем соответствующие стороны через notificationAddress... } } Kotlin class BlockedListNotifier { lateinit var notificationAddress: String @EventListener fun processBlockedListEvent(event: BlockedListEvent) { // уведомляем соответствующие стороны через notificationAddress... } } Сигнатура метода еще раз объявляет тип события, которое он слушает, но на этот раз с гибким именем и без реализации определенного инте

Spring IoC контейнер: дополнительные возможности ApplicationContext, стандартные и специальные события

Изображение
Обработка событий в ApplicationContext обеспечивается через класс ApplicationEvent и интерфейс ApplicationListener. Если bean-компонент, реализующий интерфейс ApplicationListener, развертывается в контексте, каждый раз, когда ApplicationEvent публикуется в ApplicationContext, этот bean-компонент получает уведомление. По сути, это стандартный шаблон проектирования Observer. Начиная с Spring 4.2, инфраструктура событий была значительно улучшена и предлагает модель на основе аннотаций, а также возможность публиковать любое произвольное событие (то есть объект, который не обязательно является наследником ApplicationEvent). Когда такой объект публикуется, Spring упаковывает его в событие для вас. Ниже описаны стандартные события, которые предоставляет Spring: ContextRefreshedEvent Публикуется при инициализации или обновлении ApplicationContext (например, с помощью метода refresh() в интерфейсе ConfigurableApplicationContext). Здесь "инициализировано" означает, что все bean-ком

Spring IoC контейнер: дополнительные возможности ApplicationContext, интернационализация с использованием MessageSource

Изображение
Интерфейс ApplicationContext расширяет интерфейс под названием MessageSource и, следовательно, обеспечивает функциональность интернационализации (“i18n”). Spring также предоставляет интерфейс HierarchicalMessageSource, который может разрешать сообщения иерархически. Вместе эти интерфейсы обеспечивают основу, на которой Spring влияет на разрешение сообщений. Методы, определенные в этих интерфейсах, включают: String getMessage(String code, Object[] args, String default, Locale loc): основной метод, используемый для получения сообщения из MessageSource. Если сообщение для указанной локали не найдено, используется сообщение по умолчанию. Любые переданные аргументы становятся значениями замены с использованием функции MessageFormat, предоставляемой стандартной библиотекой. String getMessage(String code, Object[] args, Locale loc): по сути то же самое, что и предыдущий метод, но с одним отличием: нельзя указать сообщение по умолчанию. Если сообщение не может быть найдено, создается исключ

Spring IoC контейнер: дополнительные возможности ApplicationContext

Изображение
Пакет org.springframework.beans.factory предоставляет базовые функции для управления и манипулирования bean-компонентами, в том числе программным способом. Пакет org.springframework.context добавляет интерфейс ApplicationContext, который расширяет интерфейс BeanFactory, в дополнение к расширению других интерфейсов для обеспечения дополнительных функций в фреймворк-ориентированном стиле. Многие люди используют ApplicationContext полностью декларативно, даже не создавая его программно, а вместо этого полагаясь на вспомогательные классы, такие как ContextLoader, для автоматического создания экземпляра ApplicationContext в рамках обычного процесса запуска веб-приложения Java EE. Чтобы улучшить функциональность BeanFactory в более ориентированном на фреймворк стиле, пакет context также предоставляет следующие функции: Доступ к сообщениям в стиле i18n через интерфейс MessageSource. Доступ к ресурсам, таким как URL-адреса и файлы, через интерфейс ResourceLoader. Публикация событий, а име

Spring IoC контейнер: абстракция Environment, регистрация LoadTimeWeaver

Изображение
LoadTimeWeaver используется Spring для динамического преобразования классов по мере их загрузки в виртуальную машину Java (JVM). Чтобы включить динамическое преобразование классов по мере их загрузки, вы можете добавить @EnableLoadTimeWeaving к одному из ваших классов @Configuration, как показано в следующем примере: Java @Configuration @EnableLoadTimeWeaving public class AppConfig { } Kotlin @Configuration @EnableLoadTimeWeaving class AppConfig В качестве альтернативы для конфигурации XML вы можете использовать элемент context:load-time-weaver: <beans> <context:load-time-weaver/> </beans> После настройки для ApplicationContext любой bean-компонент в этом ApplicationContext может реализовать LoadTimeWeaverAware, тем самым получая ссылку на экземпляр Weaver во время загрузки. Это особенно полезно в сочетании с поддержкой Spring JPA, когда динамическое преобразование классов по мере их загрузки может быть необходимо для преобразования класса

Spring IoC контейнер: абстракция Environment, использование @PropertySource

Изображение
Аннотация @PropertySource предоставляет удобный и декларативный механизм для добавления PropertySource в Spring Environment. Учитывая файл с именем app.properties, который содержит пару ключ-значение testbean.name=myTestBean, следующий класс @Configuration использует @PropertySource таким образом, что вызов testBean.getName() возвращает myTestBean: Java @Configuration @PropertySource("classpath:/com/myco/app.properties") public class AppConfig { @Autowired Environment env; @Bean public TestBean testBean() { TestBean testBean = new TestBean(); testBean.setName(env.getProperty("testbean.name")); return testBean; } } Kotlin @Configuration @PropertySource("classpath:/com/myco/app.properties") class AppConfig { @Autowired private lateinit var env: Environment @Bean fun testBean() = TestBean().apply { name = env.getProperty("testbean.name")!! } } Любые заполнит

Spring IoC контейнер: абстракция Environment, PropertySource

Изображение
Абстракция Spring Environment предоставляет операции поиска по настраиваемой иерархии источников свойств. Рассмотрим следующий список: Java ApplicationContext ctx = new GenericApplicationContext(); Environment env = ctx.getEnvironment(); boolean containsMyProperty = env.containsProperty("my-property"); System.out.println("Содержит ли мое окружение свойство 'my-property'? " + containsMyProperty); Kotlin val ctx = GenericApplicationContext() val env = ctx.environment val containsMyProperty = env.containsProperty("my-property") println("Содержит ли мое окружение свойство 'my-property'? $containsMyProperty") В предыдущем фрагменте мы видим высокоуровневый способ спросить Spring, определено ли свойство my-property для текущей среды. Чтобы ответить на этот вопрос, объект Environment выполняет поиск по набору объектов PropertySource. PropertySource - это простая абстракция над любым источником пар ключ-значение, а стан

Spring IoC контейнер: абстракция Environment, профили определения компонентов, профиль по умолчанию

Изображение
Профиль по умолчанию представляет собой профиль, который включен по умолчанию. Рассмотрим следующий пример: Java @Configuration @Profile("default") public class DefaultDataConfig { @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("classpath:com/bank/config/sql/schema.sql") .build(); } } Kotlin @Configuration @Profile("default") class DefaultDataConfig { @Bean fun dataSource(): DataSource { return EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("classpath:com/bank/config/sql/schema.sql") .build() } } Если ни один профиль не активен, dataSource создается. Вы можете рассматривать это как способ предоставить определение по умолчанию для одного или нескольких компонентов. Если какой-либо профиль включен, профиль по

Spring IoC контейнер: абстракция Environment, профили определения компонентов, активация профиля

Изображение
Теперь, когда мы обновили нашу конфигурацию, нам все еще нужно указать Spring, какой профиль активен. Если бы мы запустили наш пример приложения прямо сейчас, мы бы увидели исключение NoSuchBeanDefinitionException, потому что контейнер не смог найти bean-компонент Spring с именем dataSource. Активация профиля может быть выполнена несколькими способами, но самый простой - это сделать это программно с помощью API среды, доступного через ApplicationContext. В следующем примере показано, как это сделать: Java AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.getEnvironment().setActiveProfiles("development"); ctx.register(SomeConfig.class, StandaloneDataConfig.class, JndiDataConfig.class); ctx.refresh(); Kotlin val ctx = AnnotationConfigApplicationContext().apply { environment.setActiveProfiles("development") register(SomeConfig::class.java, StandaloneDataConfig::class.java, JndiDataConfig::class.java) refresh

Spring IoC контейнер: абстракция Environment, профили определения компонентов, XML

Изображение
Аналогом в XML является атрибут profile элемента <beans>. Наш предыдущий пример конфигурации можно переписать в два файла XML следующим образом: <beans profile="development" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xsi:schemaLocation="..."> <jdbc:embedded-database id="dataSource"> <jdbc:script location="classpath:com/bank/config/sql/schema.sql"/> <jdbc:script location="classpath:com/bank/config/sql/test-data.sql"/> </jdbc:embedded-database> </beans> <beans profile="production" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jee="http://www.springframework.org/schema/jee" xsi:

Spring IoC контейнер: абстракция Environment, профили определения компонентов, использование @Profile

Изображение
Аннотация @Profile позволяет указать, что компонент имеет право на регистрацию, если активен один или несколько указанных профилей. Используя наш предыдущий пример , мы можем переписать конфигурацию источника данных следующим образом: Java @Configuration @Profile("development") public class StandaloneDataConfig { @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("classpath:com/bank/config/sql/schema.sql") .addScript("classpath:com/bank/config/sql/test-data.sql") .build(); } } Kotlin @Configuration @Profile("development") class StandaloneDataConfig { @Bean fun dataSource(): DataSource { return EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("classpath:com/bank/config/sql/schema.sql") .addScript(&q

Spring IoC контейнер: абстракция Environment, профили определения компонентов

Изображение
Профили определения bean-компонентов обеспечивают механизм в основном контейнере, который позволяет регистрировать различные bean-компоненты в разных средах. Слово "среда" может означать разные вещи для разных пользователей, и эта функция может помочь во многих случаях использования, в том числе: Работа с источником данных в памяти при разработке по сравнению с поиском того же источника данных из JNDI в процессе контроля качества или производства. Регистрация инфраструктуры мониторинга только при развертывании приложения в производственной среде. Регистрация настраиваемых реализаций bean-компонентов для развертываний клиента A и клиента B. Рассмотрим первый вариант использования в практическом приложении, требующем DataSource. В тестовой среде конфигурация может выглядеть следующим образом: Java @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("my-schema.sql")