本文系原创,转载请注明出处:http://blog.csdn.net/woshizisezise/article/details/79203539
情景分析:由于很多商城是基于soa的架构,表现层和服务层是不同的工程。所以要实现商品列表查询需要两个系统之间进行通信。
如何实现远程通信?
1、Webservice:效率不高基于soap协议。项目中不推荐使用。
2、使用restful形式的服务:http+json。很多项目中应用。如果服务太多,服务之间调用关系混乱,需要治疗服务。
3、使用dubbo。使用rpc协议进行远程调用,直接使用socket通信。传输效率高,并且可以统计出系统之间的调用关系、调用次数。
今天我们来学习一下什么是dubbo和zookeeper,并且我搭建了一套入门的dubbo服务供大家学习。
首先来了解一下dubbo的定义。
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和Spring框架无缝集成。
Remoting: 网络通信框架,实现了 sync-over-async 和request-response 消息机制。
RPC: 一个远程过程调用的抽象,支持负载均衡、容灾和集群功能。
Registry: 服务目录框架用于服务的注册和服务事件发布和订阅。
节点角色说明:
Provider
暴露服务方称之为“服务提供者”。
Consumer
调用远程服务方称之为“服务消费者”。
Registry
服务注册与发现的中心目录服务称之为“服务注册中心”。
Monitor
统计服务的调用次数和调用时间的日志服务称之为“服务监控中心”。
Container
服务运行容器。
调用关系说明:
0. 服务容器负责启动,加载,运行服务提供者。
1. 服务提供者在启动时,向注册中心注册自己提供的服务。
2. 服务消费者在启动时,向注册中心订阅自己所需的服务。
3. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
4. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
5. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
ZooKeeper的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
注意:ZooKeeper性能上的特点决定了它能够用在大型的、分布式的系统当中。从可靠性方面来说,它并不会因为一个节点的错误而崩溃。除此之外,它严格的序列访问控制意味着复杂的控制原语可以应用在客户端上。ZooKeeper在一致性、可用性、容错性的保证,也是ZooKeeper的成功之处,它获得的一切成功都与它采用的协议——Zab协议是密不可分的
zookeeper负责保存了服务提供方和服务消费方的的URI(dubbo自定义的一种URI),服务消费方找到zookeeper,向zookeeper要到服务提供方的URI,然后就找到提供方,并调用提供方的服务。解耦,分布式,failover。dubbo是管理中间层的工具,在业务层到数据仓库间有非常多服务的接入和服务提供者需要调度,dubbo提供一个框架解决这个问题。注意这里的dubbo只是一个框架,至于你架子上放什么是完全取决于你的,就像一个汽车骨架,你需要配你的轮子引擎。这个框架中要完成调度必须要有一个分布式的注册中心,储存所有服务的元数据,你可以用zk,也可以用别的,只是大家都用zk。zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知道,简单来说就是IP地址和服务名称的对应关系。当然也可以通过硬编码的方式把这种对应关系在调用方业务代码中实现,但是如果提供服务的机器挂掉调用者无法知晓,如果不更改代码会继续请求挂掉的机器提供服务。zookeeper通过心跳机制可以检测挂掉的机器并将挂掉机器的IP和服务对应关系从列表中删除。至于支持高并发,简单来说就是横向扩展,在不更改代码的情况通过添加机器来提高运算能力。通过添加新的机器向zookeeper注册服务,服务的提供者多了能服务的客户就多了。
zookeeper是dubbo推荐的注册中心,就是一个单独运行的软件。
具体的相关dubbo和zookeeper详解和源码,大家有兴趣的可以自行去百度查找,我这儿只是说说是什么,怎么用,带大家入个门,因为这两个东西的内容还是挺多的,涉及的底层源码还是挺复杂的,那么下面我们开始讲解实战部分啦~
首先我们需要创建两个工程,其中一个作为服务提供者,另一个作为服务消费者(这个一般是web工程),那么这里我新建了两个maven工程dubbo-zookeeper-demo和dubbo-zookeeper-web。
下面我们来一级级的分解项目代码并做详细的讲解。
3.1.1 项目框架
首先来看一眼项目整体的框架如下:
工程中包括一个接口DubboTestService,一个实现类DubboTestServiceImpl,一个applicationContext.xml配置文件,一个必备的web.xml文件,还有maven工程的pom.xml文件。
3.1.2 代码分析
(1)DubboTestService.java
package com.dubbo.service;
public interface DubboTestService {
String testDubbo() throws Exception;
}
(2)DubboTestServiceImpl.java
package com.dubbo.service.impl;
import org.springframework.stereotype.Service;
import com.dubbo.service.DubboTestService;
@Service
public class DubboTestServiceImpl implements DubboTestService {
@Override
public String testDubbo() {
return "恭喜你,测试通过";
}
}
这里我写了一个接口和一个实现接口的实现类,并且在实现类中返回了一个字符串,主要就是用来验证我们的dubbo服务是通的,所以比较简单,当然大家开发的时候肯定是写自己项目中具体用到的逻辑代码了。
(3)applicationContext-service.xml
这个文件是spring的配置文件,主要用来实现组件管理,来看看具体的代码:
<beans xmlns="http://www.springframework.org/schema/beans"
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"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.2.xsd">
<context:component-scan base-package="com.dubbo.service"/>
<dubbo:application name="dubbo-zookeeper-demo" />
<dubbo:registry protocol="zookeeper" address="192.168.25.88:2181" />
<dubbo:protocol name="dubbo" port="20880" />
<dubbo:service interface="com.dubbo.service.DubboTestService" ref="dubboTestServiceImpl" timeout="300000"/>
beans>
这里配置的address=”192.168.25.88:2181”指的是zookeeper运行的服务器地址,由于我是将dubbo和zookeeper都运行在linux环境下了,所以这里的地址是我的linux服务器的地址,具体的后续运行项目的时候会讲到,到时候大家将这个改为自己实际的地址即可。
这里指定的是我们的哪个接口对外提供服务,设置为我们的DubboTestService,这里并不是只能配置一个,如果有多个Service的话,大家像这样类似的配置就好了,具体的ref引用配置的是我们的接口实现类,毕竟具体工作还是有它来实现的。
(4)web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>dubbo-zookeeper-demodisplay-name>
<welcome-file-list>
<welcome-file>index.jspwelcome-file>
welcome-file-list>
<context-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring/applicationContext-*.xmlparam-value>
context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListenerlistener-class>
listener>
web-app>
(5)pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.taotaogroupId>
<artifactId>dubbo-zookeeper-demoartifactId>
<version>0.0.1-SNAPSHOTversion>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jmsartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>dubboartifactId>
<exclusions>
<exclusion>
<artifactId>springartifactId>
<groupId>org.springframeworkgroupId>
exclusion>
<exclusion>
<artifactId>nettyartifactId>
<groupId>org.jboss.nettygroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
dependency>
<dependency>
<groupId>com.github.sgroschupfgroupId>
<artifactId>zkclientartifactId>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<configuration>
<path>/path>
<port>8080port>
configuration>
plugin>
plugins>
build>
<packaging>warpackaging>
project>
pom文件中配置的是spring和dubbo相关的jar包,还有tomcat插件的配置。
3.2.1 代码结构
项目中包含一个controller,springmvc配置文件,web.xml,pom.xml文件。
3.2.2 代码分析
(1)DubboTestController.java
package com.dubbo.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import com.dubbo.service.DubboTestService;
@Controller
public class DubboTestController {
@Autowired
private DubboTestService dubboTestService;
@RequestMapping("/test/dubbo")
public String testDubboService(Model model) throws Exception{
String message = dubboTestService.testDubbo();
model.addAttribute("message", message);
return "success";
}
}
我们在controller中注入了service,通过service调用方法得到了一个字符串,然后我们通过model将字符串添加到属性中,然后返回成功的页面,我们可以通过http://localhost:8081/test/dubbo来访问这个接口了。
(2)springmvc.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd">
<mvc:annotation-driven />
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
bean>
<bean class="com.dubbo.exception.GlobalExceptionResolver">bean>
<context:component-scan base-package="com.dubbo.controller"/>
<dubbo:application name="dubbo-zookeeper-web"/>
<dubbo:registry protocol="zookeeper" address="192.168.25.88:2181"/>
<dubbo:reference interface="com.dubbo.service.DubboTestService" id="dubboTestService" />
beans>
这里配置了视图解析器,所以我们在controller中return “success”;它就能找到/WEB-INF/jsp/success.jsp文件了。
(3)web.xml
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
id="WebApp_ID" version="2.5">
<display-name>dubbo-zookeeper-webdisplay-name>
<welcome-file-list>
<welcome-file>index.htmlwelcome-file>
welcome-file-list>
<servlet>
<servlet-name>dubbo-zookeeper-webservlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>classpath:spring/springmvc.xmlparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>dubbo-zookeeper-webservlet-name>
<url-pattern>/url-pattern>
servlet-mapping>
web-app>
这里配置了前端控制器和请求的拦截路径。
(4)success.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>成功页面title>
head>
<body>
<h1>${message }h1>
body>
html>
这里通过EL表达式取出我们传入的值。
(5)pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0modelVersion>
<groupId>com.taotaogroupId>
<artifactId>dubbo-zookeeper-webartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>warpackaging>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jdbcartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aspectsartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-jmsartifactId>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-context-supportartifactId>
dependency>
<dependency>
<groupId>jstlgroupId>
<artifactId>jstlartifactId>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>servlet-apiartifactId>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jsp-apiartifactId>
<scope>providedscope>
dependency>
<dependency>
<groupId>com.alibabagroupId>
<artifactId>dubboartifactId>
<exclusions>
<exclusion>
<artifactId>springartifactId>
<groupId>org.springframeworkgroupId>
exclusion>
<exclusion>
<artifactId>nettyartifactId>
<groupId>org.jboss.nettygroupId>
exclusion>
exclusions>
dependency>
<dependency>
<groupId>org.apache.zookeepergroupId>
<artifactId>zookeeperartifactId>
dependency>
<dependency>
<groupId>com.github.sgroschupfgroupId>
<artifactId>zkclientartifactId>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
dependency>
<dependency>
<groupId>com.taotaogroupId>
<artifactId>dubbo-zookeeper-demoartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.mavengroupId>
<artifactId>tomcat7-maven-pluginartifactId>
<configuration>
<path>/path>
<port>8081port>
configuration>
plugin>
plugins>
build>
project>
这里配置了spring,dubbo,tomcat相关的jar包,值得注意的是,这里我们需要引入dubbo-zookeeper-demo工程。
3.3.1 启动zookeeper
(1)进入到linux服务器环境下,将zookeeper压缩包上传至linux的root目录下,然后解压缩
(2)将conf文件夹下的zoo_sample.cfg复制一份,改名为zoo.cfg
(3)修改配置dataDir属性,指定一个真实目录
(4)进入到zookeeper文件夹的bin文件夹,可以看到有个zkServer.sh,通过它可以启动,关闭,查看zookeeper的状态
启动zookeeper:bin/zkServer.sh start
关闭zookeeper:bin/zkServer.sh stop
查看zookeeper状态:bin/zkServer.sh status
我们启动了zookeeper后,可以通过命令来查看zookeeper的状态
3.3.2 启动dubbo
(1)当然前提条件是你的linux下有个tomcat,然后将dubbo-admin-2.5.4.war包上传到root目录下,然后将war包复制到tomcat的webapps目录下:
cp dubbo-admin-2.5.4.war apache-tomcat-7.0.47/webapps/dubbo-admin.war
(2)进入tomcat/bin/目录,启动tomcat,dubbo-admin的war会自动解压并运行,这个时候我们可以通过浏览器访问dubbo-admin了,用户名密码都是root,如下:
运行到这里,说明zookeeper和dubbo已经正常启动了,当我们的java工程运行起来后,我们可以在dubbo-admin中看到我们的提供者和消费者,一会儿看。
3.3.4 启动dubbo-zookeeper-web
操作过程和上述一样,当看到console控制台输出启动成功的提示后,我们就可以来测试了。首先我们来看看dubbo-admin中有没有什么变化
可以看到,这个时候已经提示了demo工程为提供者,web工程为消费者,这就说明我们的dubbo已经起作用了。
这个时候通过浏览器访问http://localhost:8081/test/dubbo,如果调用服务成功,那么这里就应该会返回我们在service中返回的字符串。
到这里,我们这个项目已经成功的运行了,这里讲的也是一个入门的项目,捋清楚dubbo是什么,怎么用,复杂的高级的东西,还是得靠大家自己去继续学习了,毕竟师傅引进门,修行在个人,好了各位,古德拜~有问题请留言,如果我写的不详细漏了也请告诉我,3Q~~~~~~