Статьи

Spring 3.1 Профили среды

В Spring 3.1 теперь включена поддержка долгожданной среды, которая называется профили. Теперь мы можем активировать профили в нашем приложении, что позволяет нам определять компоненты по областям развертывания, таким как «dev», «qa», «production», «cloud» и т. Д.

Мы также можем использовать эту функцию для других целей: определения профилей для сценариев тестирования производительности, таких как «кэшированный» или «lazyload».

Основные токены

Профили Spring включаются с использованием нечувствительных к регистру токенов spring.profiles.active или spring_profiles_active.

Этот токен может быть установлен как:

  • переменная среды
  • Свойство JVM
  • Веб-параметр
  • программный

Spring также ищет токен, spring.profiles.default, который можно использовать для установки профилей по умолчанию, если ни один из них не указан в spring.profiles.active.

Группировка бобов по профилю

Spring 3.1 предоставляет определения вложенных bean-компонентов, предоставляя возможность определять bean-компоненты для различных сред:

<beans profiles="dev,qa">
  <bean id="dataSource" class="..."/>
  <bean id="messagingProvider" class="..."/>
</beans>

Вложенные <beans> должны появляться последними в файле.
Бины, используемые во всех профилях, объявляются во внешнем <beans>, как мы всегда это делаем, например, в классах Service. 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:c="http://www.springframework.org/schema/c"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="businessService"
       class="com.c...s.springthreeone.business.SimpleBusinessServiceImpl"/>

    <beans profile="dev,qa">
        <bean id="constructorBean"
          class="com.gordondickens.springthreeone.SimpleBean"
              c:myString="Constructor Set"/>

        <bean id="setterBean"
          class="com.gordondickens.springthreeone.SimpleBean">
            <property name="myString" value="Setter Set"/>
        </bean>
    </beans>

    <beans profile="prod">
        <bean id="setterBean"
          class="com.gordondickens.springthreeone.SimpleBean">
            <property name="myString" value="Setter Set - in Production YO!"/>
        </bean>
    </beans>
</beans>

Если мы поместим одно объявление <bean> ниже любых вложенных тегов <beans>, мы получим исключение org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: было найдено недопустимое содержимое, начиная с элемента ‘bean’ ,

Теперь несколько бинов могут совместно использовать один и тот же «идентификатор» XML.
В типичном сценарии мы бы хотели, чтобы бин DataSource назывался dataSource во всех всех профилях. Spring теперь позволяет нам создавать несколько bean-компонентов внутри XML-файла с одним и тем же идентификатором при условии, что они определены в разных наборах <beans>. Другими словами, уникальность идентификатора применяется только в каждом наборе <beans>.

Автоматическое обнаружение профиля (программный)

Мы можем настроить класс для установки наших профилей во время запуска приложения путем реализации соответствующего интерфейса. Например, мы можем настроить приложение для установки различных профилей в зависимости от того, где приложение развернуто — в CloudFoundry или в качестве локального веб-приложения. В файле web.xml мы можем включить параметр контекста сервлета contextInitializerClasses, чтобы загрузить этот класс:

<context-param>
  <param-name>contextInitializerClasses</param-name>
  <param-value>com.gordondickens.springthreeone.services.CloudApplicationContextInitializer</param-value>
</context-param>

Класс Initializer

package com.gordondickens.springthreeone.services;

import org.cloudfoundry.runtime.env.CloudEnvironment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;

public class CloudApplicationContextInitializer implements
  ApplicationContextInitializer<ConfigurableApplicationContext> {

  private static final Logger logger = LoggerFactory
    .getLogger(CloudApplicationContextInitializer.class);

  @Override
  public void initialize(ConfigurableApplicationContext applicationContext) {
    CloudEnvironment env = new CloudEnvironment();
    if (env.getInstanceInfo() != null) {
      logger.info("Application running in cloud. API '{}'",
        env.getCloudApiUri());
      applicationContext.getEnvironment().setActiveProfiles("cloud");
      applicationContext.refresh();
    } else {
      logger.info("Application running local");
      applicationContext.getEnvironment().setActiveProfiles("dev");
    }
  }
}

