一. 问题
spring 配置通常读取 .properties 文件;小项目 配置少;分布式项目 配置文件比较多;不容易运维维护;可以改为读取数据库,在数据库维护;
二. Spring 的已有解决方案
参考:https://www.codeproject.com/articles/28893/loading-application-properties-from-a-database
必须的jar包
- spring.jar (Spring Core)
[PropertiesPlaceholderConfigurer]
- spring-modules.jar (Spring Modules)
[CommonsConfigurationFactoryBean]
- commons-configuration.jar (Commons Configuration)
[DatabaseConfiguration]
需要数据库里 有一个表:
For this example, the database has a schema in it called TEST_SCHEMA
and a table calledAPPLICATION_PROPERTIES_TABLE
with two columns KEY
and VALUE*
.
TEST_SCHEMA.APPLICATION_PROPERTIES_TABLE
Spring Configuration
<!-- Required to connect to datasource --> <bean name="PropertyPlaceholderConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="properties" ref="CommonsConfigurationFactoryBean"/> </bean> <bean name="CommonsConfigurationFactoryBean" class="org.springmodules.commons.configuration.CommonsConfigurationFactoryBean"> <constructor-arg ref="DatabaseConfiguration"/> </bean> <bean name="DatabaseConfiguration" class="org.apache.commons.configuration.DatabaseConfiguration"> <constructor-arg type="javax.sql.DataSource" ref="someDataSource"/> <constructor-arg index="1" value="TEST_SCHEMA.APPLICATION_PROPERTIES_TABLE"/> <constructor-arg index="2" value="KEY"/> <constructor-arg index="3" value="VALUE"/> </bean> <!-- Included to elaborate functionality --> <bean name="PropertiesPrinter " class="example.PropertiesPrinter" initMethod="displayAllProperties"> <property name="fileLocation" value="${file.location}"/> <property name="petDogsName" value="${pet.dogs.name}"/> <property name="keyOne" value="${key.one}"/> </bean> <!-- PropertiesPrinter 为测试 类 -->
三 .自己的方案:
以上方法是通过commons-configuration 来实现,这种每次读取和变动都会访问数据库,在我们的实际应用中,应该是启动的时候读取一次就可以了,没有必要占着数据库连接,而且全局配置不允许应用修改的。
spring 配置:
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> <property name="properties" ref="dataBaseProperties"/> </bean> <bean id="dataBaseProperties" class="com.test.common.utils.DatabaseProperties" > <constructor-arg type="javax.sql.DataSource" ref="confDataSource"/> <constructor-arg value="select key_p,value_p from tb_application_properties where type='common' or type='test' "/> </bean> <bean name="confDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:8066/test" /> <property name="username" value="test" /> <property name="password" value="test" /> </bean>
import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.Properties; import javax.sql.DataSource; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; /** * DatabaseProperties * @version 1.0 2016年12月1日 * @since 1.0 */ public class DatabaseProperties implements InitializingBean, FactoryBean{ private static final Logger log = LoggerFactory.getLogger(DatabaseProperties.class); private static Properties props = new Properties(); private DataSource datasource; //数据源 private String query; //读取的sql public static final String SHIRO_USER_URL = "shiroUserUrl"; public static final String LOCAL_SERVICE = "localService"; public DatabaseProperties(DataSource datasource, String query) { this.datasource = datasource; this.query = query; } @Override public void afterPropertiesSet() throws Exception { initProperties(); } @Override public Object getObject() throws Exception { return props; } @Override public Class getObjectType() { return Properties.class; } @Override public boolean isSingleton() { return true; } private void initProperties() { Connection connection = null; try { connection = datasource.getConnection(); PreparedStatement ps = connection.prepareStatement(query); ResultSet rs = ps.executeQuery(); while (rs.next()) { String key = rs.getString(1); String value = rs.getString(2); if (StringUtils.isNotBlank(key) && StringUtils.isNotBlank(value)) { log.debug("load property. Key=" + key + ",Value=" + value); props.setProperty(key, value); } } rs.close(); ps.close(); } catch (Exception e) { log.error(e.getMessage()); } finally { if (connection != null) { try { connection.close(); } catch (Exception e) { log.error(e.getMessage()); } } } } }
这样 更灵活,参数在数据库里自己配,项目中可以 调用 DatabaseProperties Properties props 取得 配置的信息;
参考原文博客:
http://blog.csdn.net/maoxiang/article/details/4829553