参考https://gitee.com/owenwangwen/open-capacity-platform项目
springboot springcloud中需要经常使用到关系型数据库或者非关系型数据库,这里做了一个maven的基本模块,别人需要使用关系型或非关系数据库redis时,加入maven依赖即可,代码如下:
com.open.capacity
open-db-core
${unieap.platform.version}
open-db-core的构思,加入druid数据源操作mysql或者oracle同时支持redis的存储。
pom文件
org.springframework.boot
spring-boot-starter-data-redis
com.github.ulisesbocchio
jasypt-spring-boot-starter
1.8
org.springframework.boot
spring-boot-starter-jdbc
mysql
mysql-connector-java
com.alibaba
druid
1.0.31
com.oracle
ojdbc6
11.2.0.3
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.0
org.projectlombok
lombok
commons-lang
commons-lang
commons-collections
commons-collections
commons-beanutils
commons-beanutils
org.springframework.boot
spring-boot-starter-web
org.springframework
spring-context-support
application.yml文件
server:
port: 7777
tomcat:
uri-encoding: UTF-8
spring:
application:
name: unieap-crontab-core
http:
encoding:
charset: utf8
force: true
enabled: true
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: oracle.jdbc.OracleDriver
url: jdbc:oracle:thin:@127.0.0.1:1521:orcl
username: crm_owner_user
password: bss_crm_test
filters: stat,wall
redis:
database: 1
cluster:
nodes:
130.75.131.237:7000,130.75.131.238:7000,130.75.131.239:7000,130.75.131.237:7001,130.75.131.238:7001,130.75.131.239:7001
timeout: 1000 # 连接超时时间(毫秒)
pool:
max-active: 10 # 连接池最大连接数(使用负值表示没有限制)
max-idle: 8 # 连接池中的最大空闲连接
min-idle: 2 # 连接池中的最小空闲连接
max-wait: 100 # 连接池最大阻塞等待时间(使用负值表示没有限制)
mybatis:
config-location: classpath:mybatis.cfg.xml
mapper-locations: classpath*:com/neusoft/*/dao/.xml
logging:
level:
root: INFO
org.hibernate: INFO
org.hibernate.type.descriptor.sql.BasicBinder: TRACE
org.hibernate.type.descriptor.sql.BasicExtractor: TRACE
com.neusoft: DEBUG
com.netflix: DEBUG #用于心跳检测输出的日志
代码文件结构如下
redis代码说明
redis是key-value的存储,为了保证redis的性能,可以将数据分片存储,例如将oauth2的信息分片存储
"access:111111";
"auth_to_access:111111";
"auth:111111";
"refresh_auth:111111";
"access_to_refresh:111111";
"refresh:111111";
"refresh_to_access:111111";
"client_id_to_access:111111";
"uname_to_access:111111";
key都是111111,加前缀分散存储,废话不多说回到redis构建部分,java需要一个key-value序列化的工具 代码如下
package com.neusoft.unieap.redis.config.util;
/**
// 此时定义的序列化操作表示可以序列化所有类的对象,当然,这个对象所在的类一定要实现序列化接口
public class RedisObjectSerializer implements RedisSerializer
@Override
public byte[] serialize(Object obj) throws SerializationException {
if (obj == null) { // 这个时候没有要序列化的对象出现,所以返回的字节数组应该就是一个空数组
return EMPTY_BYTE_ARRAY;
}
return this.serializingConverter.convert(obj); // 将对象变为字节数组
}
@Override
public Object deserialize(byte[] data) throws SerializationException {
if (data == null || data.length == 0) { // 此时没有对象的内容信息
return null;
}
return this.deserializingConverter.convert(data);
}
}
序列化工具准备好后,配置redistemplate操作类注入到spring容器中供别人操作使用
package com.neusoft.unieap.redis.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import com.neusoft.unieap.redis.config.util.RedisObjectSerializer;
/**
@version 创建时间:2017年7月12日 下午3:28:10 类说明br/>*/
@Configuration
//没有此属性就不会装配bean
@ConditionalOnProperty( name="spring.redis.cluster.nodes" , matchIfMissing=false)
public class RedisConfig {
@Bean("redisTemplate")br/>@Primary
public RedisTemplate
RedisTemplate
redisTemplate.setConnectionFactory(factory);
RedisSerializer stringSerializer = new StringRedisSerializer();
RedisSerializer redisObjectSerializer = new RedisObjectSerializer();
redisTemplate.setKeySerializer(stringSerializer); // key的序列化类型
redisTemplate.setHashKeySerializer(stringSerializer);
redisTemplate.setValueSerializer(redisObjectSerializer); // value的序列化类型
redisTemplate.afterPropertiesSet();
redisTemplate.opsForValue().set("hello", "wolrd");
return redisTemplate;
}
}
这时,redis的封装已经结束,我们开始下一步关系型数据库的构建,报文采取的是oracle数据库,支持单数据源以及多数据源的方式。
单数据源整合druid的代码如下
package com.neusoft.unieap.db.config;
import java.sql.SQLException;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
/**
@Configuration
@ConditionalOnProperty(name = { "spring.datasource.enable.dynamic" }, matchIfMissing = true)
public class DruidConfig {
// 将druid纳入监控步骤如下
// 1通过springboot配置文件注入datasource中
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = false)
public DataSource druidDataSource() {
return DataSourceBuilder.create().type(DruidDataSource.class).build();
}
// 2.StatViewServlet注入到spring中
// Druid内置提供了一个StatViewServlet用于展示Druid的统计信息。
// 这个StatViewServlet的用途包括:
// 提供监控信息展示的html页面
// 提供监控信息的JSON API
// 注意:使用StatViewServlet,建议使用druid 0.2.6以上版本。
// 注入第三方没有注解的servlet
@Bean
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = false)
public ServletRegistrationBean druidServlet() { // 主要实现WEB监控的配置处理
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean(new StatViewServlet(),
"/druid/*"); // 现在要进行druid监控的配置处理操作
servletRegistrationBean.addInitParameter("allow", "127.0.0.1,130.75.131.208"); // 白名单
servletRegistrationBean.addInitParameter("deny", "192.168.28.200"); // 黑名单
servletRegistrationBean.addInitParameter("loginUsername", "owen"); // 用户名
servletRegistrationBean.addInitParameter("loginPassword", "1q2w3e4r"); // 密码
servletRegistrationBean.addInitParameter("resetEnable", "false"); // 是否可以重置数据源
return servletRegistrationBean;
}
// 3.对请求进行过滤
// WebStatFilter注入到spring容器中
// 注入第三方没有注解的过滤器
@Bean
@ConditionalOnProperty(name = "spring.datasource.type", havingValue = "com.alibaba.druid.pool.DruidDataSource", matchIfMissing = false)
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new WebStatFilter());
filterRegistrationBean.addUrlPatterns("/*"); // 所有请求进行监控处理
filterRegistrationBean.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.css,/druid/*");
return filterRegistrationBean;
}
}
此时单库的数据源集成druid mybatis已经集成完毕,下面说明动态数据源的配置。
1.需要继承spring的动态数据源
package com.neusoft.unieap.db.config.dynamic.config.util;
import java.util.HashMap;
import java.util.Map;
import javax.sql.DataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
/**
类说明
*/
public class DynamicDataSource extends AbstractRoutingDataSource{
private Map
public DynamicDataSource() {
datasources = new HashMap<>();
super.setTargetDataSources(datasources);
}
public
datasources.put(key, data);
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSourceKey();
}
}
2.定义两个库的标识
package com.neusoft.unieap.db.config.dynamic.config.util;
/**
3.定义线程变量,供每个调用时分配动态数据源
package com.neusoft.unieap.db.config.dynamic.config.util;
/**
@create 2017年7月2日
*/
public class DataSourceHolder {
private static final ThreadLocal
public static DataSourceKey getDataSourceKey() {
return dataSourceKey.get();
}
public static void setDataSourceKey(DataSourceKey type) {
dataSourceKey.set(type);
}
public static void clearDataSourceKey() {
dataSourceKey.remove();
}
}
4.springboot整合动态数据源双库配置
package com.neusoft.unieap.db.config.dynamic.config;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.PlatformTransactionManager;
import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.neusoft.unieap.db.config.dynamic.config.util.DataSourceKey;
import com.neusoft.unieap.db.config.dynamic.config.util.DynamicDataSource;
/**
@create 2017年7月2日br/>*/
@Configuration
@PropertySource("classpath:jdbc.test.properties")
@ConditionalOnProperty(name = { "spring.datasource.enable.dynamic" }, matchIfMissing = false, havingValue = "true")
public class DynamicDataSourceConfig {
private Logger logger = LoggerFactory.getLogger(DynamicDataSourceConfig.class);
// crm库br/>@Value("${spring.datasource.primary.url:#{null}}")
private String primaryDbUrl;
@Value("${spring.datasource.primary.username: #{null}}")
private String primaryUsername;br/>@Value("${spring.datasource.primary.password:#{null}}")
private String primaryPassword;
// bill库br/>@Value("${spring.datasource.secondary.url:#{null}}")
private String secondaryDbUrl;
@Value("${spring.datasource.secondary.username: #{null}}")
private String secondaryUsername;br/>@Value("${spring.datasource.secondary.password:#{null}}")
private String secondaryPassword;
// 公共配置br/>@Value("${spring.datasource.driverClassName:#{null}}")
private String driverClassName;br/>@Value("${spring.datasource.initialSize:#{null}}")
private Integer initialSize;br/>@Value("${spring.datasource.minIdle:#{null}}")
private Integer minIdle;br/>@Value("${spring.datasource.maxActive:#{null}}")
private Integer maxActive;br/>@Value("${spring.datasource.maxWait:#{null}}")
private Integer maxWait;br/>@Value("${spring.datasource.timeBetweenEvictionRunsMillis:#{null}}")
private Integer timeBetweenEvictionRunsMillis;br/>@Value("${spring.datasource.minEvictableIdleTimeMillis:#{null}}")
private Integer minEvictableIdleTimeMillis;br/>@Value("${spring.datasource.validationQuery:#{null}}")
private String validationQuery;br/>@Value("${spring.datasource.testWhileIdle:#{null}}")
private Boolean testWhileIdle;br/>@Value("${spring.datasource.testOnBorrow:#{null}}")
private Boolean testOnBorrow;br/>@Value("${spring.datasource.testOnReturn:#{null}}")
private Boolean testOnReturn;br/>@Value("${spring.datasource.poolPreparedStatements:#{null}}")
private Boolean poolPreparedStatements;br/>@Value("${spring.datasource.maxPoolPreparedStatementPerConnectionSize:#{null}}")
private Integer maxPoolPreparedStatementPerConnectionSize;br/>@Value("${spring.datasource.filters:#{null}}")
private String filters;br/>@Value("{spring.datasource.connectionProperties:#{null}}")
private String connectionProperties;
// 不需要纳入spring容器
public DataSource crmDataSource() {
DruidDataSource crmDataSource = new DruidDataSource();
crmDataSource.setUrl(this.primaryDbUrl);
crmDataSource.setUsername(this.primaryUsername);// 用户名
crmDataSource.setPassword(this.primaryPassword);// 密码
crmDataSource.setDriverClassName(driverClassName);
this.setCommons(crmDataSource);
return crmDataSource;
}
// 不需要纳入spring容器
public DataSource billDataSource() {
DruidDataSource billDataSource = new DruidDataSource();
billDataSource.setUrl(secondaryDbUrl);
billDataSource.setUsername(secondaryUsername);// 用户名
billDataSource.setPassword(secondaryPassword);// 密码
billDataSource.setDriverClassName(driverClassName);
this.setCommons(billDataSource);
return billDataSource;
}
@Bean // 只需要纳入动态数据源到spring容器br/>@Primary
public DataSource dataSource() {
DynamicDataSource dataSource = new DynamicDataSource();
DataSource crmDataSource = this.crmDataSource();
DataSource billDataSource = this.billDataSource();
dataSource.addDataSource(DataSourceKey.crm, crmDataSource);
dataSource.addDataSource(DataSourceKey.bill, billDataSource);
dataSource.setDefaultTargetDataSource(crmDataSource);
return dataSource;
}
@Bean
public StatFilter statFilter() {
StatFilter statFilter = new StatFilter();
statFilter.setLogSlowSql(true);
statFilter.setMergeSql(true);
statFilter.setSlowSqlMillis(1000);
return statFilter;
}
@Bean
public WallFilter wallFilter() {
WallFilter wallFilter = new WallFilter();
// 允许执行多条SQL
WallConfig config = new WallConfig();
config.setMultiStatementAllow(true);
wallFilter.setConfig(config);
return wallFilter;
}
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
servletRegistrationBean.setServlet(new StatViewServlet());
servletRegistrationBean.addUrlMappings("/druid/*");
return servletRegistrationBean;
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
@Bean
public NamedParameterJdbcTemplate namedParameterJdbcTemplate(DataSource dataSource) {
return new NamedParameterJdbcTemplate(dataSource);
}
private void setCommons(DruidDataSource dataSource) {
// configuration
if (initialSize != null) {
dataSource.setInitialSize(initialSize);
}
if (minIdle != null) {
dataSource.setMinIdle(minIdle);
}
if (maxActive != null) {
dataSource.setMaxActive(maxActive);
}
if (maxWait != null) {
dataSource.setMaxWait(maxWait);
}
if (timeBetweenEvictionRunsMillis != null) {
dataSource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
}
if (minEvictableIdleTimeMillis != null) {
dataSource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
}
if (validationQuery != null) {
dataSource.setValidationQuery(validationQuery);
}
if (testWhileIdle != null) {
dataSource.setTestWhileIdle(testWhileIdle);
}
if (testOnBorrow != null) {
dataSource.setTestOnBorrow(testOnBorrow);
}
if (testOnReturn != null) {
dataSource.setTestOnReturn(testOnReturn);
}
if (poolPreparedStatements != null) {
dataSource.setPoolPreparedStatements(poolPreparedStatements);
}
if (maxPoolPreparedStatementPerConnectionSize != null) {
dataSource.setMaxPoolPreparedStatementPerConnectionSize(maxPoolPreparedStatementPerConnectionSize);
}
if (connectionProperties != null) {
dataSource.setConnectionProperties(connectionProperties);
}
List filters = new ArrayList<>();
filters.add(statFilter());
filters.add(wallFilter());
dataSource.setProxyFilters(filters);
}
@Bean // 将数据源纳入spring事物管理br/>@Primary
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
@Bean
public PlatformTransactionManager annotationDrivenTransactionManager(DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
此处一个支持单数据源或者多数据源的关系型数据库核心模块已经集成完毕,支持redis-cluster分布式redis存储的nosql核心模块也已经集成完毕,可以根据业务看是否集成elasticsearch mogondb等存储到此模块,目前我们只使用oracle和redis,只做了以上封装。
转载于:https://blog.51cto.com/13005375/2053873