Я перенесла свойства базы данных из кода в скрытый файл и у меня упал сервер. В чём причина?
Изначально у меня свойства базы данных указаны в самом коде:
@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
Думаю, это должно помочь (если, конечно, у вас в коде нет других проблем)
