爲了你們比較快速的開發微服務,規範dubbo,spring,mybatis,hessian,netty的版本和用法,我寫了一個demo,下面對demo的功能作個簡單的介紹,若有疑問的地方,能夠私下問我。java
微服務項目示例 整合了dubbo2.5.11+spring 4.3.10+mybatis3.4.6+sharding-jdbc1.5.4.1(分庫分表客戶端)+apollo(集中配置) 包括微服務的rpc調用,數據庫的增刪改查,分佈式集羣惟一命名,分佈式id生成,數據分佈算法(hash一致性+pre-shard)git
源碼你能夠從url獲取:https://github.com/HowardYi/MicroServiceDemo ;github
裏面有一個spring-sharding-jdbc-example-mybatis-oracle子項目,你們導入maven項目便可web
注意能訪問到apollo 服務地址,oracle服務地址,zk服務地址,地址信息在配置文件中。須要本身打通這些服務依賴。算法
MainProvider.java能夠測試分庫分表下的增刪改查,主鍵和非主鍵路由算法測試,hint方式路由測試,分頁排序功能測試,多表併發查詢結果歸併測試。 啓動後提供dubbo服務,供下面MainProviderGateway.java應用調用,dubbo協議可調整。spring
MainProviderGateway.java啓動後提供模擬的服務網關,對服務接口的封裝,同時對外提供rest接口服務,swagger api定義,方便客戶端在swagger ui上面進行接口定義查看,接口在線測試。sql
MainConsumer.java啓動後,調用上面MainProviderGateway的接口,能夠測試dubbo遠程調用,rest協議方式。shell
DistributionInstanceNoAllocator.java測試集羣惟一編號生成功能。數據庫
DefaultIdGeneratorImpl.java測試雪花算法id生成功能。windows
ConsistedHashRouter.java測試一致性hash算法數據分佈功能。
maven做爲項目管理,提供編譯,打包,組裝發佈的目錄結構等功能;
dubbo2.5.11做爲微服務框架,提供服務rpc,軟負載均衡,容錯重試,服務自動發現和註冊,服務性能監控,服務可用性監測,後臺管理的服務依賴,動態路由設置,動態參數調整,ip鑑權等功能,目前被dubbo_integration間接依賴進來,包括web容器啓動dubbo支持,restful風格的接口swagger 功能支持,http/hessian3/hessian等協議的附件功能支持等;
spring 4.3.11做爲業務邏輯層框架,提供ioc,aop容器,事務,配置等功能;
mybatis3.4.6+spring-mybatis1.3.2+pagehelper5做爲持久層框架,提供dao自動生成,註解方式sql寫法,分頁排序支持等;
apollo0.10提供參數配置功能,不一樣環境的參數配置,再也不須要maven的fliter功能,打不一樣的部署包;
dbcp+ojdbc6提供數據源鏈接池和驅動;
slf4j+logback提供日誌輸出功能;
sharding-jdbc做爲關係型數據的分佈式客戶端框架,提供hint方式和算法方式的路由,併發查詢,結果排序分頁統計;此功能在大部分項目能夠忽略;
curator2.7.1做爲訪問zookeeper客戶端;
com.yspay.common.cluster應用實例機器惟一編號生成,動態生成惟一標識;
com.yspay.common.coordinator分佈式協調器客戶端,封裝訪問zk的代碼;
com.yspay.common.datasource支持加密用戶名和密碼的數據源鏈接池;
com.yspay.common.idgenerator snowflake雪花算法做爲惟一id生成器,取代oracle自增序列;
com.yspay.common.shard.consistedhash 一致性hash算法路由表,分庫分表的算法;
com.yspay.sample.dubboprovider.api 應用服務對外的接口層;
com.yspay.sample.dubboprovider.datasource數據源層,分佈式的數據源鏈接池;
com.yspay.sample.dubboprovider.entity業務實體層;
com.yspay.sample.dubboprovider.repository數據庫持久層;
com.yspay.sample.dubboprovider.service業務邏輯層;
1,配置加載容器,應用信息,協議和日誌等src\main\resources\dubbo.properties:
dubbo.container-》dubbo應用main方法啓動時候加載哪些容器,目前配置有:spring,spring上下文加載,jetty,dubbo服務狀態對外展現的web容器啓動,logback,dubbo服務的日誌組件初始化;
dubbo.application-》dubbo應用信息,管理控制檯能夠看到服務提供者信息;
dubbo.logback-》logback日誌配置;
dubbo.protocol-》dubbo rpc協議配置,規定了通訊傳輸組件netty4,對象序列化方式hessian2,對外服務的ip(當有多個ip地址時須要指定)和端口,處理業務的工做線程池模型和數量,最大可鏈接客戶端的數量;
jvm.heapdump.path-》jvm內存溢出時,堆棧導出目錄
2,配置註冊中心和性能監控src\main\resources\META-INF\spring\dubboCommonContext.xml:
<dubbo:registry protocol="zookeeper" client="curator" address="${dubbo.registry.address:10.213.32.120:2181}" />
<!--監控,測試環境和生產環境的時候打開-->
<dubbo:monitor protocol="registry"/>
你能夠編寫一個spring bean (api層服務),而後加上下面簡單配置便可:
配置文件src\main\resources\META-INF\spring\dubboProviderContext.xml
<dubbo:service interface="com.yspay.sample.dubboprovider.api.IOrderServiceApi" ref="orderServiceApiImpl"
protocol="dubbo" validation="false"></dubbo:service>
發佈服務能夠指定協議,指定註冊中心等信息,具體細節參考dubbo開發指南。
引入服務端發佈的服務接口依賴包,而後加上下面配置便可:
src\main\resources\META-INF\spring\dubboConsumerContext.xml
<dubbo:reference id="orderServiceApiClient" interface="com.yspay.sample.dubboprovider.api.IOrderServiceApi"></dubbo:reference>
而後客戶端代碼就能夠注入這個bean,調用遠程服務了。
1,配置應用惟一標識,屬性文件:src\main\resources\META-INF\app.properties
app.id-》指定應用在apollo配置中心的惟一標識,能夠和dubbo應用名稱一致
2,配置spring從配置中心加載哪些配置 src/main/resources/META-INF/spring/apolloContext.xml:
apollo以namespace爲配置的最小集合單位,namespace包括一組配置(key=value形式配置單元),具體概念參考apollo官方用法
<!-- 這個是最簡單的配置形式,通常應用用這種形式就能夠了,用來指示Apollo注入application namespace的配置到Spring環境中 -->
<apollo:config order="3"/>
<!-- 這個是最複雜的配置形式,指示Apollo注入PAID.dubbo namespace的配置到Spring環境中,而且順序在application前面 -->
<apollo:config namespaces="PAID.dubbo" order="2"/>
<apollo:config namespaces="PAID.datasource" order="1"/>
3,應用啓動時指定當前環境:
jvm系統參數須要包括-Denv=dev或fat或uat或pro,指定當前運行環境,應用程序啓動後根據這個值去集中配置服務取相關配置;
shell啓動腳本會從操做系統環境變量獲取這個evn參數,而後傳遞給jvm系統參數;
若是你運行Main進行測試,代碼裏面經過編碼方式指定env:
// 設置環境變量env,apollo(集中配置)須要此變量
String env = System.getProperty("env");
if (env == null) {
System.setProperty("env", "FAT");
}
4,引用配置中心的參數值
下面是數據源的地址參數,不一樣環境值不一樣,使用${name:defaultvalue}方式
<bean id="ds_0" class="com.yspay.common.datasource.SecretBasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="${manager.url:jdbc:oracle:thin:@10.168.192.1:1521:orcl}"/>
<property name="username" value="${manager.username:defaultusername}"/>
<property name="password" value="${manager.password:defaultpwd}"/>
<property name="defaultAutoCommit" value="false"></property>
<property name="initialSize" value="${trade.inisize:3}"/>
<property name="maxActive" value="${trade.maxsize:10}"/>
<property name="minIdle" value="${trade.maxidle:2}" />
<property name="maxIdle" value="${trade.minidle:2}" />
<property name="validationQuery" value="select * from dual"/>
<property name="testWhileIdle" value="false" />
<property name="timeBetweenEvictionRunsMillis" value="600" />
</bean>
5,保證apollo配置文件本地備份目錄有讀寫權限
apollo會在本地保存一份配置文件,防止不能訪問遠程配置服務的時候使用本地配置,默認會在/opt/data目錄下,若是是windows是在c盤下這個目錄;
1,配置事務管理器,以及註解方式事務管理:
src\main\resources\META-INF\spring\serviceContext.xml
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="shardingDataSource" />
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
2,代碼中標註註解:
只讀事務:
@Override
@Transactional(readOnly = true)
public void select() {
}
寫事務,指示方法事務傳播屬性,根據異常類型回滾事務:
@Override
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Throwable.class)
public void insert() {
}
1,配置
src\main\resources\META-INF\spring\mybatisContext.xml
配置mybatis session factory跟hibernate相似,這裏面有一個pageInterceptor插件,用來生成分頁sql的,具體用法能夠參考pagehelper官網。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="shardingDataSource"/>
<property name="plugins">
<array>
<bean class="com.github.pagehelper.PageInterceptor">
<property name="properties">
<!--使用下面的方式配置參數,一行配置一個 -->
<value>
helperDialect=oracle
rowBoundsWithCount=true
</value>
</property>
</bean>
</array>
</property>
</bean>
這個是配置自動生成dao(mybatis叫mapper)的實現類的,在basePackage下面的全部mapper接口,都會自動生成一個實現類bean,開發者不須要本身寫dao的實現類,只須要定義dao接口以及dao接口須要使用的sql便可
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yspay.sample.dubboprovider.repository"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
2,自動生成dao(mapper)代碼和entity代碼
2.1安裝mybatis generator eclipse插件,
2.2編寫代碼自動生成工具須要的配置,主要是指定數據源,生成代碼的目錄,哪些表須要生成代碼等等,項目中有一個配置文件例子:src\mybatis-generator-config\generatorConfig.xml,
2.3在eclipse裏面,點擊配置文件,右鍵菜單-》Run-》mybatis generator便可生成代碼了
3, 編寫定製的dao方法
上面自動生成的mapper方法一般不夠知足本身的需求,定製mapper是必要的。
建立新mapper接口,通常不要再原來自動生成的mapper上進行修改,否則表改動後,從新生成mapper代碼,會把你寫的方法抹掉;我習慣在原來表mapper類的名字後加Ext表明是擴展的mapper。
類com\yspay\sample\dubboprovider\repository\OrderMapperExt.java,定義爲自動生成類OrderMapper.java的擴展:
更新寫法:
@Update({ "update T_ORDER ", "set STATUS = #{status,jdbcType=VARCHAR} ",
"where USER_ID = #{userId,jdbcType=VARCHAR} and ORDER_ID = #{orderId,jdbcType=VARCHAR}" })
int updateStatusByUserIdOrderId(Order record);
分頁寫法:
@Select({ "select", "ORDER_ID, USER_ID, STATUS, CREATE_DATE",
"from T_ORDER" })
@ResultMap("OrderMap")
List<Order> selectByPage(RowBounds row);
只要方法裏面有RowBounds參數,sql會自動再加上分頁的sql(rownum>? and rownum<?);因此上面查詢sql並不須要分頁相關的sql