Nano Hash - криптовалюты, майнинг, программирование

Spring: добавить файл свойств извне

Я работаю над приложением Spring-MVC, в котором мы готовимся к установке приложения на разных серверах. Поскольку каждый сервер может иметь свою собственную конфигурацию, связанную с базой данных, мы надеемся использовать внешний файл свойств (вне военного файла), который можно прочитать во время запуска проекта. Как я могу использовать этот подход? Для того, чтобы это заработало, я уже перенес код инициализации приложения на Java, таким образом, статическое чтение XML, которое у нас было раньше, не потребуется. Но мы не уверены, как динамически создавать и добавлять файл свойств, который по крайней мере имеет эти 3 значения (URL-адрес JDBC, содержащий имя БД, имя пользователя, пароль). Все таблицы, остальные данные будут созданы автоматически.

Вот класс, в котором инициализируется приложение:

WebConfig.java:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = {"com.ourapp.spring"})
@EnableTransactionManagement
@EnableCaching
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    }


    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
    }

    @Bean
    public ReloadableResourceBundleMessageSource messageSource(){
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("../resources/locale/messages.properties");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }

    @Bean
    public LocaleChangeInterceptor localeInterceptor(){
        LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
        interceptor.setParamName("lang");
        return interceptor;
    }

    @Bean
    public MappingJackson2HttpMessageConverter converter() {
        return new MappingJackson2HttpMessageConverter();
    }

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/img/**").addResourceLocations("/img/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
    }

    @Bean
    public InternalResourceViewResolver getInternalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("../webapp/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

    @Bean
    public DoNotTruncateMyUrls doNotTruncate(){
       return new DoNotTruncateMyUrls();
    }

    @Bean
    public MultipartResolver multipartResolver() {
        return new StandardServletMultipartResolver();
    }

    @Bean
    @Qualifier("primary_tx")
    public HibernateTransactionManager getPrimaryTransactionManager() throws IOException {
        HibernateTransactionManager txName= new HibernateTransactionManager();
        txName.setSessionFactory(sessionFactory().getObject());
        return txName;
    }

    @Bean
    @Qualifier("extended_tx")
    public HibernateTransactionManager txName() throws IOException {
        HibernateTransactionManager txName= new HibernateTransactionManager();
        txName.setSessionFactory(getExtendedSessionFactory().getObject());
        return txName;
    }

    @Bean
    @Qualifier("sessionFactory_origin")
    public LocalSessionFactoryBean sessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(new DataSourceConfig().primaryDataSource());
        sessionFactory.setPackagesToScan("com.ourapp.spring");
        return sessionFactory;
    }

    @Bean
    @Qualifier("sessionFactory_extended")
    public LocalSessionFactoryBean getExtendedSessionFactory() {
        LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
        sessionFactory.setDataSource(new DataSourceConfig_Extended().secondaryDataSource());
        sessionFactory.setPackagesToScan("com.ourapp.spring");
        return sessionFactory;
    }

}

Спасибо. :-)


  • вы используете весеннюю загрузку? Если это так, вы можете использовать сервер конфигурации 22.06.2018
  • @pvpkiran: Нет, к сожалению, я использую spring-mvc. 22.06.2018

Ответы:


1

Вероятно, вы ищете Профили ( @Profile or @Conditional )

Шаг 1. Создайте профиль. Ниже приведен пример для профиля продукта. Точно так же вы можете создать один для dev и qa

import javax.activation.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.jndi.JndiObjectFactoryBean;

@Configuration
@Profile("prod")
@PropertySource("classpath:/com/<SomePath>/app.properties")
public class ProductionProfileConfig {

    @Autowired Environment env;

    @Bean
    public DataSource dataSource() {
        JndiObjectFactoryBean jndiObjectFactoryBean = new JndiObjectFactoryBean();
        jndiObjectFactoryBean.setJndiName(env.getProperty("dbName"));
        jndiObjectFactoryBean.setResourceRef(true);
        jndiObjectFactoryBean.setProxyInterface(javax.sql.DataSource.class);
        return (DataSource) jndiObjectFactoryBean.getObject();
    }
}

Шаг 2. Активируйте профили

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

ОБНОВЛЕНИЕ

Используйте PropertyConfigurator.configure(Loader.getResource(<your-file-path>));, если файл находится за пределами упакованной войны. Позже вы можете просто вводить значения, используя @Value or SPel

22.06.2018
  • Где будет находиться этот файл? На причале это особенно проблема, поскольку Jetty распаковывает war в /tmp в какой-то папке со случайным именем. 22.06.2018
  • Вот как вы помещаете его в путь к классам. Если файл находится внутри папки src, напрямую используйте /file.properties 22.06.2018
  • Я хочу разместить его вне файла WAR. В любом случае, я могу сделать это так же, разместив его где-нибудь снаружи 22.06.2018
  • Используйте PropertyConfigurator.configure(Loader.getResource(‹путь к вашему файлу›)); Позже вы можете просто вводить значения, используя @Value или SPel. 22.06.2018

  • 2

    Напишите менеджер конфигурации, который будет создавать объекты конфигурации на основе имени файла свойств. Например,

    Configuration config = ConfigurationManager.getConfig("dbConfig");

    Итак, теперь ваш объект конфигурации будет содержать все свойства, связанные с db. Когда вы создаете экземпляр объекта конфигурации, считывайте все свойства в этот объект.

    Допустим, ваш файл свойств содержит следующие поля:

    user.name = "Tom" user.password = "pass"

    В следующий раз, когда вам понадобится «user.name», вы просто сделаете config.getString("user.name")

    22.06.2018
  • Где будет находиться этот файл db.config? 22.06.2018
  • лучшим подходом было бы создание отдельного веб-сервиса, который будет обслуживать только ваши свойства 22.06.2018
  • Даже если будет создана новая служба, мне придется загружать значения базы данных во время запуска. Как его изменит отдельный веб-сервис 22.06.2018

  • 3

    Вы можете сделать это с помощью PropertySourcesPlaceholderConfigurer

    Создайте такой бин

    @Bean
    public static PropertySourcesPlaceholderConfigurer devPropertyPlaceholderConfigurer() throws IOException {
       PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
       configurer.setLocations(new PathMatchingResourcePatternResolver().getResources("file:pathtToFile"));
       configurer.setIgnoreUnresolvablePlaceholders(true);
       return configurer;
    }
    

    Например, если вы пишете file:/tmp/dev/*.properties . Он загрузит все файлы свойств в /tmp/dev.

    Если вы хотите настроить его на основе другой среды (разработка, тестирование, производство). тогда вы можете использовать @Profile и создать несколько bean-компонентов.

    @Bean
    @Profile("dev")
    public static PropertySourcesPlaceholderConfigurer devPropertyPlaceholderConfigurer() throws IOException {
       ..... // give dev properties file path
    }
    
    
    @Bean
    @Profile("testing")
    public static PropertySourcesPlaceholderConfigurer testPropertyPlaceholderConfigurer() throws IOException {
    .....// give test properties file path
    }
    
    @Bean
    @Profile("prod")
    public static PropertySourcesPlaceholderConfigurer prodPropertyPlaceholderConfigurer() throws IOException {
    .....// give prod properties file path
    }
    
    22.06.2018
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..