千家信息网

Java基于JNDI怎么实现读写分离

发表于:2025-02-03 作者:千家信息网编辑
千家信息网最后更新 2025年02月03日,这篇文章主要介绍"Java基于JNDI怎么实现读写分离",在日常操作中,相信很多人在Java基于JNDI怎么实现读写分离问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"J
千家信息网最后更新 2025年02月03日Java基于JNDI怎么实现读写分离

这篇文章主要介绍"Java基于JNDI怎么实现读写分离",在日常操作中,相信很多人在Java基于JNDI怎么实现读写分离问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答"Java基于JNDI怎么实现读写分离"的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

一、JNDI数据源配置

在Tomcat的conf目录下,context.xml在其中标签中添加如下JNDI配置:

二、JNDI数据源使用

1、在普通web项目中

(1)在web.xml文件中添加如下配置(也可以不配置):

 dataSourceMaster 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配置

                                                   

五、spring-db.xml配置

                                                                                                                                                                                                                                                                                                                   classpath:conf/sqlMap/*.xml                                                                                                                              

六、log4j.properties配置

log4j.rootLogger=DEBUG, CATALINA# Define all the appenderslog4j.appender.CATALINA=org.apache.log4j.RollingFileAppenderlog4j.appender.CATALINA.File=${catalina.base}/logs/catalina.loglog4j.appender.CATALINA.Append=truelog4j.appender.CATALINA.MaxFileSize=10MBlog4j.appender.CATALINA.Encoding=UTF-8# Roll-over the log once per daylog4j.appender.CATALINA.layout = org.apache.log4j.PatternLayoutlog4j.appender.CATALINA.layout.ConversionPattern = %d [%t] %-5p %c- %m%nlog4j.appender.LOCALHOST=org.apache.log4j.RollingFileAppenderlog4j.appender.LOCALHOST.File=${catalina.base}/logs/localhost.loglog4j.appender.LOCALHOST.MaxFileSize=10MBlog4j.appender.LOCALHOST.Append=truelog4j.appender.LOCALHOST.Encoding=UTF-8log4j.appender.LOCALHOST.layout = org.apache.log4j.PatternLayoutlog4j.appender.LOCALHOST.layout.ConversionPattern = %d [%t] %-5p %c- %m%nlog4j.appender.MANAGER=org.apache.log4j.RollingFileAppenderlog4j.appender.MANAGER.File=${catalina.base}/logs/manager.loglog4j.appender.MANAGER.MaxFileSize=10MBlog4j.appender.MANAGER.Append=truelog4j.appender.MANAGER.Encoding=UTF-8log4j.appender.MANAGER.DatePattern='.'yyyy-MM-dd'.log'log4j.appender.MANAGER.layout = org.apache.log4j.PatternLayoutlog4j.appender.MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%nlog4j.appender.HOST-MANAGER=org.apache.log4j.RollingFileAppenderlog4j.appender.HOST-MANAGER.File=${catalina.base}/logs/host-manager.loglog4j.appender.HOST-MANAGER.MaxFileSize=10MBlog4j.appender.HOST-MANAGER.Append=truelog4j.appender.HOST-MANAGER.Encoding=UTF-8log4j.appender.HOST-MANAGER.DatePattern='.'yyyy-MM-dd'.log'log4j.appender.HOST-MANAGER.layout = org.apache.log4j.PatternLayoutlog4j.appender.HOST-MANAGER.layout.ConversionPattern = %d [%t] %-5p %c- %m%nlog4j.appender.CONSOLE=org.apache.log4j.ConsoleAppenderlog4j.appender.CONSOLE.Encoding=UTF-8log4j.appender.CONSOLE.layout = org.apache.log4j.PatternLayoutlog4j.appender.CONSOLE.layout.ConversionPattern = %d [%t] %-5p %c- %m%n# Configure which loggers log to which appenderslog4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost]=INFO, LOCALHOSTlog4j.logger.org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/manager]= INFO, MANAGERlog4j.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)@Componentpublic 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,否则解析为空(可查看注解定义)

到此,关于"Java基于JNDI怎么实现读写分离"的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注网站,小编会继续努力为大家带来更多实用的文章!

0