Поддержка аннотаций для JavaConfig

Если мы используем JavaConfig для определения наших bean-компонентов, Spring 3.1 включает аннотацию @Profile для включения конфигурационных файлов bean-компонентов по профилям.

package com.gordondickens.springthreeone.configuration;

import com.gordondickens.springthreeone.SimpleBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

@Configuration
@Profile("dev")
public class AppConfig {
  @Bean
  public SimpleBean simpleBean() {
    SimpleBean simpleBean = new SimpleBean();
    simpleBean.setMyString("Ripped Pants");
    return simpleBean;
  }
}

Тестирование с настройкой XML

С помощью конфигурации XML мы можем просто добавить аннотацию @ActiveProfiles в тестовый класс JUnit. Чтобы включить несколько профилей, используйте формат @ActiveProfiles (profile = {«dev», «prod»})

package com.gordondickens.springthreeone;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
@ActiveProfiles(profiles = "dev")
public class DevBeansTest {

  @Autowired
  ApplicationContext applicationContext;

  @Test
  public void testDevBeans() {
    SimpleBean simpleBean =
      applicationContext.getBean("constructorBean", SimpleBean.class);
    assertNotNull(simpleBean);
  }

  @Test(expected = NoSuchBeanDefinitionException.class)
  public void testProdBean() {
    SimpleBean prodBean = applicationContext.getBean("prodBean", SimpleBean.class);
    assertNull(prodBean);
  }
}

Тестирование с JavaConfig

JavaConfig позволяет нам конфигурировать Spring с настройкой XML или без нее. Если мы хотим протестировать bean-компоненты, определенные в классе Configuration, мы конфигурируем наш тест с аргументами загрузчика и классов аннотации @ContextConfiguration.

package com.gordondickens.springthreeone.configuration;

import com.gordondickens.springthreeone.SimpleBean;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.support.AnnotationConfigContextLoader;

import static org.junit.Assert.assertNotNull;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfig.class, loader = AnnotationConfigContextLoader.class)
@ActiveProfiles(profiles = "dev")
public class BeanConfigTest {

  @Autowired
  SimpleBean simpleBean;

  @Test
  public void testBeanAvailablity() {
    assertNotNull(simpleBean);
  }
}

Декларативная конфигурация в WEB.XML

Если мы хотим установить конфигурацию в WEB.XML, это можно сделать с помощью параметров в ContextLoaderListener.

Контекст приложения

<context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>/WEB-INF/app-config.xml</param-value>
</context-param>
<context-param>
  <param-name>spring.profiles.active</param-name>
  <param-value>DOUBLEUPMINT</param-value>
</context-param>

Результаты журнала

DEBUG PropertySourcesPropertyResolver — Найден ключ «spring.profiles.active» в [servletContextInitParams] с типом [String] и значением «DOUBLEUPMINT»

Переменная среды / параметр JVM
Установка переменной среды может быть выполнена с помощью spring_profiles_default или spring_profiles_active. В Unix / Mac это будет экспорт SPRING_PROFILES_DEFAULT = DEVELOPMENT для моей локальной системы.

Мы также можем использовать параметр «-D» JVM, который также работает с Maven при использовании плагинов Tomcat или Jetty.

Примечание. Помните, что токены НЕ чувствительны к регистру и могут использовать точки или подчеркивания в качестве разделителей. Для систем Unix вам нужно использовать подчеркивание, как указано выше.

Регистрация свойств системного уровня

Резюме

Теперь у нас есть возможность активировать различные наборы Spring bean на основе определенных нами профилей. Мы можем использовать традиционную конфигурацию на основе XML или функции, добавленные для поддержки JavaConfig, первоначально представленного в Spring 3.0.