SOA
一個基本的面向服務編程(soa)的分佈式項目需要provider和consumer,也就是最基本的服務提供方和服務消費方,其中provider還可以細分爲Interface和IService的實現關係進一步在業務上細分服務。本實例就不細分provider了,爲了方便理解僅做最基本的provider和consumer劃分。
注:本實例的一切注入方式均爲註解掃描注入方式。
服務提供者Provider
一個已集成spring框架的項目,項目名爲Provider,項目結構圖如下。
本實例中,新建的項目類型爲Maven Project->maven-archetype-webapp。
Dynamic Web Module爲2.5
JDK爲1.7
1、Pom.xml
除了基本的springframework以外,主要需要引入以下包:
Zookeeper
<!-- zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>3.3.6</version>
<exclusions>
<exclusion>
<artifactId>netty</artifactId>
<groupId>io.netty</groupId>
</exclusion>
</exclusions>
</dependency>
Dubbo
<!-- dubbo -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo</artifactId>
<version>2.5.3</version>
<exclusions>
<exclusion>
<artifactId>spring</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>netty</artifactId>
<groupId>io.netty</groupId>
</exclusion>
</exclusions>
</dependency>
zkClient
<!-- zkclient -->
<dependency>
<groupId>com.github.sgroschupf</groupId>
<artifactId>zkclient</artifactId>
<version>0.1</version>
<exclusions>
<exclusion>
<artifactId>netty</artifactId>
<groupId>io.netty</groupId>
</exclusion>
</exclusions>
</dependency>
配置pom.xml的過程中可能會遇到很多編譯上的報錯,多是由包與包之間的依賴關係引起,也和開發環境有關,自行百度,具體問題具體解決。搭建過程中遇到太多問題了,有空會將常見問題做一個彙總,如配置過程中遇到瓶頸問題,請在本文下方留言聯繫我。
2、Web.xml
做最基本的spring集成配置即可,配好ContextLoaderListener和DispatcherServlet,同時建立好applicationContext.xml和dubbo-provider.xml的上下文引用即可。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- 配置web.xml,使其具有springmvc特性,主要配置兩處,一個是ContextLoaderListener,一個是DispatcherServlet -->
<!-- ContextLoaderListener初始化Spring上下文時需要使用到的contextConfigLocation參數 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:applicationContext.xml,classpath*:dubbo-provider.xml</param-value>
</context-param>
<!-- spring mvc 配置 -->
<!-- 配置DispatcherServlet表示,該工程將採用springmvc的方式。啓動時也會默認在/WEB-INF目錄下查找XXX-servlet.xml作爲配置文件,
XXX就是DispatcherServlet的名字,該文件中將配置兩項重要的mvc特性:HandlerMapping,負責爲DispatcherServlet這個前端控制器的請求查找Controller;
ViewResolver,負責爲DispatcherServlet查找ModelAndView的視圖解析器。
此處使用指定的配置文件spring-mvc.xml -->
<!-- 優點:支持rest風格,Url美觀
缺點:會攔截靜態資源 -->
<servlet>
<servlet-name>contacts</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<!--<param-value>/WEB-INF/classes/spring-mvc-servlet.xml</param-value>-->
<param-value>classpath*:/spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- url-pattern配置爲/,不帶文件後綴,會造成其它靜態文件(js,css等)不能訪問。如配爲*.do,則不影響靜態文件的訪問 -->
<servlet-mapping>
<servlet-name>contacts</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
3、applicationContext.xml
這裏的applicationContext.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:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd">
<!-- 加入spring註解掃描-->
<context:component-scan base-package="com.lhx."/>
</beans>
掃描com.lhx.路徑下的所以class文件和jar包內的文件的註解,註冊到beanFactory中。
注:這裏的配置與後面的UserService的註解有一些聯繫,暫且記住這麼一回事,後面會詳細說明
4、dubbo-provider.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:dubbo="http://code.alibabatech.com/schema/dubbo"
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-3.1.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
">
<!-- 提供方應用信息,用於計算依賴關係 -->
<dubbo:application name="dubbo_provider" />
<!-- 使用zookeeper註冊中心暴露服務地址 端口是zookeeper 中配置的2181 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- <dubbo:registry address="multicast://224.5.6.7:1234" /> -->
<!-- 用dubbo協議在20880端口暴露服務 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 使用註解方式暴露接口 -->
<dubbo:annotation package="com.lhx.user"/>
</beans>
配置項含義如代碼行註釋所示。
這裏的有一點要說明的是,因爲之前已經提過,本實例的一切注入方式均爲註解注入,所以後面再配置註解的時候要十分注意註解的引用,也就是import的包是來自於spring還是dubbo。
5、UserServiceImpl
基於第3步的鋪墊,這裏要着重說明一下服務的實現類。
UserServiceImpl
如上圖所示
@Service的引用是來自於com.alibaba.dubbo.config.annotation.Service
@Component的引用是來自於org.springframework.stereotype.Component
這裏比較有意思了,一般我們使用註解方式注入bean的話,@Service是拿來專門注入Service服務層的註解,@Component是實例化普通POJO的,可以拿來注入Controller、Service、Repository等,只有當組件不好歸類的時候,我們可以使用這個註解進行標註。
爲什麼我們在這裏注入UserServiceImpl的服務實現類的時候要用@Component,是因爲@Service要留給dubbo去暴露服務,因爲註解重名的原因,我們只能用@Component去作爲替代。所以引用@Service這個註解時一定要注意是不是import的com.alibaba.dubbo.config.annotation.Service,否則就會出現zookeeper無法捕捉dubbo暴露的服務,從而無法在zookeeper中註冊這個服務。
6、UserService
就是一個接口,註解方式暴露服務依託於接口實現類,xml方式暴露的話配置依賴會涉及到接口,但是我認爲xml方式暴露服務相比於註解暴露太麻煩,在這裏就不多提了。
package com.lhx.user.service;
import org.springframework.stereotype.Service;
public interface UserService {
public String sayHello();
}
服務消費者Consumer
1、pom.xml
插件引用於Provider一致,配置dubbo/zookeeper/zkClient即可,有一點不同就是消費者Consumer需要引用服務提供者Provider的Jar包。
右鍵Provider項目,Run As->Maven Install可將項目編譯打包,打包的格式有jar、war、rar等,供外部程序引用自然是打包成Jar包,打包格式的設置在pom.xml中定義。
2、Web.xml
同服務提供者,做最基本的spring集成配置即可,配好ContextLoaderListener和DispatcherServlet,同時建立好applicationContext.xml和dubbo-provider.xml的上下文引用即可。
3、applicationContext.xml
同服務提供者,這裏的applicationContext.xml配置很簡單,只需要一個註解掃描的配置即可。
4、dubbo-consumer.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:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd
">
<!-- 提供方應用信息,用於計算依賴關係 -->
<dubbo:application name="dubbo_consumer" />
<!-- 使用zookeeper註冊中心暴露服務地址 端口是zookeeper 中配置的2181 -->
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<!-- <dubbo:registry address="multicast://224.5.6.7:1234" /> -->
<!-- 用dubbo協議在20880端口暴露服務 -->
<dubbo:protocol name="dubbo" port="20880" />
<!-- 使用註解方式註冊消費者 -->
<dubbo:annotation package="com.lhx.user.controller"/>
</beans>
5、UserController
除了spring的註解以外,就是消費者需要註冊調用的服務,用dubbo的Reference註解即可。
package com.lhx.user.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.dubbo.config.annotation.Reference;
import com.lhx.user.service.UserService;
@Controller
public class UserController {
@Reference
private UserService userService;
@RequestMapping(value="/hello", method=RequestMethod.GET)
public @ResponseBody String hello() {
return userService.sayHello();
}
}
運行效果
值得一提的是,dubbo將服務發佈在zookeeper上這一步驟是無需依託於相應的消費者是否存在的,服務可以獨立存在,即使沒有消費者。
所以本實例建議在編寫完Provider後即可運行查看dubbo-admin的管理頁面是否已經註冊到了我們新加的服務,只有在服務確認發佈(暴露)成功後再編寫相應的消費者纔是有的放夭。
1、服務者(Provider)
2、消費者(Consumer)
結語
學會搭建dubbo+zookeeper只是摸到了分佈式框架的門檻,真正入門還需要學習很多其他方面的知識,諸如分佈式事務、分佈式緩存、負載均衡等等。
博主由於工作上的需要,也正處於這樣的一個學習階段,希望能夠憑藉着自己的努力把一些個人心得在這裏分享。