Как установить активный профиль среды Spring 3.1 через файл свойств, а не через переменную env или системное свойство

Мы используем новую функцию профилей среды Spring 3.1. В настоящее время мы устанавливаем активный профиль, устанавливая переменную среды spring.profiles.active=xxxxx на сервере, на котором мы развертываем приложение.

Мы считаем, что это неоптимальное решение, поскольку файл войны, который мы хотим развернуть, должен просто иметь дополнительный файл свойств, который устанавливает среду, в которой должен загружаться контекст приложения Spring, поэтому развертывание не зависит от некоторого набора env var на сервере.

Я попытался выяснить, как это сделать, и нашел:

ConfigurableEnvironment.setActiveProfiles()

который я могу использовать для программной установки профиля, но тогда я все еще не знаю, где и когда выполнять этот код. Где-то загружается контекст весны? Могу ли я загрузить параметр, который хочу передать методу, из файла свойств?

ОБНОВЛЕНИЕ: я только что нашел в документы, которые я мог бы быть в состоянии реализовать, чтобы установить активный профиль?


person Fabian    schedule 21.12.2011    source источник
comment
Наличие активного профиля в качестве свойства сервера часто является правильным подходом. Поскольку у вас могут быть разные источники данных для серверов подготовки, разработки и производства. Если сервер может предоставить активный профиль, вы можете развернуть один и тот же код в нескольких средах без каких-либо изменений. Это, конечно, может не подходить для вашего варианта использования, но стоит указать.   -  person Alex Barnes    schedule 21.12.2011
comment
Вы хотите, чтобы среда была закодирована в файле WAR? Разве это не поражение цели? У вас должен быть один военный файл для всех сред. Установите активный профиль для каждого сервера или с помощью системного свойства или переменной среды.   -  person sourcedelica    schedule 21.12.2011
comment
Спасибо, Алекс, за указание на это, и я знаю об этом, хотя это не вариант для нас, так как мы хотим контролировать профиль при развертывании.   -  person Fabian    schedule 22.12.2011
comment
Также @ericacm: мы хотим предоставить профиль для самостоятельной установки при развертывании, чтобы он не зависел от среды, установленной на сервере, который мы не контролируем. Я думаю, что правильно, что нужно иметь только одну войну, а не кодировать в ней среду. В моем ответе ниже вы видите, как мы достигаем этого, загружая файл env.properties.   -  person Fabian    schedule 22.12.2011
comment
@ShadowWizard Вау!!, это было не специально, это была ошибка, я много редактирую, иногда получается неправильно   -  person Akhil Jain    schedule 03.02.2013
comment
@ShadowWizard 1 Кросс, я понял твою точку зрения   -  person Akhil Jain    schedule 03.02.2013


Ответы (4)


In web.xml

<context-param>
    <param-name>spring.profiles.active</param-name>
    <param-value>profileName</param-value>
</context-param>

Использование WebApplicationInitializer

Этот подход используется, когда у вас нет файла web.xml в среде Servlet 3.0 и вы полностью загружаете Spring из Java:

class SpringInitializer extends WebApplicationInitializer {

    void onStartup(ServletContext container) {
        AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
        rootContext.getEnvironment().setActiveProfiles("profileName");
        rootContext.register(SpringConfiguration.class);
        container.addListener(new ContextLoaderListener(rootContext));
    }
}

Где класс SpringConfiguration имеет аннотацию @Configuration.

person Tomasz Nurkiewicz    schedule 21.12.2011
comment
Большое спасибо за ответ. Мне нравится решение с WebApplicationInitializer без xml, но мы используем XML. - person Fabian; 22.12.2011
comment
-Dspring.profiles.active=какой-то профиль, я думаю, более управляемый. Поскольку в некоторых случаях он не должен быть включен, будут применены значения по умолчанию. - person skipy; 07.08.2012
comment
Вместо этого вы можете использовать spring.profiles.default. Таким образом, активные профили могут быть переопределены с помощью системного свойства -Dspring.profiles.active. - person sfussenegger; 23.04.2014
comment
Конфигурация Java: если вы используете AbstractAnnotationConfigDispatcherServletInitializer, вы можете переопределить createServletApplicationContext и дополнительно настроить контекст. Пример - person Thomas; 16.07.2014

Ответ от Thomasz действителен до тех пор, пока имя профиля может быть указано статически в файле web.xml или используется новый тип конфигурации без XML, где можно программно загрузить профиль для установки из файла свойств.

Поскольку мы по-прежнему используем XML-версию, я провел дальнейшие исследования и нашел следующее хорошее решение, в котором вы реализуете свой собственный ApplicationContextInitializer, где вы просто добавляете новый PropertySource с файлом свойств в список источников для поиска настроек конфигурации для конкретной среды. в приведенном ниже примере можно установить свойство spring.profiles.active в файле env.properties.

