linux怎么查看本机内存大小
213
2022-11-15
Java基于JNDI 实现读写分离的示例代码
目录一、JNDI数据源配置二、JNDI数据源使用三、web.xml配置四、spring-servlet.xml配置五、spring-db.xml配置六、log4j.properties配置七、相关路由数据源切换逻辑代码八、搭建过程中遇到的问题和解决方案
一、JNDI数据源配置
在Tomcat的conf目录下,context.xml在其中标签中添加如下JNDI配置:
auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWaitMillis="30000" username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/user_master?useUnicode=true&characterEncoding=utf-8"/> auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWaitMillis="30000" username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/user_slave?useUnicode=true&characterEncoding=utf-8"/> 二、JNDI数据源使用 1、在普通web项目中 (1)在web.xml文件中添加如下配置(也可以不配置): 三、web.xml配置
四、spring-servlet.xml配置 xmlns:context="http://springframework.org/schema/context" xmlns:mvc="http://springframework.org/schema/mvc" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://springframework.org/schema/mvc http://springframework.org/schema/mvc/spring-mvc.xsd http://springframework.org/schema/context http://springframework.org/schema/context/spring-context.xsd"> 五、spring-db.xml配置 xmlns:aop="http://springframework.org/schema/aop" xmlns:context="http://springframework.org/schema/context" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://springframework.org/schema/context http://springframework.org/schema/context/spring-context.xsd UdkzaM http://springframework.org/schema/aop http://springframework.org/schema/aop/spring-aop.xsd" > 六、log4j.properties配置 log4j.rootLogger=DEBUG, CATALINA# Define all the appenders log4j.appender.CATALINA=org.apache.log4j.RollingFileAppender log4j.appender.CATALINA.File=${catalina.base}/logs/catalina.log log4j.appender.CATALINA.Append=true log4j.appender.CATALINA.MaxFileSize=10MB log4j.appender.CATALINA.Encoding=UTF-8 # Roll-over the log once per day log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.LOCALHOST=org.apache.log4j.RollingFileAppender log4j.appender.LOCALHOST.File=${catalina.base}/logs/localhost.log log4j.appender.LOCALHOST.MaxFileSize=10MB log4j.appender.LOCALHOST.Append=true log4j.appender.LOCALHOST.Encoding=UTF-8 log4j.appender.LOCALHOST.layout = org.apache.log4j.PatternLayout log4j.appender.LOCALHOST.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.MANAGER=org.apache.log4j.RollingFileAppender log4j.appender.MANAGER.File=${catalina.base}/logs/manager.log log4j.appender.MANAGER.MaxFileSize=10MB log4j.appender.MANAGER.Append=true log4j.appender.MANAGER.Encoding=UTF-8 log4j.appender.MANAGER.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.MANAGER.layout = org.apache.log4j.PatternLayout log4j.appender.MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.HOST-MANAGER=org.apache.log4j.RollingFileAppender log4j.appender.HOST-MANAGER.File=${catalina.base}/logs/host-manager.log log4j.appender.HOST-MANAGER.MaxFileSize=10MB log4j.appender.HOST-MANAGER.Append=true log4j.appender.HOST-MANAGER.Encoding=UTF-8 log4j.appender.HOST-MANAGER.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.HOST-MANAGER.layout = org.apache.log4j.PatternLayout log4j.appender.HOST-MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Encoding=UTF-8 log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern = %d [%t] %-5p %c- %m%n # Configure which loggers log to which appenders log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO, LOCALHOST log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]= INFO, MANAGER log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]= INFO, HOST-MANAGER 七、相关路由数据源切换逻辑代码 package com.xiaoxi.config; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import java.util.Map; public class DynamicRoutingDataSource extends AbstractRoutingDataSource { @Override public void setTargetDataSources(Map super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); } @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDbType(); } } package com.xiaoxi.config; /** * 线程上下文 * 用于保存线程本地变量DbType(用于切换数据源) * 如果是异步线程操作,需要用InheritableThreadLocal (需要保存父线程的变量) * * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public class DataSourceContextHolder { private static final ThreadLocal public static ThreadLocal return contextHolder; } private DataSourceContextHolder () {} public static String getDbType() { return contextHolder.get() == null ? DbType.MASTER.dbType : contextHolder.get().dbType; } public static void setDbType(DbType dbType) { contextHolder.set(dbType); } public static void clearDbType() { contextHolder.remove(); } public enum DbType { MASTER("Master"), SLAVE("Slave"); private String dbType; DbType(String dbType) { this.dbType = dbType; } public String getDbType() { return dbType; } } } package com.xiaoxi.aop; import com.xiaoxi.config.DataSourceContextHolder; import org.apache.log4j.Logger; 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.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 数据源切面,用于在执行sql前进行读写数据源切换 * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ @Aspect @Order(-1) @Component public class DataSourceAop { private static Logger logger = Logger.getLogger(DataSourceAop.class); @Before("execution(* com.xiaoxi.dao..*.query*(..))") public void setReadDataSourceType() { DataSourceContextHolder.setDbType(DataSourceContextHolder.DbType.MASTER); logger.debug("[DataSourceAop] DataSource Covert To SLAVE"); } @Before("execution(* com.xiaoxi.dao..*.insert*(..))" + "|| execution(* com.xiaoxi.dao..*.update*(..))" + "|| execution(* com.xiaoxi.dao..*.delete*(..))") public void setWriteDataSourceType() { DataSourceContextHolder.setDbType(DataSourceContextHolder.DbType.SLAVE); logger.debug("[DataSourceAop] DataSource Covert To MASTER"); } /** ☆☆☆☆☆ 也可以获取参数中路由字段进行切换数据源 ☆☆☆☆☆ **/ @Pointcut("execution(* com.xiaoxi.dao..*.*(..))") public void cutPoint() {} @Before(value="cutPoint()") public void setDynamicDataSource(JoinPoint point){ String className = point.getTarget().getClass().getSimpleName(); String methodName = point.getSignature().getName(); String log = "[DataSourceAop] className:%s, methodName:%s"; logger.debug(String.format(log, className, methodName)); } } 八、搭建过程中遇到的问题和解决方案 1、注入数据源dataSourceMaster和dataSourceSlave失败 spring 中jndiName配置的数据源名称和Tomcat配置文件中Resource name存在区别,并非一致,其中java:comp/env为环境,否则会报can not find jndi name … 2、Cannot create JDBC driver of class ‘' for connect URL ‘null' 3、The requested resource is not available(404) 分析了web.xml和servlet.xml发现配置无误,注解驱动和包扫描都配置,但仍然访问不了,后发现 项目启动过程中打印的日志存在问题,如下: 2019-12-17 16:20:41,767 [RMI TCP Connection(3)-127.0.0.1] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping- Mapped “{[/userInfo],methods=[GET]}” onto public java.lang.String com.xiaoxi.controller.UserInfoController.queryUserInfoById(java.lang.String) 通过分析发现这里的请求映射,通过controller的requestMapping映射到具体方法,却丢失了方法上的requestMapping路径,后发现方法RequestMapping写法如下: @Controller @RequestMapping("/userInfo") public class UserInfoController { private static Logger logger =Logger.getLogger(UserInfoController.class); @Autowired private UserInfoService userInfoService; @ResponseBody @RequestMapping(name= "/queryUserInfoById", method = RequestMethod.GET) public String queryUserInfoById(@RequestParam("id") String id){ logger.info("UserInfoController.queryUserInfoById. id:{}" + id); UserInfo userInfo = userInfoService.queryUserInfoById(id); return jsON.toJSONString(userInfo); } } 此处的RequestMapping属性name应该改为value,否则解析为空(可查看注解定义)
auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWaitMillis="30000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/user_master?useUnicode=true&characterEncoding=utf-8"/>
auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWaitMillis="30000" username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/user_slave?useUnicode=true&characterEncoding=utf-8"/> 二、JNDI数据源使用 1、在普通web项目中 (1)在web.xml文件中添加如下配置(也可以不配置): 三、web.xml配置
四、spring-servlet.xml配置 xmlns:context="http://springframework.org/schema/context" xmlns:mvc="http://springframework.org/schema/mvc" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://springframework.org/schema/mvc http://springframework.org/schema/mvc/spring-mvc.xsd http://springframework.org/schema/context http://springframework.org/schema/context/spring-context.xsd"> 五、spring-db.xml配置 xmlns:aop="http://springframework.org/schema/aop" xmlns:context="http://springframework.org/schema/context" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://springframework.org/schema/context http://springframework.org/schema/context/spring-context.xsd UdkzaM http://springframework.org/schema/aop http://springframework.org/schema/aop/spring-aop.xsd" > 六、log4j.properties配置 log4j.rootLogger=DEBUG, CATALINA# Define all the appenders log4j.appender.CATALINA=org.apache.log4j.RollingFileAppender log4j.appender.CATALINA.File=${catalina.base}/logs/catalina.log log4j.appender.CATALINA.Append=true log4j.appender.CATALINA.MaxFileSize=10MB log4j.appender.CATALINA.Encoding=UTF-8 # Roll-over the log once per day log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.LOCALHOST=org.apache.log4j.RollingFileAppender log4j.appender.LOCALHOST.File=${catalina.base}/logs/localhost.log log4j.appender.LOCALHOST.MaxFileSize=10MB log4j.appender.LOCALHOST.Append=true log4j.appender.LOCALHOST.Encoding=UTF-8 log4j.appender.LOCALHOST.layout = org.apache.log4j.PatternLayout log4j.appender.LOCALHOST.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.MANAGER=org.apache.log4j.RollingFileAppender log4j.appender.MANAGER.File=${catalina.base}/logs/manager.log log4j.appender.MANAGER.MaxFileSize=10MB log4j.appender.MANAGER.Append=true log4j.appender.MANAGER.Encoding=UTF-8 log4j.appender.MANAGER.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.MANAGER.layout = org.apache.log4j.PatternLayout log4j.appender.MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.HOST-MANAGER=org.apache.log4j.RollingFileAppender log4j.appender.HOST-MANAGER.File=${catalina.base}/logs/host-manager.log log4j.appender.HOST-MANAGER.MaxFileSize=10MB log4j.appender.HOST-MANAGER.Append=true log4j.appender.HOST-MANAGER.Encoding=UTF-8 log4j.appender.HOST-MANAGER.DatePattern='.'yyyy-MM-dd'.log' log4j.appender.HOST-MANAGER.layout = org.apache.log4j.PatternLayout log4j.appender.HOST-MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender log4j.appender.CONSOLE.Encoding=UTF-8 log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout log4j.appender.CONSOLE.layout.ConversionPattern = %d [%t] %-5p %c- %m%n # Configure which loggers log to which appenders log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO, LOCALHOST log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]= INFO, MANAGER log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]= INFO, HOST-MANAGER 七、相关路由数据源切换逻辑代码 package com.xiaoxi.config; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import java.util.Map; public class DynamicRoutingDataSource extends AbstractRoutingDataSource { @Override public void setTargetDataSources(Map super.setTargetDataSources(targetDataSources); super.afterPropertiesSet(); } @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDbType(); } } package com.xiaoxi.config; /** * 线程上下文 * 用于保存线程本地变量DbType(用于切换数据源) * 如果是异步线程操作,需要用InheritableThreadLocal (需要保存父线程的变量) * * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ public class DataSourceContextHolder { private static final ThreadLocal public static ThreadLocal return contextHolder; } private DataSourceContextHolder () {} public static String getDbType() { return contextHolder.get() == null ? DbType.MASTER.dbType : contextHolder.get().dbType; } public static void setDbType(DbType dbType) { contextHolder.set(dbType); } public static void clearDbType() { contextHolder.remove(); } public enum DbType { MASTER("Master"), SLAVE("Slave"); private String dbType; DbType(String dbType) { this.dbType = dbType; } public String getDbType() { return dbType; } } } package com.xiaoxi.aop; import com.xiaoxi.config.DataSourceContextHolder; import org.apache.log4j.Logger; 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.springframework.core.annotation.Order; import org.springframework.stereotype.Component; /** * 数据源切面,用于在执行sql前进行读写数据源切换 * 〈功能详细描述〉 * * @see [相关类/方法](可选) * @since [产品/模块版本](可选) */ @Aspect @Order(-1) @Component public class DataSourceAop { private static Logger logger = Logger.getLogger(DataSourceAop.class); @Before("execution(* com.xiaoxi.dao..*.query*(..))") public void setReadDataSourceType() { DataSourceContextHolder.setDbType(DataSourceContextHolder.DbType.MASTER); logger.debug("[DataSourceAop] DataSource Covert To SLAVE"); } @Before("execution(* com.xiaoxi.dao..*.insert*(..))" + "|| execution(* com.xiaoxi.dao..*.update*(..))" + "|| execution(* com.xiaoxi.dao..*.delete*(..))") public void setWriteDataSourceType() { DataSourceContextHolder.setDbType(DataSourceContextHolder.DbType.SLAVE); logger.debug("[DataSourceAop] DataSource Covert To MASTER"); } /** ☆☆☆☆☆ 也可以获取参数中路由字段进行切换数据源 ☆☆☆☆☆ **/ @Pointcut("execution(* com.xiaoxi.dao..*.*(..))") public void cutPoint() {} @Before(value="cutPoint()") public void setDynamicDataSource(JoinPoint point){ String className = point.getTarget().getClass().getSimpleName(); String methodName = point.getSignature().getName(); String log = "[DataSourceAop] className:%s, methodName:%s"; logger.debug(String.format(log, className, methodName)); } } 八、搭建过程中遇到的问题和解决方案 1、注入数据源dataSourceMaster和dataSourceSlave失败 spring 中jndiName配置的数据源名称和Tomcat配置文件中Resource name存在区别,并非一致,其中java:comp/env为环境,否则会报can not find jndi name … 2、Cannot create JDBC driver of class ‘' for connect URL ‘null' 3、The requested resource is not available(404) 分析了web.xml和servlet.xml发现配置无误,注解驱动和包扫描都配置,但仍然访问不了,后发现 项目启动过程中打印的日志存在问题,如下: 2019-12-17 16:20:41,767 [RMI TCP Connection(3)-127.0.0.1] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping- Mapped “{[/userInfo],methods=[GET]}” onto public java.lang.String com.xiaoxi.controller.UserInfoController.queryUserInfoById(java.lang.String) 通过分析发现这里的请求映射,通过controller的requestMapping映射到具体方法,却丢失了方法上的requestMapping路径,后发现方法RequestMapping写法如下: @Controller @RequestMapping("/userInfo") public class UserInfoController { private static Logger logger =Logger.getLogger(UserInfoController.class); @Autowired private UserInfoService userInfoService; @ResponseBody @RequestMapping(name= "/queryUserInfoById", method = RequestMethod.GET) public String queryUserInfoById(@RequestParam("id") String id){ logger.info("UserInfoController.queryUserInfoById. id:{}" + id); UserInfo userInfo = userInfoService.queryUserInfoById(id); return jsON.toJSONString(userInfo); } } 此处的RequestMapping属性name应该改为value,否则解析为空(可查看注解定义)
auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWaitMillis="30000"
username="root" password="root" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/user_slave?useUnicode=true&characterEncoding=utf-8"/>
二、JNDI数据源使用
1、在普通web项目中
(1)在web.xml文件中添加如下配置(也可以不配置):
三、web.xml配置
四、spring-servlet.xml配置
xmlns:context="http://springframework.org/schema/context" xmlns:mvc="http://springframework.org/schema/mvc" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://springframework.org/schema/mvc http://springframework.org/schema/mvc/spring-mvc.xsd http://springframework.org/schema/context http://springframework.org/schema/context/spring-context.xsd">
xmlns:context="http://springframework.org/schema/context" xmlns:mvc="http://springframework.org/schema/mvc"
xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd
http://springframework.org/schema/mvc http://springframework.org/schema/mvc/spring-mvc.xsd
http://springframework.org/schema/context http://springframework.org/schema/context/spring-context.xsd">
五、spring-db.xml配置
xmlns:aop="http://springframework.org/schema/aop" xmlns:context="http://springframework.org/schema/context" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://springframework.org/schema/context http://springframework.org/schema/context/spring-context.xsd UdkzaM http://springframework.org/schema/aop http://springframework.org/schema/aop/spring-aop.xsd" >
xmlns:aop="http://springframework.org/schema/aop" xmlns:context="http://springframework.org/schema/context"
xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd
http://springframework.org/schema/context http://springframework.org/schema/context/spring-context.xsd UdkzaM
http://springframework.org/schema/aop http://springframework.org/schema/aop/spring-aop.xsd" >
六、log4j.properties配置
log4j.rootLogger=DEBUG, CATALINA# Define all the appenders
log4j.appender.CATALINA=org.apache.log4j.RollingFileAppender
log4j.appender.CATALINA.File=${catalina.base}/logs/catalina.log
log4j.appender.CATALINA.Append=true
log4j.appender.CATALINA.MaxFileSize=10MB
log4j.appender.CATALINA.Encoding=UTF-8
# Roll-over the log once per day
log4j.appender.CATALINA.layout = org.apache.log4j.PatternLayout
log4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.LOCALHOST=org.apache.log4j.RollingFileAppender
log4j.appender.LOCALHOST.File=${catalina.base}/logs/localhost.log
log4j.appender.LOCALHOST.MaxFileSize=10MB
log4j.appender.LOCALHOST.Append=true
log4j.appender.LOCALHOST.Encoding=UTF-8
log4j.appender.LOCALHOST.layout = org.apache.log4j.PatternLayout
log4j.appender.LOCALHOST.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.MANAGER=org.apache.log4j.RollingFileAppender
log4j.appender.MANAGER.File=${catalina.base}/logs/manager.log
log4j.appender.MANAGER.MaxFileSize=10MB
log4j.appender.MANAGER.Append=true
log4j.appender.MANAGER.Encoding=UTF-8
log4j.appender.MANAGER.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.MANAGER.layout = org.apache.log4j.PatternLayout
log4j.appender.MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.HOST-MANAGER=org.apache.log4j.RollingFileAppender
log4j.appender.HOST-MANAGER.File=${catalina.base}/logs/host-manager.log
log4j.appender.HOST-MANAGER.MaxFileSize=10MB
log4j.appender.HOST-MANAGER.Append=true
log4j.appender.HOST-MANAGER.Encoding=UTF-8
log4j.appender.HOST-MANAGER.DatePattern='.'yyyy-MM-dd'.log'
log4j.appender.HOST-MANAGER.layout = org.apache.log4j.PatternLayout
log4j.appender.HOST-MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Encoding=UTF-8
log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern = %d [%t] %-5p %c- %m%n
# Configure which loggers log to which appenders
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO, LOCALHOST
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]= INFO, MANAGER
log4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager]= INFO, HOST-MANAGER
七、相关路由数据源切换逻辑代码
package com.xiaoxi.config;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import java.util.Map;
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
@Override
public void setTargetDataSources(Map
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDbType();
}
}
package com.xiaoxi.config;
/**
* 线程上下文
* 用于保存线程本地变量DbType(用于切换数据源)
* 如果是异步线程操作,需要用InheritableThreadLocal (需要保存父线程的变量)
*
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
public class DataSourceContextHolder {
private static final ThreadLocal
public static ThreadLocal
return contextHolder;
}
private DataSourceContextHolder () {}
public static String getDbType() {
return contextHolder.get() == null ? DbType.MASTER.dbType : contextHolder.get().dbType;
}
public static void setDbType(DbType dbType) {
contextHolder.set(dbType);
}
public static void clearDbType() {
contextHolder.remove();
}
public enum DbType {
MASTER("Master"),
SLAVE("Slave");
private String dbType;
DbType(String dbType) {
this.dbType = dbType;
}
public String getDbType() {
return dbType;
}
}
}
package com.xiaoxi.aop;
import com.xiaoxi.config.DataSourceContextHolder;
import org.apache.log4j.Logger;
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.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 数据源切面,用于在执行sql前进行读写数据源切换
* 〈功能详细描述〉
*
* @see [相关类/方法](可选)
* @since [产品/模块版本](可选)
*/
@Aspect
@Order(-1)
@Component
public class DataSourceAop {
private static Logger logger = Logger.getLogger(DataSourceAop.class);
@Before("execution(* com.xiaoxi.dao..*.query*(..))")
public void setReadDataSourceType() {
DataSourceContextHolder.setDbType(DataSourceContextHolder.DbType.MASTER);
logger.debug("[DataSourceAop] DataSource Covert To SLAVE");
}
@Before("execution(* com.xiaoxi.dao..*.insert*(..))" +
"|| execution(* com.xiaoxi.dao..*.update*(..))" +
"|| execution(* com.xiaoxi.dao..*.delete*(..))")
public void setWriteDataSourceType() {
DataSourceContextHolder.setDbType(DataSourceContextHolder.DbType.SLAVE);
logger.debug("[DataSourceAop] DataSource Covert To MASTER");
}
/** ☆☆☆☆☆ 也可以获取参数中路由字段进行切换数据源 ☆☆☆☆☆ **/
@Pointcut("execution(* com.xiaoxi.dao..*.*(..))")
public void cutPoint() {}
@Before(value="cutPoint()")
public void setDynamicDataSource(JoinPoint point){
String className = point.getTarget().getClass().getSimpleName();
String methodName = point.getSignature().getName();
String log = "[DataSourceAop] className:%s, methodName:%s";
logger.debug(String.format(log, className, methodName));
}
}
八、搭建过程中遇到的问题和解决方案
1、注入数据源dataSourceMaster和dataSourceSlave失败
spring 中jndiName配置的数据源名称和Tomcat配置文件中Resource name存在区别,并非一致,其中java:comp/env为环境,否则会报can not find jndi name …
2、Cannot create JDBC driver of class ‘' for connect URL ‘null'
3、The requested resource is not available(404)
分析了web.xml和servlet.xml发现配置无误,注解驱动和包扫描都配置,但仍然访问不了,后发现
项目启动过程中打印的日志存在问题,如下:
2019-12-17 16:20:41,767 [RMI TCP Connection(3)-127.0.0.1] INFO org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping- Mapped “{[/userInfo],methods=[GET]}” onto public java.lang.String com.xiaoxi.controller.UserInfoController.queryUserInfoById(java.lang.String)
通过分析发现这里的请求映射,通过controller的requestMapping映射到具体方法,却丢失了方法上的requestMapping路径,后发现方法RequestMapping写法如下:
@Controller
@RequestMapping("/userInfo")
public class UserInfoController {
private static Logger logger =Logger.getLogger(UserInfoController.class);
@Autowired
private UserInfoService userInfoService;
@ResponseBody
@RequestMapping(name= "/queryUserInfoById", method = RequestMethod.GET)
public String queryUserInfoById(@RequestParam("id") String id){
logger.info("UserInfoController.queryUserInfoById. id:{}" + id);
UserInfo userInfo = userInfoService.queryUserInfoById(id);
return jsON.toJSONString(userInfo);
}
}
此处的RequestMapping属性name应该改为value,否则解析为空(可查看注解定义)
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~