上一个教程我们讲解如何读取配置数据更加优雅,简洁,本次我们将接着上个教程的成果来应用到项目的数据源初始化配置,如需看上篇教程的同学可点击链接【Spring Boot从入门到进阶教程系列 -- 多种配置数据加载方式详解,优劣分析】
下面我们直接开启代码之旅
步骤1. 我们承接上篇教程的数据库对象配置,该对象字段对应application.properties文件的数据
/** * @author shadow */ @Component @ConfigurationProperties(prefix = "spring.datasource") public class DbConfig { private String database; private String url; private String username; private String password; private String driverClassName; private int initialSize; private int minIdle; private int maxActive; private int maxWait; private int timeBetweenEvictionRunsMillis; private int minEvictableIdleTimeMillis; private String validationQuery; private boolean testWhileIdle; private boolean testOnBorrow; private boolean testOnReturn; private String filters; private String logSlowSql; private String mgbXmlLocation; public String getDatabase() { return database; } public void setDatabase(String database) { this.database = database; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getDriverClassName() { return driverClassName; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public int getInitialSize() { return initialSize; } public void setInitialSize(int initialSize) { this.initialSize = initialSize; } public int getMinIdle() { return minIdle; } public void setMinIdle(int minIdle) { this.minIdle = minIdle; } public int getMaxActive() { return maxActive; } public void setMaxActive(int maxActive) { this.maxActive = maxActive; } public int getMaxWait() { return maxWait; } public void setMaxWait(int maxWait) { this.maxWait = maxWait; } public int getTimeBetweenEvictionRunsMillis() { return timeBetweenEvictionRunsMillis; } public void setTimeBetweenEvictionRunsMillis(int timeBetweenEvictionRunsMillis) { this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis; } public int getMinEvictableIdleTimeMillis() { return minEvictableIdleTimeMillis; } public void setMinEvictableIdleTimeMillis(int minEvictableIdleTimeMillis) { this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis; } public String getValidationQuery() { return validationQuery; } public void setValidationQuery(String validationQuery) { this.validationQuery = validationQuery; } public boolean isTestWhileIdle() { return testWhileIdle; } public void setTestWhileIdle(boolean testWhileIdle) { this.testWhileIdle = testWhileIdle; } public boolean isTestOnBorrow() { return testOnBorrow; } public void setTestOnBorrow(boolean testOnBorrow) { this.testOnBorrow = testOnBorrow; } public boolean isTestOnReturn() { return testOnReturn; } public void setTestOnReturn(boolean testOnReturn) { this.testOnReturn = testOnReturn; } public String getFilters() { return filters; } public void setFilters(String filters) { this.filters = filters; } public String getLogSlowSql() { return logSlowSql; } public void setLogSlowSql(String logSlowSql) { this.logSlowSql = logSlowSql; } public String getMgbXmlLocation() { return mgbXmlLocation; } public void setMgbXmlLocation(String mgbXmlLocation) { this.mgbXmlLocation = mgbXmlLocation; } }
步骤2. 我们已经获得了数据库配置的参数对象,下面我们写一个初始化数据源的实现类
/** * @author shadow */ @Configuration public class DruidConfiguration { @Autowired(required = false) private DbConfig dbConfig; // Druid监控后台配置 @Bean public ServletRegistrationBean druidServlet() { ServletRegistrationBean reg = new ServletRegistrationBean(); reg.setServlet(new StatViewServlet()); reg.addUrlMappings("/druid/*"); reg.addInitParameter("loginUsername", dbConfig.getUsername()); reg.addInitParameter("loginPassword", dbConfig.getPassword()); reg.addInitParameter("logSlowSql", dbConfig.getLogSlowSql()); return reg; } // Druid拦截器配置,包含非过滤路径 @Bean public FilterRegistrationBean filterRegistrationBean() { FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(); filterRegistrationBean.setFilter(new WebStatFilter()); filterRegistrationBean.addUrlPatterns("/*"); filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*"); filterRegistrationBean.addInitParameter("profileEnable", "true"); return filterRegistrationBean; } // DataSource初始化配置 @Primary @Bean(name = "dataSource") public DataSource druidDataSource() { DruidDataSource datasource = new DruidDataSource(); datasource.setUrl(dbConfig.getUrl()); datasource.setUsername(dbConfig.getUsername()); datasource.setPassword(dbConfig.getPassword()); datasource.setDriverClassName(dbConfig.getDriverClassName()); datasource.setInitialSize(dbConfig.getInitialSize()); datasource.setMinIdle(dbConfig.getMinIdle()); datasource.setMaxActive(dbConfig.getMaxActive()); datasource.setMaxWait(dbConfig.getMaxWait()); datasource.setTimeBetweenEvictionRunsMillis(dbConfig.getTimeBetweenEvictionRunsMillis()); datasource.setMinEvictableIdleTimeMillis(dbConfig.getMinEvictableIdleTimeMillis()); datasource.setValidationQuery(dbConfig.getValidationQuery()); datasource.setTestWhileIdle(dbConfig.isTestWhileIdle()); datasource.setTestOnBorrow(dbConfig.isTestOnBorrow()); datasource.setTestOnReturn(dbConfig.isTestOnReturn()); try { datasource.setFilters(dbConfig.getFilters()); } catch (SQLException e) { e.printStackTrace(); } return datasource; } // 数据源事务管理器配置 @Bean(name = "transactionManager") @Primary public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
步骤3. 我们需要加密解密数据源的帐号密码,请参考第一篇教程【Spring Boot从入门到进阶教程系列 -- 外部Tomcat多方式启动,加密解密配置数据】
请看以下核心代码
/** * Spring加载配置文件 * * @author shadow */ public abstract class AbstractPropertyConfigurer extends PropertyPlaceholderConfigurer { private String[] decodeKeys; public AbstractPropertyConfigurer(String filePath, String[] decodeKeys) { this.decodeKeys = decodeKeys; PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); Resource resource = resolver.getResource(filePath); setLocation(resource); } @Override protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties properties) { properties = appendProperties(properties); properties = decodeProperties(properties); super.processProperties(beanFactoryToProcess, properties); } public Properties decodeProperties(Properties properties) { String encrypt_key = properties.getProperty("default.encryptyKey"); encrypt_key = StringUtils.isEmpty(encrypt_key) ? "" : AESUtils.decrypt(encrypt_key); if (!StringUtils.isEmpty(decodeKeys) && decodeKeys.length > 0) { for (String decodeKey : decodeKeys) { String data = properties.getProperty(decodeKey); if (!StringUtils.isEmpty(data)) { properties.put(decodeKey, AESUtils.decrypt(data, encrypt_key)); } } } return properties; } public abstract Properties appendProperties(Properties properties); }
以上代码完成后启动项目即可完成数据源的实例化,顺带附上对比以前xml配置
<!-- 数据源参数 --> <context:property-placeholder location="classpath*:jdbc.properties"/> <!-- 数据源实例化 --> <bean id="springDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"> <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass --> <property name="driverClassName" value="${db.driver}"/> <!-- 基本属性 url、user、password --> <property name="url" value="${db.url}"/> <property name="username" value="${db.user}"/> <property name="password" value="${db.password}"/> <!-- 配置初始化大小、最小、最大 --> <property name="initialSize" value="5"/> <property name="minIdle" value="5"/> <property name="maxActive" value="10"/> <!-- 配置获取连接等待超时的时间 --> <property name="maxWait" value="60000"/> <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --> <property name="timeBetweenEvictionRunsMillis" value="60000"/> <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --> <property name="minEvictableIdleTimeMillis" value="300000"/> <property name="validationQuery" value="SELECT 'x' from dual"/> <property name="testWhileIdle" value="true"/> <property name="testOnBorrow" value="false"/> <property name="testOnReturn" value="false"/> <!-- 打开PSCache,并且指定每个连接上PSCache的大小(Oracle使用) --> <property name="poolPreparedStatements" value="true"/> <property name="maxPoolPreparedStatementPerConnectionSize" value="10"/> <!-- 配置监控统计拦截的filters --> <property name="filters" value="stat"/> </bean>