public class P13nApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

    private static Logger LOG = LoggerFactory.getLogger(P13nApplicationContextInitializer.class);

    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
        try {
            environment.getPropertySources().addFirst(new ResourcePropertySource("classpath:env.properties"));
            LOG.info("env.properties loaded");
        } catch (IOException e) {
            // it's ok if the file is not there. we will just log that info.
            LOG.info("didn't find env.properties in classpath so not loading it in the AppContextInitialized");
        }
    }

}

Затем вам нужно добавить этот инициализатор в качестве параметра к ContextLoaderListener весны следующим образом к вашему web.xml:

<context-param>
    <param-name>contextInitializerClasses</param-name>
    <param-value>somepackage.P13nApplicationContextInitializer</param-value>
</context-param>
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Вы также можете применить его к DispatcherServlet:

<servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextInitializerClasses</param-name>
        <param-value>somepackage.P13nApplicationContextInitializer</param-value>
    </init-param>
</servlet>
person Fabian    schedule 22.12.2011
comment
Мне просто любопытно, @Fabian, почему ты называешь это P13n. Некоторое время назад я написал некоторый код персонализации для компании, и я использовал термин P13N, он был написан на Java и использовал Spring. Возможно, это просто совпадение, но просто любопытно. - person Adam Gent; 08.11.2012
comment
Как добавить инициализатор вне web.xml, например. в контексте myapplication.xml? - person luksmir; 11.09.2013
comment
Можно ли это сделать с DispatcherServlet, без ContextLoaderListener? - person rustyx; 13.02.2014
comment
Мне не удалось внедрить конфигурацию в компонент с помощью @Value(${propName}), но я смог внедрить с помощью @Value(#{environment[propName]}). Почему это так ? - person user34567; 24.03.2017

У меня почему-то работает только один способ

public class ActiveProfileConfiguration implements ServletContextListener {   
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.setProperty(AbstractEnvironment.DEFAULT_PROFILES_PROPERTY_NAME, "dev");
        System.setProperty(AbstractEnvironment.ACTIVE_PROFILES_PROPERTY_NAME, "dev");
    }

....

 <listener>
     <listener-class>somepackahe.ActiveProfileConfiguration</listener-class>
 </listener>
 <listener>
     <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
 </listener>
person Michail Nikolaev    schedule 26.12.2012
comment
Идеально. Именно то, что мне было нужно. Спасибо - person flosk8; 28.08.2014
comment
Я использовал AbstractAnnotationConfigDispatcherServletInitializer, а не ApplicationContextInitializer или WebApplicationInitializer. Это решение сработало для этого случая, не нуждаясь в xml. - person Joe Borysko; 21.06.2016

Вот вариант подхода P13nApplicationContextInitializer. Однако на этот раз мы получаем путь к свойствам env из JNDI. В моем случае я установил глобальную переменную среды JNDI как coacorrect/spring-profile = file:/tmp/env.properties

  1. В tomcat/tomee server.xml добавьте следующее: <Environment name="coacorrect/spring-profile" type="java.lang.String" value="/opt/WebSphere/props"/>
  2. Далее в tomcat/tomee добавить в META-INF/context.xml WAR'а <ResourceLink global="coacorrect/spring-profile" name="coacorrect/spring-profile" type="java.lang.String"/>
  3. В любой контейнер добавьте соответствующий в web.xml

    public class SpringProfileApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext>{
    
    public static final Logger log = LoggerFactory.getLogger(SpringProfileApplicationContextInitializer.class);
    private static final String profileJNDIName="coacorrect/spring-profile";
    private static final String failsafeProfile="remote-coac-dbserver";
    
    @Override
    public void initialize(ConfigurableApplicationContext applicationContext) {
    
        ConfigurableEnvironment environment = applicationContext.getEnvironment();
    
        try {
            InitialContext ic = new InitialContext();
            Object r1 = ic.lookup(profileJNDIName);
            if (r1 == null) {
                // try the tomcat variant of JNDI lookups in case we are on tomcat/tomee
                r1 = ic.lookup("java:comp/env/"+profileJNDIName);
            }
            if (r1 == null) {
                log.error("Unable to locate JNDI environment variable {}", profileJNDIName);
                return;
            }
    
            String profilePath=(String)r1;
            log.debug("Found JNDI env variable {} = {}",r1);
            environment.getPropertySources().addFirst(new ResourcePropertySource(profilePath.trim()));
            log.debug("Loaded COAC dbprofile path. Profiles defined {} ", Arrays.asList(environment.getDefaultProfiles()));
    
        } catch (IOException e) {
            // it's ok if the file is not there. we will just log that info.
            log.warn("Could not load spring-profile, defaulting to {} spring profile",failsafeProfile);
            environment.setDefaultProfiles(failsafeProfile);
        } catch (NamingException ne) {
            log.error("Could not locate JNDI variable {}, defaulting to {} spring profile.",profileJNDIName,failsafeProfile);
            environment.setDefaultProfiles(failsafeProfile);
        }
    }
    

    }

person Jim Doyle    schedule 13.06.2015