Spring Cloud Config Server + Wildfly JNDI (MySql) + Spring Data Jpa с Hibernate с обновлением DataSource
Из данного заголовка я получил рабочий образец без Spring Data Part, используя простой шаблон DataSource и JDBC с обновлением источника данных при нажатии на curl для обновления bean-компонента Datasource. Но не смог заставить его работать с Spring Data JPA, потратив бесчисленные часы поиска и просмотра различных сообщений в блоге, таких как https://www.baeldung.com/spring-persistence-jpa-jndi-datasource, https://www.jeejava.com/spring-boot-jndi-datasource/
Я объясню все шаги, а также свяжу проект git с работающим примером шаблона JDBC и проект JPA ниже. Все компоненты настроены локально для демонстрации.
Добавление источника данных JNDI MySql в Wildfly (финальная версия 10.1.10)
Благодаря следующему видео - 3 способа добавления источника данных в Wildfly 9, я добавил два источника данных MySql, указывающих на две разные базы данных на моем локальном сервере mysql, путем развертывания jar коннектора mysql и добавления источника данных с помощью консоли Wildfly, и тестирование обоих из консоли прошло успешно.,
Конфиг Сервер и Клиент
Оба из них настроены правильно и также проверены. Клиенты конфигурации jdbcConfigClient и jpaConfigClient читают свойство поиска JNDI с удаленного сервера конфигурации. MysqlConnector jar, ConfigClient и Config Server развернуты на локальном wildfly с помощью консоли Wildfly (только один клиент развернут для тестирования).
JdbcClient
Вот фрагмент конфигурации источника данных вместе с основным приложением и образцом контроллера для тестирования обновления источника данных:
@SpringBootApplication
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
@RefreshScope
public class ConfigclientApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ConfigclientApplication.class, args);
}
}
@RefreshScope
@RestController
class MessageRestController {
@Autowired
SampleDao dao;
@Value("${message:Hello default}")
private String message;
@RequestMapping("/message")
public String getMessage() {
return this.message;
}
@RequestMapping("/person")
public List<SampleEntity> getAll() {
return dao.findAll();
}
}
@RefreshScope
@Configuration
class DataSourceConfig {
@Value("${jndi.datasource.name}")
private String jndiName;
//@RequestMapping("/jndi")
public String getJndiName() {
return this.jndiName;
}
@Bean
@RefreshScope
public DataSource getDataSource() throws NamingException {
JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
System.out.println("Datasource jndi is "+getJndiName());
//return (DataSource) new JndiTemplate().lookup(getJndiName());
return jndiDataSourceLookup.getDataSource(getJndiName());
}
@Bean
@RefreshScope
public JdbcTemplate getJbdcTemplate() throws NamingException {
return new JdbcTemplate(getDataSource());
}
Для тестирования я нажал на запрос Get /person, чтобы получить список людей, и смог успешно получить ответ с обновлением источника данных, а также с помощью запроса curl для настройки клиента, как это было предложено в Getting Started Centralized Config. Для полной проверки проекта jdbcConfigClient
JPA Config Client
Вот когда все стало проблематично. Я пробовал много разных вещей, но даже с жестко закодированным параметром JNDI приложение не запустилось из-за разных причин, таких как отсутствие параметра URL, недоступный компонент EntityManager или загрузка Hikari Config и сбой, даже если я не использую Hikari Источник данных в конфигурации Java Источник данных, который, как я полагаю, при загрузке Spring пытается загрузить по умолчанию. Я попытался исключить hikari cp из Spring data Starter, попытался исключить автоконфигурацию источника данных, используя свойство exlcude @EnableAutoConfiguration
в основном приложении до сих пор нет смысла. Я использую конфигурацию источника данных Jpa в обычных проектах без JNDI и сервера конфигурации. Ниже приведен фрагмент конфигурации источника данных JPA с основным приложением:
SpringBootApplication
@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
@EnableAutoConfiguration
@RefreshScope
public class ConfigclientApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ConfigclientApplication.class, args);
}
}
@RefreshScope
@RestController
class MessageRestController {
@Autowired
SampleDao dao;
@Value("${message:Hello default}")
private String message;
@RequestMapping("/message")
public String getMessage() {
return this.message;
}
@RequestMapping("/person")
public List<SampleEntity> getAll() {
return dao.findAll();
}
}
@RefreshScope
@Configuration
@EnableJpaRepositories("com.example.demo.dao")
@EnableTransactionManagement
/*@EntityScan("com.example.demo.entity")
@ComponentScan("com.example.demo")*/
class DataSourceConfig {
@Value("${jndi.datasource.name}")
private String jndiName;
public String getJndiName() {
return this.jndiName;
}
@Bean
public DataSource getDataSource() throws NamingException {
//JndiDataSourceLookup jndiDataSourceLookup = new JndiDataSourceLookup();
//System.out.println("Datasource jndi is "+getJndiName());
//return (DataSource) new JndiTemplate().lookup(getJndiName());
//return jndiDataSourceLookup.getDataSource("java:/MySqlDS");
JndiObjectFactoryBean bean = new JndiObjectFactoryBean();
bean.setJndiName(getJndiName());
bean.setProxyInterface(DataSource.class);
bean.setLookupOnStartup(false);
bean.afterPropertiesSet();
return (DataSource)bean.getObject();
}
@Bean
public EntityManagerFactory entityManagerFactory() throws NamingException {
LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
factory.setDataSource(getDataSource());
factory.setPackagesToScan("com.example.demo.entity");
HibernateJpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
vendorAdapter.setDatabase(Database.MYSQL);
vendorAdapter.setShowSql(true);
factory.setJpaVendorAdapter(vendorAdapter);
factory.afterPropertiesSet();
//HashMap<String, Object> properties = new HashMap<>();
//properties.put("hibernate.generate-ddl", Boolean.TRUE.toString());
//properties.put("hibernate.hbm2ddl.auto", "update");
//properties.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
//entityManagerContainer.setJpaPropertyMap(properties);
return factory.getObject();
}
@Bean
public PlatformTransactionManager transactionManager() throws NamingException {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory());
return transactionManager;
}
}
Проект JPA можно найти здесь - JpaConfigClient. Если я полностью удаляю всю конфигурацию источника данных и просто задаю следующее свойство в файле удаленных свойств:
spring.datasource.jndi-name=java:/MySqlDs
Используя автоконфигурацию, конфигурация JPA завершается успешно, и я могу получить данные с помощью запроса почтальона, но это не мое требование, и я не могу обновить источник данных, так как он автоматически конфигурируется при загрузке. Также файл удаленных свойств с именем a-bootiful-client.properties содержит только следующие свойства:
#spring.datasource.jndi-name=java:/MySqlDs
jndi.datasource.name=java.name=java:comp/env/MySqlDs
message=Hi test
Когда приложение запускается, оно правильно ищет источник данных wildfly (я попытался назвать источник данных как java:comp/env/DatasourceName
а также с использованием по умолчанию java:/DatasourceName
также, но это не имело значения, и у меня были те же проблемы, о которых сообщалось выше. Не стесняйтесь раскошелиться на вышеупомянутый проект.