配置文件
datasource:
mysql:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: com.mysql.jdbc.Driver
url: jdbc:mysql://x.x.x.x:3306/table?useUnicode=true&useSSL=false&characterEncoding=utf8
username: root
password: root
initialSize: 1
minIdle: 3
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 30000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,slf4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
sqlserver:
url: jdbc:sqlserver://x.x.x.x:1433;databasename=cwbase001
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
username: root
password: root
hrsqlserver:
url: jdbc:sqlserver://x.x.x.x:1433;databasename=HR
driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
username: root
password: root
首先要将spring boot自带的DataSourceAutoConfiguration禁掉
@SpringBootApplication (exclude = {
DataSourceAutoConfiguration.class
})
public class Application {
public static void main (String[] args) {
SpringApplication.run(Application.class, args);
System.out.println("######## 启动成功 ########" );
}
}
枚举类,多数据源枚举
public enum DataSourceType {
Mysql("mysql" ),
SQLServer("sqlserver" ),
HrSQLServer("hrsqlserver" );
private String name;
DataSourceType(String name) {
this .name = name;
}
public String getName () {
return name;
}
public void setName (String name) {
this .name = name;
}
}
数据库连接配置实体类,用户存储数据相关配置。
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@ConfigurationProperties (prefix = "datasource" )
public class DataSourceBean {
private Map mysql;
private Map sqlserver;
private Map hrsqlserver;
public Map getMysql () {
return mysql;
}
public void setMysql (Map mysql) {
this .mysql = mysql;
}
public Map getSqlserver () {
return sqlserver;
}
public void setSqlserver (Map sqlserver) {
this .sqlserver = sqlserver;
}
public Map getHrsqlserver () {
return hrsqlserver;
}
public void setHrsqlserver (Map hrsqlserver) {
this .hrsqlserver = hrsqlserver;
}
}
@MyDataSource 注解,在service层中使用,AOP中截获设置
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention (RetentionPolicy.RUNTIME)
@Target ({ElementType.METHOD})
public @interface MyDataSource {
DataSourceType value () default DataSourceType.Mysql ;
}
JdbcContextHolder 上下文处理
public class JdbcContextHolder {
private final static ThreadLocal local = new ThreadLocal<>();
public static void putDataSource (String name) {
local.set(name);
}
public static String getDataSource () {
return local.get();
}
}
DynamicDataSource 实现AOP动态切换的关键
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey () {
String dbName = JdbcContextHolder.getDataSource();
if (dbName == null ){
dbName = DataSourceType.Mysql.getName();
}
logger.debug("数据源为: " +dbName);
return dbName;
}
}
数据源处理 utils
import com.alibaba.druid.pool.DruidDataSource;
import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class DataSourceUtil {
public static List getClassFields (Class clazz) {
List list = new ArrayList<>();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields){
list.add(field.getName());
}
return list;
}
public static Object getFieldValueByName (String fieldName, Object o) throws Exception {
String firstLetter = fieldName.substring(0 , 1 ).toUpperCase();
String getter = "get" + firstLetter + fieldName.substring(1 );
Method method = o.getClass().getMethod(getter, new Class[] {});
Object value = method.invoke(o, new Object[] {});
return value;
}
public static DataSource getDataSource (Map params) throws SQLException {
DruidDataSource datasource = new DruidDataSource();
datasource.setUrl(params.get("url" ));
datasource.setUsername(params.get("username" ));
datasource.setPassword(params.get("password" ));
datasource.setDriverClassName(params.get("driverClassName" ));
if (params.containsKey("initialSize" )) {
datasource.setInitialSize(Integer.parseInt(params.get("initialSize" )));
}
if (params.containsKey("minIdle" )) {
datasource.setMinIdle(Integer.parseInt(params.get("minIdle" )));
}
if (params.containsKey("maxActive" )) {
datasource.setMaxActive(Integer.parseInt(params.get("maxActive" )));
}
if (params.containsKey("maxWait" )){
datasource.setMaxWait(Long.parseLong(params.get("maxWait" )));
}
if (params.containsKey("timeBetweenEvictionRunsMillis" )){
datasource.setTimeBetweenEvictionRunsMillis(Long.parseLong(params.get("timeBetweenEvictionRunsMillis" )));
}
if (params.containsKey("minEvictableIdleTimeMillis" )){
datasource.setMinEvictableIdleTimeMillis(Long.parseLong(params.get("minEvictableIdleTimeMillis" )));
}
if (params.containsKey("validationQuery" )){
datasource.setValidationQuery(params.get("validationQuery" ));
}
if (params.containsKey("testWhileIdle" )){
datasource.setTestWhileIdle(Boolean.parseBoolean(params.get("testWhileIdle" )));
}
if (params.containsKey("testOnBorrow" )){
datasource.setTestOnBorrow(Boolean.parseBoolean(params.get("testOnBorrow" )));
}
if (params.containsKey("testOnReturn" )){
datasource.setTestOnBorrow(Boolean.parseBoolean(params.get("testOnReturn" )));
}
if (params.containsKey("poolPreparedStatements" )){
datasource.setPoolPreparedStatements(Boolean.parseBoolean(params.get("poolPreparedStatements" )));
}
if (params.containsKey("maxPoolPreparedStatementPerConnectionSize" )){
datasource.setMaxPoolPreparedStatementPerConnectionSize(
Integer.parseInt(params.get("maxPoolPreparedStatementPerConnectionSize" )));
}
if (params.containsKey("filters" )){
datasource.setFilters(params.get("filters" ));
}
if (params.containsKey("connectionProperties" )){
datasource.setConnectionProperties(params.get("connectionProperties" ));
}
return datasource;
}
}
数据源配置,整合Druid
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.context.annotation.Primary;
import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@SuppressWarnings ("AlibabaRemoveCommentedCode" )
@Configuration
public class DataSourceConfig {
private Logger logger = LoggerFactory.getLogger(this .getClass());
@Autowired
private DataSourceBean dataSourceBean;
@Bean (name = "dynamicDataSource" )
@Primary
public DataSource dataSource () {
DynamicDataSource dynamicDataSource = new DynamicDataSource();
Map map = new HashMap<>();
List fields = DataSourceUtil.getClassFields(DataSourceBean.class);
int i = 0 ;
for (String field:fields){
Map config = null ;
try {
config = (Map) DataSourceUtil.getFieldValueByName(field,dataSourceBean);
} catch (Exception e) {
e.printStackTrace();
}
if (config == null ){
logger.error("数据源配置失败 :" +field);
continue ;
}
try {
DataSource dataSource = DataSourceUtil.getDataSource(config);
if (i == 0 ){
logger.debug("设置默认数据源: " +field);
dynamicDataSource.setDefaultTargetDataSource(dataSource);
}
map.put(field,DataSourceUtil.getDataSource(config));
logger.debug("链接数据库: " +field);
i++;
} catch (SQLException e) {
logger.error("druid configuration initialization filter" , e);
}
}
logger.debug("共配置了 " +i+"个数据源 " );
dynamicDataSource.setTargetDataSources(map);
return dynamicDataSource;
}
@Bean (name="druidServlet" )
public ServletRegistrationBean druidServlet () {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*" );
reg.addInitParameter("allow" , "" );
return reg;
}
@Bean (name = "filterRegistrationBean" )
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" );
filterRegistrationBean.addInitParameter("principalCookieName" ,"USER_COOKIE" );
filterRegistrationBean.addInitParameter("principalSessionName" ,"USER_SESSION" );
filterRegistrationBean.addInitParameter("DruidWebStatFilter" ,"/*" );
return filterRegistrationBean;
}
}
DataSourceAspect Aop依据上下文进行赋值
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import javax.xml.crypto.Data;
import java.lang.reflect.Method;
@Aspect
@Order (3 )
@Component
public class DataSourceAspect {
private Logger logger = LoggerFactory.getLogger(this .getClass());
@Pointcut ("execution(* com.xxx.*.service..*(..)))" )
public void aspect () {
System.out.println("aspect" );
}
@Before ("aspect()" )
private void before (JoinPoint joinPoint) {
Object target = joinPoint.getTarget();
String method = joinPoint.getSignature().getName();
Class> classz = target.getClass();
Class>[] parameterTypes = ((MethodSignature) joinPoint.getSignature()).getMethod().getParameterTypes();
try {
Method m = classz.getMethod(method,parameterTypes);
if (m != null && m.isAnnotationPresent(MyDataSource.class)){
MyDataSource data = m.getAnnotation(MyDataSource.class);
JdbcContextHolder.putDataSource(data.value().getName());
logger.debug("===============上下文赋值完成 :" +data.value().getName());
}else {
JdbcContextHolder.putDataSource(DataSourceType.Mysql.getName());
logger.debug("===============使用默认数据源 :" +DataSourceType.Mysql.getName());
}
}catch (Exception e){
e.printStackTrace();
}
}
}
目录结构
使用方式 在service方法上写入注解
@Override
@MyDataSource (DataSourceType.Mysql)
public int count (HelpDO helpDO, Map map) {
return helpDao.count(getQuery(helpDO,map));
}