Я перенесла свойства базы данных из кода в скрытый файл и у меня упал сервер. В чём причина?

Изначально у меня свойства базы данных указаны в самом коде:

    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName("org.postgresql.Driver");
        dataSource.setUrl("jdbc:postgresql://localhost:5432/first_db");
        dataSource.setUsername("postgres");
        dataSource.setPassword("postgres");

        return dataSource;
    }

Далее я переношу их в скрытый конфигурационный файл,
оттуда беру необходимые значения и уже при помощи интерфейса Environment подключаюсь к базе данных:

@Configuration
@EnableWebMvc
@PropertySource("classpath:database.properties")
public class SpringConfig implements WebMvcConfigurer {
    private final ApplicationContext applicationContext;
    private final Environment environment;

    @Autowired
    public SpringConfig(ApplicationContext applicationContext, Environment environment) {
        this.applicationContext = applicationContext;
        this.environment = environment;
    }


    @Bean
    public DataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();

        dataSource.setDriverClassName(environment.getProperty("driver"));
        dataSource.setUrl(environment.getProperty("url"));
        dataSource.setUsername(environment.getProperty("username"));
        dataSource.setPassword(environment.getProperty("password"));

        return dataSource;
    }
}

Но после конфигурации БД из внешнего файла у меня приложение перестаёт нормально работать и выдаёт следующую ошибку на сервере:

HTTP Status 500 – Internal Server Error

Type Exception Report

Message Request processing failed; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is org.postgresql.util.PSQLException: ВАЖНО: пользователь "ialin" не прошёл проверку подлинности (по паролю) (pgjdbc: autodetected server-encoding to be windows-1251, if the message is not readable, please check database logs and/or host, port, dbname, user, password, pg_hba.conf)

Description The server encountered an unexpected condition that prevented it from fulfilling the request.

введите сюда описание изображения

После моих изменений psql почему-то теперь использует не имя заданное при инсталляции, а имя пользователя системы, может в этом проблема? Как это исправить?


Ответы (1 шт):

Автор решения: Дмитрий

С высокой вероятностью проблема в том, что вы не учитываете возможность наличия множества свойств в приложении (а на самом деле это всегда так). Давайте рассмотри пример:

@PropertySources({
    @PropertySource("classpath:test.properties"),
    @PropertySource("classpath:my.properties")
})

предположим содержание test.properties такое:

test1 = prop1

в свою очередь my.properties содержит

test2 = prop2

В данном случае я хочу иметь доступ ко всем переменным, которые находятся в двух файлах свойств: test.properties и my.properties. И это работает. Если вы заинжектите переменную типа Environment (как вы сделали у себя) то по ключу test1 получите prop1 , а по ключу test2 - prop2. Все логично. Но что будет если наши файлы свойств будут иметь одинаковые ключи.

предположим содержание test.properties такое:

test1 = prop1

в свою очередь my.properties содержит

test1 = prop2

Надо понимать, что Environment обращается к классу Properties, который доступен в Джаве из коробки, а сам класс Properties основан на обычной Map. А что произойдет, если в Map записать два одинаковых ключа с различными значениями? Правильно! Второе значение затрет первое и по ключу вы получите второе значение, а первое просто исчезнет.

Поскольку чудес не бывает, в указанной выше ситуации для ключа test1 значение из файла my.properties (prop2) затерло значение из файла test.properties (prop1) и теперь по ключу test1 вы всегда получите только значение prop2, а значение prop1 утеряно навсегда (также как в случае использования Map).

Вывод такой: если различные свойства имеют одинаковые ключи, то они будут перезаписывать друг друга в зависимости от приоритетности (назовем это так, а на самом деле все зависит от того, кто последний будет прочитан, ведь под капотом Map, а там хранится последнее перезаписанное значение). И в рассмотреном нами случае my.properties перезапишут все общие ключи с test.properties. Именно поєтому мы имеем такое поведение в приведенном нами примере.

А теперь, когда вы понимаете, как это работает, вам следует учесть еще один момент: в любой системе всегда есть свои свойства. Одно из этих свойств называется именно username. И, скорее всего, вы догадались, что происходит: системные свойства просто перезатирают ваши в случае совпадения их ключей.

Самое простое решение - поменять ключи и впреть не использовать такие "простые" ключи, чтобы не попасть в такую ситуацию. Посему из своего файла свойст с таким контекстом:

driver = some.driver
url = some.url
username = some.username
password = some.password

делаем файл с таким контекстом:

db.driver = some.driver
db.url = some.url
db.username = some.username
db.password = some.password

Думаю, это должно помочь (если, конечно, у вас в коде нет других проблем)

→ Ссылка