我正在编写一个桌面Spring Boot和数据JPA应用程序
初始设置来自应用程序。属性(一些spring.datasource.和spring.jpa.)
我的程序的一个功能是可以通过ui指定数据库设置(rdbms类型、主机、端口、用户名、密码等)<这就是为什么我想在运行时重新定义已经初始化的db属性。这就是为什么我正在寻找一种方法来做到这一点。
我试着做以下事情:
1)我编写了自定义DbConfig,其中在单例范围内声明了数据源。
@Configuration
public class DBConfig {
@ConfigurationProperties(prefix = "spring.datasource")
@Bean
@Scope("singleton")
@Primary
public DataSource dataSource() {
return DataSourceBuilder
.create()
.build();
}
}
2) 在一些DBSettingsController中,我得到了这个bean的实例并更新了新的设置:
public class DBSettingsController {
...
@Autowired DataSource dataSource;
...
public void applySettings(){
if (dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource){
org.apache.tomcat.jdbc.pool.DataSource tomcatDataSource = (org.apache.tomcat.jdbc.pool.DataSource) dataSource;
PoolConfiguration poolProperties = tomcatDataSource.getPoolProperties();
poolProperties.setUrl("new url");
poolProperties.setDriverClassName("new driver class name");
poolProperties.setUsername("new username");
poolProperties.setPassword("new password");
}
}
}
但它没有效果。Spring数据存储库是使用初始初始化的数据源属性的钢。
我还听说了Spring云配置和@RefreshScope。但我认为在我的小桌面应用程序旁边运行http Web服务器是一种开销。
是否有可能为这样的bean编写自定义范围?或者通过某种方式绑定在application.properties
和相应的bean属性中所做的更改?
这是我的解决方案(由于它创建于2016年,可能已经过时):
DbConfig(实际上并不需要,我只是为了完整性而添加了配置)
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.jta.JtaTransactionManager;
import javax.sql.DataSource;
@Configuration
public class DBConfig extends HibernateJpaAutoConfiguration {
@Value("${spring.jpa.orm}")
private String orm; // this is need for my entities declared in orm.xml located in resources directory
@SuppressWarnings("SpringJavaAutowiringInspection")
public DBConfig(DataSource dataSource, JpaProperties jpaProperties, ObjectProvider<JtaTransactionManager> jtaTransactionManagerProvider) {
super(dataSource, jpaProperties, jtaTransactionManagerProvider);
}
@Override
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(
EntityManagerFactoryBuilder factoryBuilder)
{
final LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = super.entityManagerFactory(factoryBuilder);
entityManagerFactoryBean.setMappingResources(orm);
return entityManagerFactoryBean;
}
}
数据资源配置
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Scope;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
@Configuration
public class DataSourceConfig {
@Bean
@Qualifier("default")
@ConfigurationProperties(prefix = "spring.datasource")
protected DataSource defaultDataSource(){
return DataSourceBuilder
.create()
.build();
}
@Bean
@Primary
@Scope("singleton")
public AbstractRoutingDataSource routingDataSource(@Autowired @Qualifier("default") DataSource defaultDataSource){
RoutingDataSource routingDataSource = new RoutingDataSource();
routingDataSource.addDataSource(RoutingDataSource.DEFAULT,defaultDataSource);
routingDataSource.setDefaultTargetDataSource(defaultDataSource);
return routingDataSource;
}
}
我对RoutingDataSource的扩展:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
public class RoutingDataSource extends AbstractRoutingDataSource {
static final int DEFAULT = 0;
static final int NEW = 1;
private volatile int key = DEFAULT;
void setKey(int key){
this.key = key;
}
private Map<Object,Object> dataSources = new HashMap();
RoutingDataSource() {
setTargetDataSources(dataSources);
}
void addDataSource(int key, DataSource dataSource){
dataSources.put(new Integer(key),dataSource);
}
@Override
protected Object determineCurrentLookupKey() {
return new Integer(key);
}
@Override
protected DataSource determineTargetDataSource() {
return (DataSource) dataSources.get(key);
}
}
这是一个特殊的spring组件,用于在运行时切换数据源:
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.boot.spi.MetadataImplementor;
import org.hibernate.tool.hbm2ddl.SchemaUpdate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.stereotype.Component;
import javax.sql.DataSource;
@Component
public class DBSettingsSwitcher {
@Autowired
private AbstractRoutingDataSource routingDataSource;
@Value("${spring.jpa.orm}")
private String ormMapping;
public void applySettings(DBSettings dbSettings){
if (routingDataSource instanceof RoutingDataSource){
// by default Spring uses DataSource from apache tomcat
DataSource dataSource = DataSourceBuilder
.create()
.username(dbSettings.getUserName())
.password(dbSettings.getPassword())
.url(dbSettings.JDBConnectionURL())
.driverClassName(dbSettings.driverClassName())
.build();
RoutingDataSource rds = (RoutingDataSource)routingDataSource;
rds.addDataSource(RoutingDataSource.NEW,dataSource);
rds.setKey(RoutingDataSource.NEW);
updateDDL(dbSettings);
}
}
private void updateDDL(DBSettings dbSettings){
/** worked on hibernate 5*/
StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.applySetting("hibernate.connection.url", dbSettings.JDBConnectionURL())
.applySetting("hibernate.connection.username", dbSettings.getUserName())
.applySetting("hibernate.connection.password", dbSettings.getPassword())
.applySetting("hibernate.connection.driver_class", dbSettings.driverClassName())
.applySetting("hibernate.dialect", dbSettings.dialect())
.applySetting("show.sql", "false")
.build();
Metadata metadata = new MetadataSources()
.addResource(ormMapping)
.addPackage("specify_here_your_package_with_entities")
.getMetadataBuilder(registry)
.build();
new SchemaUpdate((MetadataImplementor) metadata).execute(false,true);
}
}
其中DB设置只是一个接口(您应该根据需要实施):
public interface DBSettings {
int getPort();
String getServer();
String getSelectedDataBaseName();
String getPassword();
String getUserName();
String dbmsType();
String JDBConnectionURL();
String driverClassName();
String dialect();
}
在Spring上下文中有了自己的DBSettings实现和构建的dbsettingswitcher,现在您可以调用dbsettingswitcher。applySettings(dbSettingsIml)和您的数据请求将被路由到新的数据源。
问题内容: 我需要在运行时在应用程序中更改属性。例如,我有一项服务,该服务发送带有重置密码的电子邮件。要求有效期为12小时。但是我想在运行时将此时间更改为24或更多。我需要给管理员执行此操作的机会。 我的财产文件有 我的服务 我的Spring xml配置 我可以在运行时以某种方式更改此值吗? 问题答案: 只需远离xml配置,就快要到2017年了。 使用@Value,您将从属性文件中获取hours.
问题内容: 如何在运行时更新此环境变量,以便ctypes可以在任何地方加载库?我尝试了以下方法,但似乎都没有用。 问题答案: 在运行诸如Python之类的程序时,动态加载程序(ld.so.1或类似的文件)已经读取LD_LIBRARY_PATH,并且此后将不会注意到任何更改。因此,除非Python软件本身评估LD_LIBRARY_PATH并使用它来构建可能的库路径名或要使用的等效函数,否则在脚本中设
问题内容: 我想向管理界面公开一些(特定于应用程序的)设置,以便用户可以轻松地更改它们,也不必重新启动Django。 我应该怎么做? 我在http://djangopackages.com/grids/g/live-setting/上签出了应用程序(btw django-constance最吸引人),但实际上所有这些应用程序所做的就是将值存储在数据库中,从而提供了一个网站。界面来更改它们,并进行缓
问题内容: 我们在模型pojos中的一些方法已被注释为: columnDefinition 属性取决于数据库供应商,因此在尝试使用Hibernate删除HSQLDB中的架构时会失败: 为了解决这个问题,我正在考虑这个解决方案(但不想花时间,如果不可能的话),在运行时,为每个方法列加注: 获取@Column批注 创建列注释的副本,使用javaassist将columnDefinition设置为nul
返回或设置一个String 类型,表示附加的数据源的名称。可读写。 expression.DataSource expression 必需。该表达式返回“应用于”列表中的对象之一。 示例 如果数据源的名称为空,本示例设置其名称。 Sub SetAndReturnDataSourceName() Dim appOffice As OfficeDataSourceObject Set