一、Dubbo概念介绍
1.1、Dubbo是什么?
Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求,并且本质上是个服务调用的东东,说白了就是个远程服务调用的分布式框架
其核心部分包含:
1》远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
2》集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
3》自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
1.2. Dubbo能做什么?
1.透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
2.软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
1.3. dubbo的架构
dubbo架构图如下所示:
节点角色说明:
Provider: 暴露服务的服务提供方。(服务提供者在启动时,向注册中心注册自己提供的服务。)
Consumer: 调用远程服务的服务消费方。(服务消费者在启动时,向注册中心订阅自己所需的服务。 )
Registry: 服务注册与发现的注册中心。(注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。)
Monitor: 统计服务的调用次调和调用时间的监控中心。(服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。)
Container: 服务运行容器。( 服务容器负责启动,加载,运行服务提供者。)
对于这些角色来说,其他都还好,Monitor可能猿友们前期使用会把它忽略,但是后期会发现它的作用十分明显哦,如服务的调用量越来越大,服务的容量问题就暴露出来,这个服务需要多少机器支撑?什么时候该加机器?为了解决这个问题,第一步,要将服务现在每天的调用量,响应时间,都统计出来,作为容量规划的参考指标。其次,要可以动态调整权重,在线上,将某台机器的权重一直加大,并在加大的过程中记录响应时间的变化,直到响应时间到达阀值,记录此时的访问量,再以此访问量乘以机器数反推总容量。
二、前期准备
2.1、下载Zookeeper-3.3.6 :
/s/1QUDSlb185PP0gpwbAv4H5w
下载Apache-maven-3.3.9 :
/s/1i5eXbXOxxBLOKtYkRII5Jw
下载settings.xml :
/s/1enBc069Gn5jiCt7G4VJVVQ
下载dubbo.xsd :
/s/19egh9YPcsk0JDRSIlvJJ1w
2.2、配置环境变量
2.2.1、在Zookeeper的根目录下新建一个文件夹dataTmp,我的对应路径为:D:\zookeeper-3.3.6\dataTmp
2.2.2、修改conf文件夹下的 zoo.cfg
2.2.3、在环境变量中添加ZOOKEEPER_HOME 并在path中追加;%ZOOKEEPER_HOME%/bin;%ZOOKEEPER_HOME%/conf;
2.2.4、在环境变量中添加MAVEN_HOME 并在path中追加
;%MAVEN_HOME%\bin;
2.2.5、在E盘新建文件夹tools 将dubbo.xsd 和 settings.xml 放进去,后面会用到
三、注册中心、消费者、提供者搭建实例
3.1、Zookeeper的搭建
3.2、配置生产者 (Mybatis+datasource+redis)
3.2.1、创建base项目如下:
3.2.2、maven 配置settings.xml 步骤如下:
Window-------Preferences--------Maven-------User Settings 选择GlobalSettings和UserSettings 然后Apply
3.2.3、将maven工程转换成web工程,步骤如下:
右击工程属性,找到Project Facets,选择Dynamic Web Module,3.0
点击apply。这样把这个maven工程转换成了web工程。
3.2.4、配置dubbo本地catalog文件
由于阿里已经不再维护dubbo,原dubbo xml配置地址失效,在编译时dubbo-provider.xml可能会报错,该问题可以通过如下方式解决:下载dubbo.xsd(附件中有)并在eclipse->window->perferences->XML Catalog设置
其中key与配置文件相同为/schema/dubbo/dubbo.xsd
3.2.5、修改pom.xml 如下:
<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance" xsi:schemaLocation="/POM/4.0.0/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zx</groupId><artifactId>base</artifactId><version>0.0.1-SNAPSHOT</version><packaging>war</packaging><name>base</name><url></url><description>Dubbo分布式项目平台</description><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>1.8</java.version></properties><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>1.5.1.RELEASE</version></parent><dependencies><!-- ====================================spring boot==================================== --><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>1.2.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework</groupId><artifactId>springloaded</artifactId></dependency><!-- ====================================AOP==================================== --><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId></dependency><!-- ====================================Junit单元测试==================================== --><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>4.1.4.RELEASE</version><scope>test</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.12</version></dependency><!-- ===============================Dubbo + Zookeeper==================================== --><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>2.8.4</version></dependency><dependency><groupId>com.101tec</groupId><artifactId>zkclient</artifactId><version>0.2</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.9</version><exclusions><exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion><exclusion><artifactId>slf4j-log4j12</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency><!-- ===============================mysql==================================== --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><!-- ===============================druid连接池==================================== --><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.0.21</version></dependency><!-- ===============================fastjson json转对象(JsonObject)==================================== --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.3</version></dependency><!-- ===============================dom4j读写Xml==================================== --><dependency><groupId>dom4j</groupId><artifactId>dom4j</artifactId><version>1.6.1</version></dependency><!-- ====================== javassist 对 java字节码处理 为JBoss实现动态"AOP"框架。======================== --><dependency><groupId>org.javassist</groupId><artifactId>javassist</artifactId></dependency><!-- ===============================commons==================================== --><dependency><groupId>mons</groupId><artifactId>commons-lang3</artifactId><version>3.6</version></dependency><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>1.3.2</version></dependency><dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.4.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.1</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.1.1</version></dependency><!-- ===============================jedis 缓存==================================== --><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.8.1</version></dependency><!-- ===============================mybatis==================================== --><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency><dependency><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-core</artifactId><version>1.3.2</version></dependency> </dependencies></project>
3.2.6、创建Application.java 和 SpringUtil.java
Application.java
package com.zx.base;import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;import org.springframework.boot.builder.SpringApplicationBuilder;import org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer;import org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer;import org.springframework.boot.web.support.SpringBootServletInitializer;import org.springframework.context.annotation.ImportResource;@SpringBootApplication(exclude = MybatisAutoConfiguration.class)//@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)@ImportResource(locations = "classpath*:/spring/applicationContext.xml")public class Application extends SpringBootServletInitializer implements EmbeddedServletContainerCustomizer{@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder application) {return application.sources(Application.class);}@Overridepublic void customize(ConfigurableEmbeddedServletContainer container) {//设置启动端口container.setPort(8081);}public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
SpringUtil.java
package com.zx.base.rpc.util;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.context.ApplicationEvent;/*** SpringUtil类*/public final class SpringUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;public static Object get(String name) {return applicationContext.getBean(name);}public static <T> T get(Class<T> cl) {return applicationContext.getBean(cl);}public static void sendEvent(ApplicationEvent event) {applicationContext.publishEvent(event);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringUtil.applicationContext = applicationContext;}}
3.2.7、在src/main/resources 下创建spring文件夹 创建applicationContext.xml (和刚才的Application.java中的locations对应)
创建logback-spring.xml (springboot启动时会自动加载)
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance" xmlns:context="/schema/context"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd/schema/aop/schema/aop/spring-aop.xsd"><!-- 根据环境变量加载不同配置文件 运行时请注意在环境变量中配置-DenvTarget=local--><bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><list><value>classpath:/config/system-#{systemProperties['envTarget']}.properties</value></list></property></bean><bean class="com.zx.base.rpc.util.SpringUtil" /></beans>
logback-spring.xml
<!-- spring boot 默认会加载该文件 --><configuration debug="true" scan="true" scanPeriod="5 seconds"><contextName>base</contextName><!-- 默认为local --><include resource="config/logback-${envTarget:-local}.xml" /></configuration>
3.2.8、在src/main/resources 下新建config文件夹,创建logback配置文件
与logback-spring.xml 中的config/logback-${envTarget:-local}.xml 对应
logback-local.xml
<included><property name="LOG_PATH" value="${catalina.home:-.}/logs" /><appender name="ROLLINGFILE"class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_PATH}/base.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_PATH}/base.log.%d{yyyy-MM-dd}</fileNamePattern><maxHistory>30</maxHistory></rollingPolicy><encoder><Pattern>%date{yyyy-MM-dd HH:mm:ss} %logger %level - %msg%n</Pattern></encoder></appender><appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"><encoder><Pattern>%date{yyyy-MM-dd HH:mm:ss} %logger %level - %msg%n</Pattern></encoder></appender><root level="INFO"><appender-ref ref="STDOUT" /><appender-ref ref="ROLLINGFILE" /></root></included>
system-local.properties.xml (这里配置系统参数,添加Zookeeper地址和Dubbo地址,数据源,redis地址)
#DUBBO CONFIGdubbo.registry.address=zookeeper://127.0.0.1:2181dubbo.monitor.address=dubbo://127.0.0.1:7070/com.alibaba.dubbo.monitor.MonitorService#WRITE DB CONFIGjdbc.driverClass=com.mysql.jdbc.Driverjdbc.jdbcUrl.write=jdbc:mysql://123.1.456.789:3306/livejdbc.username.write=zxjdbc.password.write=123456#READ DB CONFIGjdbc.jdbcUrl.read1=jdbc:mysql://123.1.456.789:3306/livejdbc.username.read1=zxjdbc.password.read1=123456#REDIS CONFIGredis.host=http://server1:zx@10.1.88.24:6379/0
3.2.9、配置Dubbo
在spring文件夹下创建dubbo-provider.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans" xmlns:xsi="/2001/XMLSchema-instance" xmlns:context="/schema/context" xmlns:dubbo="/schema/dubbo"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd/schema/dubbo/schema/dubbo/dubbo.xsd"><dubbo:application name="base" owner="zx"/><!-- <dubbo:provider protocol="dubbo" port="20881"/> --><dubbo:protocol name="dubbo" port="20881" /><!-- zookeeper注册中心 --><dubbo:registry address="${dubbo.registry.address}"/><!-- 配置监控的服务地址和IP --><dubbo:monitor address="${dubbo.monitor.address}" /><!-- 配置导出文件大小上限 --><dubbo:protocol payload="11000000"></dubbo:protocol></beans>
在 applicationContext.xml中 追加
<!-- dubbo配置 --><import resource="dubbo-provider.xml"/>
3.2.10、 创建包和类,下面我的结构图
com.zx.base 下放的springboot启动类
com.zx.base.api.model.manager 下放的表实体类(generator逆向生成的)
com.zx.base.api.service.manager 下放的是service层接口
com.zx.base.api.vo 下放的是分页实体类
com.zx.base.prc.dbrw 下放的是数据源相关的实体类
com.zx.base.rpc.dao.manager 下放的是表Mapper (generator逆向生成的)
com.zx.base.rpc.service.manager 下放的是Service接口实现类
com.zx.base.rpc.util 下放的是各种工具类
ITestService.java
package com.zx.base.api.service.manager;public interface ITestService {public String getName();}
Page.java
package com.zx.base.api.vo;import java.io.Serializable;import java.io.UnsupportedEncodingException;public class Page implements Serializable{private static final long serialVersionUID = -7510688937825278196L;private int showCount; // 每页显示记录数private int totalPage; // 总页数private int totalResult; // 总记录数private int currentPage; // 当前页private int currentResult; // 当前记录起始索引private int currentPageForApp; // 当前页 app用private int currentResultForApp; // 当前记录起始索引 app用private boolean entityOrField; // true:需要分页的地方,传入的参数就是Page实体;false:需要分页的地方,传入的参数所代表的实体拥有Page属性private String pageStr; // 最终页面显示的底部翻页导航,详细见:getPageStr();private String pageHtml;//一对多分页private boolean export;private String isSearch;public String getIsSearch() {return isSearch;}public void setIsSearch(String isSearch) {this.isSearch = isSearch;}public boolean isExport() {return export;}public void setExport(boolean export) {this.export = export;}public Page() {this.showCount = 15;}public int getTotalPage() {if (totalResult % showCount == 0)totalPage = totalResult / showCount;elsetotalPage = totalResult / showCount + 1;return totalPage;}public void setTotalPage(int totalPage) {this.totalPage = totalPage;}public int getTotalResult() {return totalResult;}public void setTotalResult(int totalResult) {this.totalResult = totalResult;}public int getPageNum() {return currentPage;}public int getCurrentPage() {if (currentPage <= 0)currentPage = 1;if (currentPage > getTotalPage())currentPage = getTotalPage();return currentPage;}public int getCurrentPageOfBeforeQuery() {if (currentPage <= 0)currentPage = 1;return currentPage;}public void setCurrentPage(int currentPage) {this.currentPage = currentPage;}public int getCurrentPageForApp() {if (currentPageForApp <= 0)currentPageForApp = 1;return currentPageForApp;}public void setCurrentPageForApp(int currentPageForApp) {this.currentPageForApp = currentPageForApp;}public String getPageStr() {StringBuffer sb = new StringBuffer();if (totalResult > 0) {sb.append(" <ul class=\"pagination\">\n");sb.append("<li><a>共 "+totalResult+" 条</a></li>\n");if (currentPage == 1) {/*sb.append(" <li><a>共<font color=red>" + totalResult+ "</font>条</a></li>\n");sb.append(" <li><input type=\"number\" value=\"\" id=\"toGoPage\" style=\"width:60px;text-align:center;float:left\" placeholder=\"页码\"/></li>\n");sb.append(" <li style=\"cursor:pointer;\"><a onclick=\"toTZ();\" class=\"btn btn-mini btn-success\">跳转</a></li>\n");sb.append(" <li><a>首页</a></li>\n");*/sb.append(" <li><a><i class=\"icon-double-angle-left\"></i></a></li>\n");} else {/*sb.append(" <li><a>共<font color=red>" + totalResult+ "</font>条</a></li>\n");sb.append(" <li><input type=\"number\" value=\"\" id=\"toGoPage\" style=\"width:60px;text-align:center;float:left\" placeholder=\"页码\"/></li>\n");sb.append(" <li style=\"cursor:pointer;\"><a onclick=\"toTZ();\" class=\"btn btn-mini btn-success\">跳转</a></li>\n");sb.append(" <li style=\"cursor:pointer;\"><a onclick=\"nextPage(1)\">首页</a></li>\n");*/sb.append(" <li style=\"cursor:pointer;\"><a onclick=\"nextPage("+ (currentPage - 1) + ")\"><i class=\"icon-double-angle-left\"></i></a></li>\n");}int showTag = 5; // 分页标签显示数量int startTag = 1;if (currentPage > showTag/2 + 1) {startTag = currentPage - showTag/2;startTag = startTag > totalPage-showTag ? totalPage-showTag + 1:startTag; startTag = startTag <=0 ? 1:startTag;}int endTag = startTag + showTag - 1;for (int i = startTag; i <= totalPage && i <= endTag; i++) {if (currentPage == i)sb.append("<li class=\"current active\"><a>" + i + "</a></li>\n");elsesb.append(" <li style=\"cursor:pointer;\"><a onclick=\"nextPage("+ i + ")\">" + i + "</a></li>\n");}if (currentPage == totalPage) {sb.append(" <li><a><i class=\"icon-double-angle-right\"></i></a></li>\n");} else {sb.append(" <li style=\"cursor:pointer;\"><a onclick=\"nextPage("+ (currentPage + 1) + ")\"><i class=\"icon-double-angle-right\"></i></a></li>\n");}sb.append(" <li><a>第 " + currentPage + " 页</a></li>\n");sb.append(" <li><a>共 " + totalPage + " 页</a></li>\n");sb.append(" <li><a style=\"padding-bottom: 0px;padding-top: 1px;padding-left: 0px;padding-right: 0px;margin-left: 10px;\"><input type=\"text\" value=\"\" id=\"toGoPage\" style=\"width:40px;border:0px solid #d5d5d5;text-align:center;font-size: 14px;line-height: 19px;\"></a></li>\n");sb.append(" <li style=\"cursor:pointer;\"><a onclick=\"toTZ();\" style=\"padding-bottom: 6px;margin-left: 10px;\">跳转</a></li>\n");sb.append("</ul>\n");sb.append("<script type=\"text/javascript\">\n");sb.append("function nextPage(page){");sb.append(" if(true && document.forms[0]){\n");sb.append(" var url = document.forms[0].getAttribute(\"action\");\n");sb.append(" if(url.indexOf('?')>-1){url += \"&"+ (entityOrField ? "currentPage" : "page.currentPage")+ "=\";}\n");sb.append(" else{url += \"?"+ (entityOrField ? "currentPage" : "page.currentPage")+ "=\";}\n");sb.append(" document.forms[0].action = url+page;\n");sb.append(" document.forms[0].submit();\n");sb.append(" }else{\n");sb.append(" var url = document.location+'';\n");sb.append(" if(url.indexOf('?')>-1){\n");sb.append(" if(url.indexOf('currentPage')>-1){\n");sb.append("var reg = /currentPage=\\d*/g;\n");sb.append("url = url.replace(reg,'currentPage=');\n");sb.append(" }else{\n");sb.append("url += \"&"+ (entityOrField ? "currentPage" : "page.currentPage")+ "=\";\n");sb.append(" }\n");sb.append(" }else{url += \"?"+ (entityOrField ? "currentPage" : "page.currentPage")+ "=\";}\n");sb.append(" document.location = url + page;\n");sb.append(" }\n");sb.append("}\n");sb.append("function toTZ(){");sb.append("var toPaggeVlue = document.getElementById(\"toGoPage\").value;");sb.append("if(toPaggeVlue == ''){document.getElementById(\"toGoPage\").value=1;return;}");sb.append("if(isNaN(Number(toPaggeVlue))){document.getElementById(\"toGoPage\").value=1;return;}");sb.append("nextPage(toPaggeVlue);");sb.append("}\n");sb.append("</script>\n");}try {pageStr = new String(sb.toString().getBytes("UTF-8"),"UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}return pageStr;}public void setPageStr(String pageStr) {this.pageStr = pageStr;}public String getPageHtml() {StringBuffer sb = new StringBuffer();if (totalResult > 0) {sb.append("<table class='kukaoPageTable' style=\"width: 100%;margin-top: -10px;\">\n");sb.append("<tr><td><div class=\"row\"><div class=\"col-sm-6\">\n");sb.append("<div class='kukaoPageAllCounts' style=\"padding-top: 6px;\"> 共 "+totalResult+" 条</div>\n");sb.append("</div><div class=\"col-sm-6\"> <div style=\"float: right;margin: 0;\"><ul class=\"pagination\" style=\"margin: 0;\">");if (getCurrentPage() == 1) {sb.append("<li class=\"paginate_button previous disabled\"><a onclick=\"javascript:void(0);\">上一页</a></li>\n");} else {sb.append(" <li class=\"paginate_button previous\"><a onclick=\"nextPage("+ (currentPage - 1) +")\">上一页</a></li>\n");}int showTag = 10; // 分页标签显示数量int startTag = 1;if (currentPage > showTag/2 + 1) {startTag = currentPage - showTag/2;startTag = startTag > getTotalPage()-showTag ? getTotalPage()-showTag + 1:startTag; startTag = startTag <=0 ? 1:startTag;}int endTag = startTag + showTag - 1;for (int i = startTag; i <= getTotalPage() && i <= endTag; i++) {if (currentPage == i)sb.append("<li class=\"paginate_button active\"><a>" + i + "</a></li>\n");elsesb.append(" <li class=\"paginate_button\"><a onclick=\"nextPage("+ i + ")\">" + i + "</a></li>\n");}if (currentPage == getTotalPage()) {sb.append(" <li class=\"paginate_button next\"><a onclick=\"javascript:void(0);\">下一页</a></li>\n");} else {sb.append(" <li class=\"paginate_button next\"><a onclick=\"nextPage("+(currentPage + 1)+")\">下一页</a></li>\n");}sb.append("</ul></div></div></div></td></tr></table>\n");sb.append("<script type=\"text/javascript\">\n");sb.append("function nextPage(page){");sb.append(" if(true && document.forms[0]){\n");sb.append(" var url = document.forms[0].getAttribute(\"action\");\n");sb.append(" if(url.indexOf('?')>-1){url += \"&"+ (entityOrField ? "currentPage" : "page.currentPage")+ "=\";}\n");sb.append(" else{url += \"?"+ (entityOrField ? "currentPage" : "page.currentPage")+ "=\";}\n");sb.append(" document.forms[0].action = url+page;\n");sb.append(" document.forms[0].submit();\n");sb.append(" }else{\n");sb.append(" var url = document.location+'';\n");sb.append(" if(url.indexOf('?')>-1){\n");sb.append(" if(url.indexOf('currentPage')>-1){\n");sb.append("var reg = /currentPage=\\d*/g;\n");sb.append("url = url.replace(reg,'currentPage=');\n");sb.append(" }else{\n");sb.append("url += \"&"+ (entityOrField ? "currentPage" : "page.currentPage")+ "=\";\n");sb.append(" }\n");sb.append(" }else{url += \"?"+ (entityOrField ? "currentPage" : "page.currentPage")+ "=\";}\n");sb.append(" document.location = url + page;\n");sb.append(" }\n");sb.append("}\n");sb.append("</script>\n");}try {pageHtml = new String(sb.toString().getBytes("UTF-8"),"UTF-8");} catch (UnsupportedEncodingException e) {e.printStackTrace();}return pageHtml;}public void setPageHtml(String pageHtml) {this.pageHtml = pageHtml;}public int getShowCount() {return showCount;}public void setShowCount(int showCount) {this.showCount = showCount;}public int getCurrentResult() {currentResult = (getCurrentPage() - 1) * getShowCount();if (currentResult < 0)currentResult = 0;return currentResult;}public void setCurrentResult(int currentResult) {this.currentResult = currentResult;}public int getCurrentResultForApp() {currentResultForApp = (getCurrentPageForApp() - 1) * getShowCount();if (currentResultForApp < 0)currentResultForApp = 0;return currentResultForApp;}public void setCurrentResultForApp(int currentResultForApp) {this.currentResultForApp = currentResultForApp;}public boolean isEntityOrField() {return entityOrField;}public void setEntityOrField(boolean entityOrField) {this.entityOrField = entityOrField;}}
DynamicDataSource.java
package com.zx.base.prc.dbrw;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.ThreadLocalRandom;import java.util.concurrent.atomic.AtomicLong;import java.util.concurrent.locks.Lock;import java.util.concurrent.locks.ReentrantLock;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;public class DynamicDataSource extends AbstractRoutingDataSource {private Object writeDataSource; //写数据源private List<Object> readDataSources; //多个读数据源private int readDataSourceSize; //读数据源个数private int readDataSourcePollPattern = 0; //获取读数据源方式,0:随机,1:轮询private AtomicLong counter = new AtomicLong(0);private static final Long MAX_POOL = Long.MAX_VALUE;private final Lock lock = new ReentrantLock();@Overridepublic void afterPropertiesSet() {if (this.writeDataSource == null) {throw new IllegalArgumentException("Property 'writeDataSource' is required");}setDefaultTargetDataSource(writeDataSource);Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DynamicDataSourceGlobal.WRITE.name(), writeDataSource);if (this.readDataSources == null) {readDataSourceSize = 0;} else {for(int i=0; i<readDataSources.size(); i++) {targetDataSources.put(DynamicDataSourceGlobal.READ.name() + i, readDataSources.get(i));}readDataSourceSize = readDataSources.size();}setTargetDataSources(targetDataSources);super.afterPropertiesSet();}@Overrideprotected Object determineCurrentLookupKey() {DynamicDataSourceGlobal dynamicDataSourceGlobal = DynamicDataSourceHolder.getDataSource();if(dynamicDataSourceGlobal == null|| dynamicDataSourceGlobal == DynamicDataSourceGlobal.WRITE|| readDataSourceSize <= 0) {return DynamicDataSourceGlobal.WRITE.name();}int index = 1;if(readDataSourcePollPattern == 1) {//轮询方式long currValue = counter.incrementAndGet();if((currValue + 1) >= MAX_POOL) {try {lock.lock();if((currValue + 1) >= MAX_POOL) {counter.set(0);}} finally {lock.unlock();}}index = (int) (currValue % readDataSourceSize);} else {//随机方式index = ThreadLocalRandom.current().nextInt(0, readDataSourceSize);}return dynamicDataSourceGlobal.name() + index;}public void setWriteDataSource(Object writeDataSource) {this.writeDataSource = writeDataSource;}public void setReadDataSources(List<Object> readDataSources) {this.readDataSources = readDataSources;}public void setReadDataSourcePollPattern(int readDataSourcePollPattern) {this.readDataSourcePollPattern = readDataSourcePollPattern;}}DynamicDataSourceGlobal.javapackage com.zx.base.prc.dbrw;public enum DynamicDataSourceGlobal {READ, WRITE;}
DynamicDataSourceHolder.java
package com.zx.base.prc.dbrw;public final class DynamicDataSourceHolder {private static final ThreadLocal<DynamicDataSourceGlobal> holder = new ThreadLocal<DynamicDataSourceGlobal>();private DynamicDataSourceHolder() {//}public static void putDataSource(DynamicDataSourceGlobal dataSource){holder.set(dataSource);}public static DynamicDataSourceGlobal getDataSource(){return holder.get();}public static void clearDataSource() {holder.remove();}}
DynamicDataSourceTransactionManager.java
package com.zx.base.prc.dbrw;import org.springframework.jdbc.datasource.DataSourceTransactionManager;import org.springframework.transaction.TransactionDefinition;public class DynamicDataSourceTransactionManager extends DataSourceTransactionManager {/*** 只读事务到读库,读写事务到写库* @param transaction* @param definition*/@Overrideprotected void doBegin(Object transaction, TransactionDefinition definition) {//设置数据源boolean readOnly = definition.isReadOnly();if(readOnly) {DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobal.READ);} else {DynamicDataSourceHolder.putDataSource(DynamicDataSourceGlobal.WRITE);}super.doBegin(transaction, definition);}/*** 清理本地线程的数据源* @param transaction*/@Overrideprotected void doCleanupAfterCompletion(Object transaction) {super.doCleanupAfterCompletion(transaction);DynamicDataSourceHolder.clearDataSource();}}
DynamicPlugin.java
package com.zx.base.prc.dbrw;import org.apache.ibatis.executor.Executor;import org.apache.ibatis.executor.keygen.SelectKeyGenerator;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.SqlCommandType;import org.apache.ibatis.plugin.*;import org.apache.ibatis.session.ResultHandler;import org.apache.ibatis.session.RowBounds;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.transaction.support.TransactionSynchronizationManager;import java.util.Locale;import java.util.Map;import java.util.Properties;import java.util.concurrent.ConcurrentHashMap;@Intercepts({@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class }),@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class,ResultHandler.class }) })public class DynamicPlugin implements Interceptor {protected static final Logger logger = LoggerFactory.getLogger(DynamicPlugin.class);private static final String REGEX = ".*insert\\u0020.*|.*delete\\u0020.*|.*update\\u0020.*";private static final Map<String, DynamicDataSourceGlobal> cacheMap = new ConcurrentHashMap<>();@Overridepublic Object intercept(Invocation invocation) throws Throwable {boolean synchronizationActive = TransactionSynchronizationManager.isSynchronizationActive();if(!synchronizationActive) {Object[] objects = invocation.getArgs();MappedStatement ms = (MappedStatement) objects[0];DynamicDataSourceGlobal dynamicDataSourceGlobal = null;if((dynamicDataSourceGlobal = cacheMap.get(ms.getId())) == null) {//读方法if(ms.getSqlCommandType().equals(SqlCommandType.SELECT)) {//!selectKey 为自增id查询主键(SELECT LAST_INSERT_ID() )方法,使用主库if(ms.getId().contains(SelectKeyGenerator.SELECT_KEY_SUFFIX)) {dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;} else {BoundSql boundSql = ms.getSqlSource().getBoundSql(objects[1]);String sql = boundSql.getSql().toLowerCase(Locale.CHINA).replaceAll("[\\t\\n\\r]", " ");if(sql.matches(REGEX)) {dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;} else {dynamicDataSourceGlobal = DynamicDataSourceGlobal.READ;}}}else{dynamicDataSourceGlobal = DynamicDataSourceGlobal.WRITE;}logger.warn("设置方法[{}] use [{}] Strategy, SqlCommandType [{}]..", ms.getId(), dynamicDataSourceGlobal.name(), ms.getSqlCommandType().name());cacheMap.put(ms.getId(), dynamicDataSourceGlobal);}DynamicDataSourceHolder.putDataSource(dynamicDataSourceGlobal);}return invocation.proceed();}@Overridepublic Object plugin(Object target) {if (target instanceof Executor) {return Plugin.wrap(target, this);} else {return target;}}@Overridepublic void setProperties(Properties properties) {//}}
TestServiceImpl.java
package com.zx.base.rpc.service.manager;import javax.annotation.Resource;import org.springframework.stereotype.Service;import com.zx.base.api.service.manager.ITestService;import com.zx.base.rpc.dao.manager.TeacherMapper;@Servicepublic class TestServiceImpl implements ITestService{@ResourceTeacherMapper teacherMapper;@Overridepublic String getName() {return "zhouxuan";}}
PagePlugin.java
package com.zx.base.rpc.util;import java.lang.reflect.Field;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.List;import java.util.Properties;import javax.xml.bind.PropertyException;import org.apache.ibatis.executor.ErrorContext;import org.apache.ibatis.executor.ExecutorException;import org.apache.ibatis.executor.statement.BaseStatementHandler;import org.apache.ibatis.executor.statement.RoutingStatementHandler;import org.apache.ibatis.executor.statement.StatementHandler;import org.apache.ibatis.mapping.BoundSql;import org.apache.ibatis.mapping.MappedStatement;import org.apache.ibatis.mapping.ParameterMapping;import org.apache.ibatis.mapping.ParameterMode;import org.apache.ibatis.plugin.Interceptor;import org.apache.ibatis.plugin.Intercepts;import org.apache.ibatis.plugin.Invocation;import org.apache.ibatis.plugin.Plugin;import org.apache.ibatis.plugin.Signature;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.reflection.property.PropertyTokenizer;import org.apache.ibatis.scripting.xmltags.ForEachSqlNode;import org.apache.ibatis.session.Configuration;import org.apache.ibatis.type.TypeHandler;import org.apache.ibatis.type.TypeHandlerRegistry;import com.zx.base.api.vo.Page;@Intercepts({ @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class }) })public class PagePlugin implements Interceptor {private static String dialect = ""; // 数据库方言private static String pageSqlId = ""; // mapper.xml中需要拦截的ID(正则匹配)public Object intercept(Invocation ivk) throws Throwable {if (ivk.getTarget() instanceof RoutingStatementHandler) {RoutingStatementHandler statementHandler = (RoutingStatementHandler) ivk.getTarget();BaseStatementHandler delegate = (BaseStatementHandler) ReflectHelper.getValueByFieldName(statementHandler, "delegate");MappedStatement mappedStatement = (MappedStatement) ReflectHelper.getValueByFieldName(delegate, "mappedStatement");if (mappedStatement.getId().matches(pageSqlId)) { // 拦截需要分页的SQLBoundSql boundSql = delegate.getBoundSql();Object parameterObject = boundSql.getParameterObject();// 分页SQL<select>中parameterType属性对应的实体参数,即Mapper接口中执行分页方法的参数,该参数不得为空if (parameterObject == null) {throw new NullPointerException("parameterObject尚未实例化!");} else {Connection connection = (Connection) ivk.getArgs()[0];String sql = boundSql.getSql();// String countSql = "select count(0) from (" + sql+// ") as tmp_count"; //记录统计String countSql = "select count(0) from (" + sql+ ") tmp_count"; // 记录统计 == oracle 加 as 报错(SQL// command not properly ended)PreparedStatement countStmt = connection.prepareStatement(countSql);BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,boundSql.getParameterMappings(), parameterObject);setParameters(countStmt, mappedStatement, countBS,parameterObject);ResultSet rs = countStmt.executeQuery();int count = 0;if (rs.next()) {count = rs.getInt(1);}rs.close();countStmt.close();Page page = null;if (parameterObject instanceof Page) { // 参数就是Page实体page = (Page) parameterObject;page.setEntityOrField(true); // 见com.jalan.entity.Page.entityOrField// 注释page.setTotalResult(count);} else { // 参数为某个实体,该实体拥有Page属性Field pageField = ReflectHelper.getFieldByFieldName(parameterObject, "page");if (pageField != null) {page = (Page) ReflectHelper.getValueByFieldName(parameterObject, "page");if (page == null)page = new Page();page.setEntityOrField(false); // 见com.jalan.entity.Page.entityOrField// 注释page.setTotalResult(count);ReflectHelper.setValueByFieldName(parameterObject,"page", page); // 通过反射,对实体对象设置分页对象} else {throw new NoSuchFieldException(parameterObject.getClass().getName() + "不存在 page 属性!");}}if( !page.isExport()){String pageSql = generatePageSql(sql, page);ReflectHelper.setValueByFieldName(boundSql, "sql", pageSql); // 将分页sql语句反射回BoundSql.}}}}return ivk.proceed();}/*** 对SQL参数(?)设值,参考org.apache.ibatis.executor.parameter.* DefaultParameterHandler** @param ps* @param mappedStatement* @param boundSql* @param parameterObject* @throws SQLException*/@SuppressWarnings("unchecked")private void setParameters(PreparedStatement ps,MappedStatement mappedStatement, BoundSql boundSql,Object parameterObject) throws SQLException {ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();if (parameterMappings != null) {Configuration configuration = mappedStatement.getConfiguration();TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();MetaObject metaObject = parameterObject == null ? null: configuration.newMetaObject(parameterObject);for (int i = 0; i < parameterMappings.size(); i++) {ParameterMapping parameterMapping = parameterMappings.get(i);if (parameterMapping.getMode() != ParameterMode.OUT) {Object value;String propertyName = parameterMapping.getProperty();PropertyTokenizer prop = new PropertyTokenizer(propertyName);if (parameterObject == null) {value = null;} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {value = parameterObject;} else if (boundSql.hasAdditionalParameter(propertyName)) {value = boundSql.getAdditionalParameter(propertyName);} else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX)&& boundSql.hasAdditionalParameter(prop.getName())) {value = boundSql.getAdditionalParameter(prop.getName());if (value != null) {value = configuration.newMetaObject(value).getValue(propertyName.substring(prop.getName().length()));}} else {value = metaObject == null ? null : metaObject.getValue(propertyName);}@SuppressWarnings("rawtypes")TypeHandler typeHandler = parameterMapping.getTypeHandler();if (typeHandler == null) {throw new ExecutorException("There was no TypeHandler found for parameter "+ propertyName + " of statement "+ mappedStatement.getId());}typeHandler.setParameter(ps, i + 1, value,parameterMapping.getJdbcType());}}}}/*** 根据数据库方言,生成特定的分页sql** @param sql* @param page* @return*/private String generatePageSql(String sql, Page page) {if (page != null && Tools.notEmpty(dialect)) {StringBuffer pageSql = new StringBuffer();if ("mysql".equals(dialect)) {pageSql.append(sql);pageSql.append(" limit " + page.getCurrentResult() + ","+ page.getShowCount());} else if ("oracle".equals(dialect)) {pageSql.append("select * from (select tmp_tb.*,ROWNUM row_id from (");pageSql.append(sql);// pageSql.append(") as tmp_tb where ROWNUM<=");pageSql.append(") tmp_tb where ROWNUM<=");pageSql.append(page.getCurrentResult() + page.getShowCount());pageSql.append(") where row_id>");pageSql.append(page.getCurrentResult());}return pageSql.toString();} else {return sql;}}public Object plugin(Object arg0) {return Plugin.wrap(arg0, this);}public void setProperties(Properties p) {dialect = p.getProperty("dialect");if (Tools.isEmpty(dialect)) {try {throw new PropertyException("dialect property is not found!");} catch (PropertyException e) {e.printStackTrace();}}pageSqlId = p.getProperty("pageSqlId");if (Tools.isEmpty(pageSqlId)) {try {throw new PropertyException("pageSqlId property is not found!");} catch (PropertyException e) {e.printStackTrace();}}}}
ReflectHelper.java
package com.zx.base.rpc.util;import java.lang.reflect.Field;/*** @author Administrator*反射工具*/public class ReflectHelper {/*** 获取obj对象fieldName的Field* @param obj* @param fieldName* @return*/public static Field getFieldByFieldName(Object obj, String fieldName) {for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()) {try {return superClass.getDeclaredField(fieldName);} catch (NoSuchFieldException e) {}}return null;}/*** 获取obj对象fieldName的属性值* @param obj* @param fieldName* @return* @throws SecurityException* @throws NoSuchFieldException* @throws IllegalArgumentException* @throws IllegalAccessException*/public static Object getValueByFieldName(Object obj, String fieldName)throws SecurityException, NoSuchFieldException,IllegalArgumentException, IllegalAccessException {Field field = getFieldByFieldName(obj, fieldName);Object value = null;if(field!=null){if (field.isAccessible()) {value = field.get(obj);} else {field.setAccessible(true);value = field.get(obj);field.setAccessible(false);}}return value;}/*** 设置obj对象fieldName的属性值* @param obj* @param fieldName* @param value* @throws SecurityException* @throws NoSuchFieldException* @throws IllegalArgumentException* @throws IllegalAccessException*/public static void setValueByFieldName(Object obj, String fieldName,Object value) throws SecurityException, NoSuchFieldException,IllegalArgumentException, IllegalAccessException {Field field = obj.getClass().getDeclaredField(fieldName);if (field.isAccessible()) {field.set(obj, value);} else {field.setAccessible(true);field.set(obj, value);field.setAccessible(false);}}}
Tools.java
package com.zx.base.rpc.util;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Random;public class Tools {/*** 随机生成六位数验证码** @return*/public static int getRandomNum() {Random r = new Random();return r.nextInt(900000) + 100000;// (Math.random()*(999999-100000)+100000)}/*** 随机生成主键** @return*/public static String getRandomKey() {long part1 = System.currentTimeMillis();String part2 = String.format("%07d", new Random().nextInt(10000000));StringBuffer str = new StringBuffer().append(part1).append(part2);return str.toString();}/*** 检测字符串是否不为空(null,"","null")** @param s* @return 不为空则返回true,否则返回false*/public static boolean notEmpty(String s) {return s != null && !"".equals(s) && !"null".equals(s);}/*** 检测字符串是否为空(null,"","null")** @param s* @return 为空则返回true,不否则返回false*/public static boolean isEmpty(String s) {return s == null || "".equals(s) || "null".equals(s);}/*** 字符串转换为字符串数组** @param str* 字符串* @param splitRegex* 分隔符* @return*/public static String[] str2StrArray(String str, String splitRegex) {if (isEmpty(str)) {return null;}System.out.println(splitRegex);return str.split(splitRegex);}/*** 用默认的分隔符(,)将字符串转换为字符串数组** @param str* 字符串* @return*/public static String[] str2StrArray(String str) {return str2StrArray(str, ",\\s*");}/*** 按照yyyy-MM-dd HH:mm:ss的格式,日期转字符串** @param date* @return yyyy-MM-dd HH:mm:ss*/public static String date2Str(Date date) {return date2Str(date, "yyyy-MM-dd HH:mm:ss");}/*** 按照yyyy-MM-dd HH:mm:ss的格式,字符串转日期** @param date* @return*/public static Date str2Date(String date) {if (notEmpty(date)) {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");try {return sdf.parse(date);} catch (ParseException e) {e.printStackTrace();}return new Date();} else {return null;}}/*** 按照参数format的格式,日期转字符串** @param date* @param format* @return*/public static String date2Str(Date date, String format) {if (date != null) {SimpleDateFormat sdf = new SimpleDateFormat(format);return sdf.format(date);} else {return "";}}/*** 把时间根据时、分、秒转换为时间段** @param StrDate*/public static String getTimes(String StrDate) {String resultTimes = "";SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");java.util.Date now;try {now = new Date();java.util.Date date = df.parse(StrDate);long times = now.getTime() - date.getTime();long day = times / (24 * 60 * 60 * 1000);long hour = (times / (60 * 60 * 1000) - day * 24);long min = ((times / (60 * 1000)) - day * 24 * 60 - hour * 60);long sec = (times / 1000 - day * 24 * 60 * 60 - hour * 60 * 60 - min * 60);StringBuffer sb = new StringBuffer();// sb.append("发表于:");if (hour > 0) {sb.append(hour + "小时前");} else if (min > 0) {sb.append(min + "分钟前");} else {sb.append(sec + "秒前");}resultTimes = sb.toString();} catch (ParseException e) {e.printStackTrace();}return resultTimes;}public static boolean isNum(String strin) {String s = strin.replaceAll("[0-9;]+", "");if (s.equals("")) {return true;} else {return false;}}public static int getWordCount(String s) {s = s.replaceAll("[^\\x00-\\xff]", "**");int length = s.length();return length;}/*** 按字节长度截取字符串** @param str* 将要截取的字符串参数* @param toCount* 截取的字节长度* @param more* 字符串末尾补上的字符串* @return 返回截取后的字符串*/@SuppressWarnings("static-access")public static String substring(String str, int toCount, String more) {int reInt = 0;String reStr = "";if (str == null)return "";char[] tempChar = str.toCharArray();for (int kk = 0; (kk < tempChar.length && toCount > reInt); kk++) {String s1 = str.valueOf(tempChar[kk]);byte[] b = s1.getBytes();reInt += b.length;reStr += tempChar[kk];}if (toCount == reInt || (toCount == reInt - 1))reStr += more;return reStr;}/*** 判断两个字符串是否相等** @param one* @param two* @return*/public static boolean isEquals(String one, String two) {if (one != null && two != null) {return one.trim().equals(two.trim());} else if (one == null && two == null) {return true;} else if (one == null && two.trim().length() == 0) {return true;} else if (two == null && one.trim().length() == 0) {return true;} else {return false;}}/*** @Title: getFormatDate* @param @param format* @param @return* @return String* @throws*/public static String getFormatDate(String format) {SimpleDateFormat date = new SimpleDateFormat(format);return date.format(new Date());}}
3.2.11、集成mybatis
在pom.xml文件中追加 mybatis-generator配置
<build><finalName>base</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!-- mybatis代码自动生成工具,执行命令 mybatis-generator:generate --><plugin><groupId>org.mybatis.generator</groupId><artifactId>mybatis-generator-maven-plugin</artifactId><version>1.3.2</version><configuration><configurationFile>src/main/resources/mybatis/generatorConfig.xml</configurationFile><verbose>true</verbose><overwrite>true</overwrite></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><configuration><skip>true</skip></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>${java.version}</source><target>${java.version}</target><compilerArguments> <verbose /> <bootclasspath>${java.home}\lib\rt.jar;${java.home}\lib\jce.jar</bootclasspath> </compilerArguments></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><configuration><finalName>base</finalName><appendAssemblyId>true</appendAssemblyId><descriptors><descriptor>src/main/resources/assembly/api.xml</descriptor></descriptors></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin></plugins><resources><resource> <directory>src/main/resources</directory> <includes> <include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.tld</include><include>**/*.json</include> </includes> <filtering>false</filtering></resource><resource> <directory>src/main/java</directory> <includes><include>**/*.properties</include> <include>**/*.xml</include> <include>**/*.tld</include><include>**/*.p12</include></includes> <filtering>false</filtering> </resource> </resources></build>
3.2.12、创建mybatis 配置文件
api.xml
<assembly><id>api</id><formats><format>jar</format></formats><baseDirectory>com\zx\base</baseDirectory><fileSets><fileSet><directory>${project.basedir}\target\base\WEB-INF\classes\com\zx\base\api</directory> <excludes><exclude>${project.basedir}\target\base\WEB-INF\classes\com\zx\base\api\service\manager\TestServiceImpl.class</exclude></excludes><outputDirectory>/api</outputDirectory></fileSet></fileSets></assembly>
generatorConfig.xml
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE generatorConfiguration PUBLIC "-////DTD MyBatis Generator Configuration 1.0//EN" "/dtd/mybatis-generator-config_1_0.dtd" ><generatorConfiguration><!-- 数据库驱动 --><classPathEntry location="D:/apache-maven-3.3.9/repository/mysql/mysql-connector-java/5.1.40/mysql-connector-java-5.1.40.jar" /><context id="DB2Tables" targetRuntime="MyBatis3"><property name="javaFileEncoding" value="UTF-8"/><commentGenerator type="org.mybatis.generator.internal.CustomeCommentGenerator"><property name="javaFileEncoding" value="UTF-8"/><!-- 是否去除自动生成的注释 true:是 : false:否 --><property name="suppressAllComments" value="false" /><property name="suppressDate" value="true" /></commentGenerator><!--数据库链接URL,用户名、密码 --><jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://123.1.456.789:3306/live" userId="kuakao" password="123456"></jdbcConnection><javaTypeResolver><property name="forceBigDecimals" value="false" /></javaTypeResolver><javaModelGenerator targetPackage="com.zx.base.api.model.manager" targetProject="./src/main/java"> <property name="enableSubPackages" value="true" /> <!-- 从数据库返回的值被清理前后的空格 --> <property name="trimStrings" value="true" /> </javaModelGenerator> <!--对应的mapper.xml文件 --> <sqlMapGenerator targetPackage="manager" targetProject="./src/main/resources/mybatis"> <property name="enableSubPackages" value="true" /> </sqlMapGenerator> <!-- 对应的Mapper接口类文件 --> <javaClientGenerator type="XMLMAPPER"targetPackage="com.zx.base.rpc.dao.manager" targetProject="./src/main/java"> <property name="enableSubPackages" value="true" /> </javaClientGenerator> <!-- 要生成哪些表--><table tableName="sys_user" domainObjectName="SysUser" enableCountByExample="true" enableUpdateByExample="true" enableDeleteByExample="true" enableSelectByExample="true" selectByExampleQueryId="true"></table></context></generatorConfiguration>
mybatis-config-mappings.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-////DTD Config 3.0//EN" "/dtd/mybatis-3-config.dtd"><configuration><settings><!-- 这个配置使全局的映射器启用或禁用缓存 --><setting name="cacheEnabled" value="true" /><!-- 全局启用或禁用延迟加载。当禁用时,所有关联对象都会即时加载 --><setting name="lazyLoadingEnabled" value="true" /><!-- 当启用时,有延迟加载属性的对象在被调用时将会完全加载任意属性。否则,每种属性将会按需要加载 --><setting name="aggressiveLazyLoading" value="true" /><!-- 允许或不允许多种结果集从一个单独的语句中返回(需要适合的驱动) --><setting name="multipleResultSetsEnabled" value="true" /><!-- 使用列标签代替列名。不同的驱动在这方便表现不同。参考驱动文档或充分测试两种方法来决定所使用的驱动 --><setting name="useColumnLabel" value="true" /><!-- 允许JDBC支持生成的键。需要适合的驱动。如果设置为true则这个设置强制生成的键被使用,尽管一些驱动拒绝兼容但仍然有效(比如Derby) --><setting name="useGeneratedKeys" value="false" /><!-- 指定MyBatis如何自动映射列到字段/属性。PARTIAL只会自动映射简单,没有嵌套的结果。FULL会自动映射任意复杂的结果(嵌套的或其他情况) --><setting name="autoMappingBehavior" value="FULL" /><!-- 配置默认的执行器。SIMPLE执行器没有什么特别之处。REUSE执行器重用预处理语句。BATCH执行器重用语句和批量更新 --><setting name="defaultExecutorType" value="SIMPLE" /><!-- 设置超时时间,它决定驱动等待一个数据库响应的时间 --><setting name="defaultStatementTimeout" value="25000" /><setting name="logImpl" value="STDOUT_LOGGING" /></settings><typeAliases><package name="com.zx.base.api.model.manager" /></typeAliases><plugins><plugin interceptor="com.zx.base.rpc.util.PagePlugin"><property name="dialect" value="mysql" /><property name="pageSqlId" value=".*listPage*.*" /></plugin><plugin interceptor="com.zx.base.prc.dbrw.DynamicPlugin"></plugin></plugins></configuration>
3.2.13、配置datasource 和 redis
datasource.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans" xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context" xmlns:tx="/schema/tx"xmlns:aop="/schema/aop"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/tx/schema/tx/spring-tx.xsd/schema/aop/schema/aop/spring-aop.xsd/schema/context/schema/context/spring-context.xsd"><bean id="stat-filter" class="com.alibaba.druid.filter.stat.StatFilter"><property name="slowSqlMillis" value="10000" /><property name="logSlowSql" value="true" /></bean><bean id="abstractDataSource" abstract="true" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close"><!-- 配置初始化大小、最小、最大 --><property name="initialSize" value="50" /><property name="minIdle" value="50" /><property name="maxActive" value="500" /><!-- 配置获取连接等待超时的时间 --><property name="maxWait" value="60000" /><!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 --><property name="timeBetweenEvictionRunsMillis" value="60000" /><!-- 配置一个连接在池中最小生存的时间,单位是毫秒 --><property name="minEvictableIdleTimeMillis" value="300000" /><property name="validationQuery" value="SELECT 'x'" /><property name="testWhileIdle" value="true" /><property name="testOnBorrow" value="true" /><property name="testOnReturn" value="true" /><!-- 打开PSCache,并且指定每个连接上PSCache的大小 --><property name="poolPreparedStatements" value="true" /><property name="maxPoolPreparedStatementPerConnectionSize" value="20" /><!-- 配置监控统计拦截的filters --><property name="filters" value="stat" /><property name="connectionProperties" value="druid.stat.mergeSql=true" /><property name="useGlobalDataSourceStat" value="true" /></bean><bean id="dataSourceWrite" parent="abstractDataSource"><property name="driverClassName" value="${jdbc.driverClass}" /><property name="url" value="${jdbc.jdbcUrl.write}?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull" /><property name="username" value="${jdbc.username.write}" /><property name="password" value="${jdbc.password.write}" /></bean><bean id="dataSourceRead" parent="abstractDataSource"><property name="driverClassName" value="${jdbc.driverClass}" /><property name="url" value="${jdbc.jdbcUrl.read1}?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&zeroDateTimeBehavior=convertToNull" /><property name="username" value="${jdbc.username.read1}" /><property name="password" value="${jdbc.password.read1}" /></bean><bean id="dataSource" class="com.zx.base.prc.dbrw.DynamicDataSource" primary="true"><property name="writeDataSource" ref="dataSourceWrite" /><property name="readDataSources"><list><ref bean="dataSourceRead" /></list></property></bean><bean id="zxSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" primary="true"><property name="dataSource" ref="dataSource" /><property name="configLocation" value="classpath:/mybatis/mybatis-config-mappings.xml" /><property name="mapperLocations"><array><value>classpath:/mybatis/manager/*Mapper.xml</value></array></property></bean><bean id="zxmapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer" primary="true"><property name="basePackage" value="com.zx.base.rpc.dao.manager" /><property name="sqlSessionFactoryBeanName" value="zxSessionFactory" /></bean><!-- zx事务配置 --><bean id="zxTxManager"class="com.zx.base.prc.dbrw.DynamicDataSourceTransactionManager" primary="true"><property name="dataSource" ref="dataSource" /></bean><tx:advice id="zxTxAdvice" transaction-manager="zxTxManager"><tx:attributes><tx:method name="query*" read-only="true"/><tx:method name="select*" read-only="true"/><tx:method name="list*" read-only="true"/><tx:method name="find*" read-only="true"/><tx:method name="load*" read-only="true"/><tx:method name="search*" read-only="true"/><tx:method name="get*" read-only="true"/><tx:method name="count*" read-only="true"/><tx:method name="*" propagation="REQUIRED" rollback-for="Throwable"/></tx:attributes></tx:advice><aop:config><aop:pointcut id="zxPointCut"expression="(execution (* com.zx.base.rpc.service.manager.*ServiceImpl.*(..)))" /><aop:advisor advice-ref="zxTxAdvice" pointcut-ref="zxPointCut" /></aop:config><tx:annotation-driven transaction-manager="zxTxManager" /></beans>
redis.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd"><bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool"> <constructor-arg index="0" ref="jedisPoolConfig"/> <constructor-arg index="1"> <list> <bean name="master" class="redis.clients.jedis.JedisShardInfo"> <constructor-arg index="0" value="${redis.host}"/> </bean> </list> </constructor-arg> </bean> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"><!-- 最大连接数 --><property name="maxTotal" value="500" /><!-- 最小空闲连接数 --><property name="minIdle" value="10" /><!-- 最大空闲连接数 --><property name="maxIdle" value="100" /><!-- 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 --><property name="numTestsPerEvictionRun" value="250"/><property name="timeBetweenEvictionRunsMillis" value="30000" /><property name="minEvictableIdleTimeMillis" value="-1" /><property name="softMinEvictableIdleTimeMillis" value="10000" /><property name="maxWaitMillis" value="10000"/><property name="testOnBorrow" value="true" /><property name="testWhileIdle" value="true"/><property name="testOnReturn" value="true"/><property name="jmxEnabled" value="true"/><property name="jmxNamePrefix" value="jjk"/><property name="blockWhenExhausted" value="false"/></bean></beans>
在 applicationContext.xml中 追加
<!-- 数据源配置 --><import resource="datasource.xml"/><!-- redis配置 --><import resource="redis.xml"/>
3.2.14、将接口ITestService 发布
在dubbo-provider.xml中 添加
<dubbo:service interface="com.zx.base.api.service.manager.ITestService" ref="testServiceImpl" protocol="dubbo" timeout="1200000" />
3.2.15、启动base
右键Application.java ------run as ------Java Application
看到如下信息说明生产者启动成功
3.2.16、查看dubbo是否注册了 刚刚的 ITestService
进入zookeeper安装目录 /bin 文件夹下 点击zkCli
输入 ls /dubbo
可以看到已经注册成功了
至此生产者项目已经搭建成功
3.3、配置消费者
3.3.1、新建Maven项目 consumer 步骤和之前的base一样
3.3.2、修改pom.xml文件
<projectxmlns="/POM/4.0.0"xmlns:xsi="/2001/XMLSchema-instance"xsi:schemaLocation="/POM/4.0.0/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.zx</groupId><artifactId>consumer</artifactId><packaging>war</packaging><version>0.0.1-SNAPSHOT</version><name>consumer Maven Webapp</name><url></url><properties><!-- jar 版本设置 --><spring.version>4.1.4.RELEASE</spring.version><junit.version>4.11</junit.version><log4j.version>1.2.17</log4j.version><slf4j.version>1.7.5</slf4j.version><poi.version>3.10-FINAL</poi.version><commons-lang3.version>3.1</commons-lang3.version><commons-io.version>2.4</commons-io.version><commons-codec.version>1.8</commons-codec.version><commons-fileupload.version>1.3.1</commons-fileupload.version><commons-beanutils.version>1.8.3</commons-beanutils.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>com.zx</groupId><artifactId>base</artifactId><version>1.0</version><scope>system</scope><type>jar</type><systemPath>${project.basedir}/src/main/webapp/WEB-INF/lib/base-api.jar</systemPath></dependency><dependency><groupId>javax.websocket</groupId><artifactId>javax.websocket-api</artifactId><version>1.0</version><scope>provided</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-websocket</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-messaging</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-orm</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>${spring.version}</version></dependency><!-- /artifact/mons/commons-email --><dependency><groupId>mons</groupId><artifactId>commons-email</artifactId><version>1.2</version></dependency><dependency><groupId>commons-codec</groupId><artifactId>commons-codec</artifactId><version>1.7</version><scope>compile</scope></dependency><!-- ################### json解释 ################ --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>2.7.1</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>2.7.2</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.5.1</version></dependency><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-core-lgpl</artifactId><version>1.9.6</version></dependency><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-core-asl</artifactId><version>1.8.5</version></dependency><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-asl</artifactId><version>1.9.2</version></dependency><dependency><groupId>org.codehaus.jackson</groupId><artifactId>jackson-mapper-lgpl</artifactId><version>1.9.6</version></dependency><!-- ############################################## --><!-- javax提供的annotation --><dependency><groupId>javax.inject</groupId><artifactId>javax.inject</artifactId><version>1</version></dependency><!-- 提供对c标签的支持 --><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!-- junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>${junit.version}</version></dependency><!-- aop代理 --><dependency><groupId>asm</groupId><artifactId>asm</artifactId><version>3.3.1</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version> 1.6.11</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aop</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-aspects</artifactId><version>${spring.version}</version></dependency><!-- log4j --><dependency><groupId>log4j</groupId><artifactId>log4j</artifactId><version>${log4j.version}</version></dependency><dependency><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId><version>1.1.2</version></dependency><dependency><groupId>commons-validator</groupId><artifactId>commons-validator</artifactId><version>1.5.0</version></dependency><!-- GENERAL UTILS begin <dependency> <groupId>mons</groupId> <artifactId>commons-lang3</artifactId> <version>${commons-lang3.version}</version></dependency> <dependency> <groupId>commons-codec</groupId> <artifactId>commons-codec</artifactId> <version>${commons-codec.version}</version></dependency> --><dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>${commons-io.version}</version></dependency><dependency><groupId>commons-fileupload</groupId><artifactId>commons-fileupload</artifactId><version>${commons-fileupload.version}</version></dependency><dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>${commons-beanutils.version}</version><exclusions><exclusion><groupId>commons-logging</groupId><artifactId>commons-logging</artifactId></exclusion></exclusions></dependency><dependency><groupId>commons-httpclient</groupId><artifactId>commons-httpclient</artifactId><version>3.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpmime</artifactId><version>4.5.1</version></dependency><!-- http client --><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.4.1</version></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpcore</artifactId><version>4.4.1</version></dependency><!-- servlet api --><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.1</version><scope>provided</scope></dependency><!--json-lib --><dependency><groupId>net.sf.ezmorph</groupId><artifactId>ezmorph</artifactId><version>1.0.6</version></dependency><dependency><groupId>net.sf.morph</groupId><artifactId>morph</artifactId><version>1.1.1</version></dependency><dependency><groupId>net.sf.json-lib</groupId><artifactId>json-lib</artifactId><version>2.4</version><classifier>jdk15</classifier></dependency><dependency><groupId>org.fusesource</groupId><artifactId>sigar</artifactId><version>1.6.4</version></dependency><!-- <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <scope>provided</scope></dependency> --><dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version></dependency><dependency><groupId>commons-lang</groupId><artifactId>commons-lang</artifactId><version>2.6</version></dependency><!-- <dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.2</version></dependency> --><!-- logback --><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-core</artifactId><version>1.1.6</version></dependency><dependency><groupId>ch.qos.logback</groupId><artifactId>logback-classic</artifactId><version>1.1.6</version></dependency><dependency><groupId>org.logback-extensions</groupId><artifactId>logback-ext-spring</artifactId><version>0.1.2</version></dependency><dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>2.8.1</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.3</version></dependency><dependency><groupId>javassist</groupId><artifactId>javassist</artifactId><version>3.12.1.GA</version></dependency><!-- zookeeper --><dependency><groupId>com.101tec</groupId><artifactId>zkclient</artifactId><version>0.2</version></dependency><dependency><groupId>org.apache.zookeeper</groupId><artifactId>zookeeper</artifactId><version>3.4.8</version><exclusions><exclusion><groupId>log4j</groupId><artifactId>log4j</artifactId></exclusion><exclusion><artifactId>slf4j-log4j12</artifactId><groupId>org.slf4j</groupId></exclusion></exclusions></dependency><!-- dubbo --><dependency><groupId>com.alibaba</groupId><artifactId>dubbo-rpc-rest</artifactId><version>2.8.4</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>dubbo-rpc-webservice</artifactId><version>2.8.4</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>dubbo</artifactId><version>2.8.4</version></dependency><!-- /artifact/com.google.code.gson/gson --><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.7</version></dependency><!-- /artifact/javax.validation/validation-api --><dependency><groupId>javax.validation</groupId><artifactId>validation-api</artifactId><version>1.0.0.GA</version></dependency><dependency><groupId>org.springframework.data</groupId><artifactId>spring-data-redis</artifactId><version>1.5.2.RELEASE</version></dependency><dependency><groupId>org.springframework.session</groupId><artifactId>spring-session</artifactId><version>1.0.2.RELEASE</version></dependency></dependencies><build><finalName>consumer</finalName><plugins><!-- Plugin to run and test through maven --><plugin><groupId>org.eclipse.jetty</groupId><artifactId>jetty-maven-plugin</artifactId><version>9.3.6.v1106</version><configuration><systemProperties></systemProperties><scanIntervalSeconds>0</scanIntervalSeconds><stopKey>foo</stopKey><stopPort>9991</stopPort><httpConnector><port>8080</port></httpConnector><webAppConfig><contextPath>/</contextPath></webAppConfig></configuration></plugin><!-- Ensures we are compiling at 1.8 level --><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.3.2</version><configuration><source>${java.version}</source><target>${java.version}</target></configuration></plugin></plugins></build></project>
3.3.3、右键base项目 Run As ----Maven install
将生成的base-api.jar 复制到 consumer的 src/main/webapp/WEB-INF/lib下
3.3.4、搭建SpringMVC ,详情请见 使用Maven搭建SpringMVC
下面是我的结构图
com.zx.controller包 下放的是Controller层
com.zx.util包 下放的是工具类
web.xml
<?xml version="1.0" encoding="UTF-8"?>
org.springframework.web.context.ContextLoaderListener
org.springframework.web.util.IntrospectorCleanupListener
contextConfigLocation
classpath:/spring/applicationContext*.xml
<listener><listener-class>ch.qos.logback.ext.spring.web.LogbackConfigListener</listener-class></listener><context-param><param-name>logbackConfigLocation</param-name><param-value>classpath:/config/logback.xml</param-value></context-param><servlet><servlet-name>spring</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class></servlet><servlet-mapping><servlet-name>spring</servlet-name><url-pattern>/</url-pattern></servlet-mapping></web-app>
spring-servlet.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance" xmlns:context="/schema/context"xmlns:tx="/schema/tx" xmlns:mvc="/schema/mvc"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd/schema/tx/schema/tx/spring-tx.xsd/schema/mvc/schema/mvc/spring-mvc.xsd"><context:annotation-config /><!-- 配置扫描的包 --><context:component-scan base-package="com.zx.**" /><!-- 注册HandlerMapper、HandlerAdapter两个映射类 --><mvc:annotation-driven /><!-- 访问静态资源 --><mvc:default-servlet-handler /><!-- 视图解析器 --><beanclass="org.springframework.web.servlet.view.InternalResourceViewResolver"><property name="prefix" value="/WEB-INF/views/"></property><property name="suffix" value=".jsp"></property></bean></beans>applicationContext.xml<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance" xmlns:context="/schema/context"xmlns:aop="/schema/aop" xmlns:task="/schema/task"xmlns:mvc="/schema/mvc"xmlns:beans="/schema/beans"xmlns:util="/schema/util"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd/schema/aop/schema/aop/spring-aop.xsd/schema/task/schema/task/spring-task.xsd/schema/util/schema/util/spring-util.xsd/schema/mvc/schema/mvc/spring-mvc.xsd"><context:annotation-config /><context:component-scan base-package="com.zx.*" /><aop:aspectj-autoproxy proxy-target-class="true" /><import resource="redis.xml"/><import resource="dubbo-consumer.xml"/> <mvc:annotation-driven /><!-- <bean id="multipartResolver" class="org.springframework.monsMultipartResolver"> <property name="maxUploadSize"><value>100000</value></property><property name="defaultEncoding"><value>UTF-8</value></property></bean> --><bean id="propertyConfigurer"class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"><property name="locations"><list><value>classpath:/config/system-#{systemProperties['envTarget']}.properties</value></list></property></bean><!-- spring session --><!-- <beans:bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"><beans:property name="shardInfo" ref="jedisShareInfo"/></beans:bean><beans:bean name="jedisShareInfo" class="redis.clients.jedis.JedisShardInfo"> <beans:constructor-arg index="0" value="${redis.host}"/></beans:bean> --><!-- 将session放入redis --><!-- <beans:bean id="redisHttpSessionConfiguration"class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"><beans:property name="maxInactiveIntervalInSeconds" value="600" /></beans:bean><util:constant static-field="org.springframework.session.data.redis.config.ConfigureRedisAction.NO_OP"/>--><mvc:annotation-driven conversion-service="conversionService"/><bean id="conversionService"class="org.springframework.context.support.ConversionServiceFactoryBean"><property name="converters"><list><bean class="com.zx.util.TimestampConverter"></bean></list></property></bean><bean class="com.zx.util.SpringUtil" /><bean class="com.zx.util.SpringContextHolder" lazy-init="false" /></beans>
dubbo-consumer.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xmlns:dubbo="/schema/dubbo"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd/schema/dubbo/schema/dubbo/dubbo.xsd"><dubbo:application name="consumer" owner="zx"></dubbo:application><!-- zookeeper注册中心 --><dubbo:registry address="${dubbo.registry.address}" file="${catalina.home}/dubbo-registry/dubbo-registry.properties" /><!-- 配置监控的服务地址和IP --><!-- <dubbo:monitor address="${dubbo.monitor.address}" /> --><!-- <dubbo:reference interface="com.zx.base.api.ITestService" id="testService" check="false"/> --><dubbo:reference interface="com.zx.base.api.service.manager.ITestService" id="testService" protocol="dubbo" check="false" /></beans>
redis.xml
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="/schema/beans"xmlns:xsi="/2001/XMLSchema-instance"xmlns:context="/schema/context"xsi:schemaLocation="/schema/beans/schema/beans/spring-beans.xsd/schema/context/schema/context/spring-context.xsd"><bean id="shardedJedisPool" class="redis.clients.jedis.ShardedJedisPool"><constructor-arg index="0" ref="jedisPoolConfig"/><constructor-arg index="1"><list><bean name="master" class="redis.clients.jedis.JedisShardInfo"><constructor-arg index="0" value="http://server1:zx@123.1.456.24:6379/0"/></bean></list></constructor-arg></bean><bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"><!-- 最大连接数 --><property name="maxTotal" value="500" /><!-- 最小空闲连接数 --><property name="minIdle" value="10" /><!-- 最大空闲连接数 --><property name="maxIdle" value="100" /><!-- 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3 --><property name="numTestsPerEvictionRun" value="250"/><property name="timeBetweenEvictionRunsMillis" value="30000" /><property name="minEvictableIdleTimeMillis" value="-1" /><property name="softMinEvictableIdleTimeMillis" value="10000" /><property name="maxWaitMillis" value="10000"/><property name="testOnBorrow" value="true" /><property name="testWhileIdle" value="true"/><property name="testOnReturn" value="true"/><property name="jmxEnabled" value="true"/><property name="jmxNamePrefix" value="jjk"/><property name="blockWhenExhausted" value="false"/></bean></beans>
logback.xml
<!DOCTYPE xml><configuration debug="true" scan="true" scanPeriod="5 seconds"><contextName>consumer</contextName><!-- 默认为local --><include resource="config/logback-${envTarget:-local}.xml" /></configuration>
logback-local.xml
<included><property name="LOG_PATH" value="${catalina.home}/logs" /><appendername="ROLLINGFILE"class="ch.qos.logback.core.rolling.RollingFileAppender"><file>${LOG_PATH}/consumer.log</file><rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"><fileNamePattern>${LOG_PATH}/consumer.log.%d{yyyy-MM-dd}</fileNamePattern><maxHistory>30</maxHistory></rollingPolicy><encoder><Pattern>%date{yyyy-MM-dd HH:mm:ss} %logger %level - %msg%n</Pattern></encoder></appender><appendername="STDOUT"class="ch.qos.logback.core.ConsoleAppender"><encoder><Pattern>%date{yyyy-MM-dd HH:mm:ss} %logger %level - %msg%n</Pattern></encoder></appender><root level="INFO"><appender-ref ref="STDOUT" /><appender-ref ref="ROLLINGFILE" /></root></included>
system-local.properties
#DUBBO CONFIGdubbo.registry.address=zookeeper://127.0.0.1:2181
SpringUtil.java
package com.zx.util;import org.springframework.beans.BeansException;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.context.ApplicationEvent;public final class SpringUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;public static Object get(String name) {return applicationContext.getBean(name);}public static <T> T get(Class<T> cl) {return applicationContext.getBean(cl);}public static void sendEvent(ApplicationEvent event) {applicationContext.publishEvent(event);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringUtil.applicationContext = applicationContext;}}
SpringContextHolder.java
package com.zx.util;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.beans.BeansException;import org.springframework.beans.factory.DisposableBean;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;/*** 以静态变量保存Spring ApplicationContext, 可在任何代码任何地方任何时候中取出ApplicaitonContext.*/@SuppressWarnings("unchecked")public class SpringContextHolder implements ApplicationContextAware, DisposableBean {private static ApplicationContext applicationContext = null;private static final Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);/*** 取得存储在静态变量中的ApplicationContext.*/public static ApplicationContext getApplicationContext() {assertContextInjected();return applicationContext;}/*** 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.*/public static <T> T getBean(String name) {assertContextInjected();return (T) applicationContext.getBean(name);}/*** 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.*/public static <T> T getBean(Class<T> requiredType) {assertContextInjected();return applicationContext.getBean(requiredType);}/*** 清除SpringContextHolder中的ApplicationContext为Null.*/public static void clear() {logger.debug("清除SpringContextHolder中的ApplicationContext:" + applicationContext);applicationContext = null;}/*** 实现ApplicationContextAware接口, 注入Context到静态变量中.*/public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {logger.debug("注入ApplicationContext到SpringContextHolder:" + applicationContext);if (SpringContextHolder.applicationContext != null) {logger.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:"+ SpringContextHolder.applicationContext);}SpringContextHolder.applicationContext = applicationContext; //NOSONAR}/*** 实现DisposableBean接口, 在Context关闭时清理静态变量.*/public void destroy() throws Exception {SpringContextHolder.clear();}/*** 检查ApplicationContext不为空.*/private static void assertContextInjected() {if (applicationContext == null) {throw new IllegalStateException("applicaitonContext未注入,请在applicationContext.xml中定义SpringContextHolder");}}}TimestampConverter.javapackage com.zx.util;import java.sql.Timestamp;import org.springframework.core.convert.converter.Converter;import org.ponent;@Componentpublic class TimestampConverter implements Converter<String, Timestamp>{@Overridepublic Timestamp convert(String timeStr) {if(timeStr != null && timeStr.length() > 0){return Timestamp.valueOf(timeStr);}return null;}}
TestController.java
package com.zx.controller;import javax.annotation.Resource;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.servlet.ModelAndView;import com.zx.base.api.service.manager.ITestService;@Controller@RequestMapping("/test")public class TestController {@ResourceITestService testService;@RequestMapping("/helloworld")public ModelAndView hello(){ModelAndView view = new ModelAndView("success");return view;}@RequestMapping("/getName")public void getName(){String name = testService.getName();System.out.println(name);}}
success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%><!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "/TR/html4/loose.dtd"><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><title>成功页面</title></head><body><h4>恭喜您成功了</h4></body></html>
3.3.5、启动consumer
3.3.6、调用Controller接口
成功映射到success.jsp
在调一下另外一个Service层的接口
看到控制台成功打印 ,说明成功了
至此,消费者项目consumer搭建完毕!