Java基于JNDI 实现读写分离的示例代码

网友投稿 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文件中添加如下配置(也可以不配置):

dataSourceMaster&lhttp://t;/res-ref-name>

javax.sql.DataSource

Container

dataSourceSlave

javax.sql.DataSource

Container

三、web.xml配置

Archetype Created Web Application

log4jConfigLocation

classpath:log4j.properties

log4jRefreshInterval

60000

CharacterEncodingFilter

org.springframework.web.filter.CharacterEncodingFilter

encoding

utf-8

forceEncoding

true

CharacterEncodingFilter

xiyun

xiyun

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath:conf/spring/spring-servlet.xml

1

xiyun

*.do

四、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" >

classpath:conf/sqlMap/*.xml

六、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 targetDataSources) {

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 contextHolder = new ThreadLocal<>();

public static ThreadLocal getLocal() {

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文件中添加如下配置(也可以不配置):

dataSourceMaster&lhttp://t;/res-ref-name>

javax.sql.DataSource

Container

dataSourceSlave

javax.sql.DataSource

Container

三、web.xml配置

Archetype Created Web Application

log4jConfigLocation

classpath:log4j.properties

log4jRefreshInterval

60000

CharacterEncodingFilter

org.springframework.web.filter.CharacterEncodingFilter

encoding

utf-8

forceEncoding

true

CharacterEncodingFilter

xiyun

xiyun

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath:conf/spring/spring-servlet.xml

1

xiyun

*.do

四、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" >

classpath:conf/sqlMap/*.xml

六、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 targetDataSources) {

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 contextHolder = new ThreadLocal<>();

public static ThreadLocal getLocal() {

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文件中添加如下配置(也可以不配置):

dataSourceMaster&lhttp://t;/res-ref-name>

javax.sql.DataSource

Container

dataSourceSlave

javax.sql.DataSource

Container

三、web.xml配置

Archetype Created Web Application

log4jConfigLocation

classpath:log4j.properties

log4jRefreshInterval

60000

CharacterEncodingFilter

org.springframework.web.filter.CharacterEncodingFilter

encoding

utf-8

forceEncoding

true

CharacterEncodingFilter

xiyun

xiyun

org.springframework.web.servlet.DispatcherServlet

contextConfigLocation

classpath:conf/spring/spring-servlet.xml

1

xiyun

*.do

四、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" >

classpath:conf/sqlMap/*.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" >

classpath:conf/sqlMap/*.xml

六、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 targetDataSources) {

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 contextHolder = new ThreadLocal<>();

public static ThreadLocal getLocal() {

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小时内删除侵权内容。

上一篇:Avnet EXP视频模块的主要特性及开发应用
下一篇:iOS 微信支付开发流程
相关文章

 发表评论

暂时没有评论,来抢沙发吧~