Java基于JNDI实现读写分离的示例代码
一、JNDI数据源配置
在Tomcat的conf目录下,context.xml在其中标签中添加如下JNDI配置:
<Resource name="dataSourceMaster" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
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"/>
<Resource name="dataSourceSlave" factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
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文件中添加如下配置(也可以不配置):
<resource-ref>
<res-ref-name>dataSourceMaster</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<resource-ref>
<res-ref-name>dataSourceSlave</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
三、web.xml配置
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>Archetype Created Web Application</display-name>
<context-param>
<param-name>log4jConfigLocation</param-name>
<param-value>classpath:log4j.properties</param-value>
</context-param>
<context-param>
<param-name>log4jRefreshInterval</param-name>
<param-value>60000</param-value>
</context-param>
<filter>
<filter-name>CharacterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CharacterEncodingFilter</filter-name>
<servlet-name>xiyun</servlet-name>
</filter-mapping>
<servlet>
<servlet-name>xiyun</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value> classpath:conf/spring/spring-servlet.xml </param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>xiyun</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
</web-app>
四、spring-servlet.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.xiaoxi"/>
<mvc:annotation-driven/>
<import resource="classpath:conf/spring/spring-db.xml"/>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/freemarker/"/>
<property name="suffix" value=".ftl"/>
</bean>
</beans>
五、spring-db.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd" >
<!-- 主数据源配置 -->
<bean id="dataSourceMaster" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/dataSourceMaster"/>
</bean>
<!-- 从数据源配置 -->
<bean id="dataSourceSlave" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiName" value="java:comp/env/dataSourceSlave"/>
</bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:annotation-config/>
<bean id="dynamicDataSource" class="com.xiaoxi.config.DynamicRoutingDataSource">
<property name="targetDataSources">
<map>
<entry key="Master" value-ref="dataSourceMaster"/>
<entry key="Slave" value-ref="dataSourceSlave"/>
</map>
</property>
<property name="defaultTargetDataSource" value="dataSourceMaster"/>
</bean>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- 配置数据源 -->
<property name="dataSource" ref="dynamicDataSource"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 映射数据源 -->
<property name="dataSource" ref="dynamicDataSource"/>
<!-- 映射mybatis核心配置文件 -->
<property name="configLocation" value="classpath:conf/spring/mybatis-config.xml"/>
<!-- 映射mapper文件 -->
<property name="mapperLocations">
<list>
<value>classpath:conf/sqlMap
public class DataSourceContextHolder {
private static final ThreadLocal<DbType> contextHolder = new ThreadLocal<>();
public static ThreadLocal<DbType> 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;
@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,否则解析为空(可查看注解定义)
到此这篇关于Java基于JNDI 实现读写分离的示例代码的文章就介绍到这了,更多相关Java JNDI读写分离内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341