分布式软件架构(二)RPC框架dubbo

RPC框架

什么是RPC

RPC(remote procedure cal)l,即远程过程调用。比如两台服务器A和B,A服务器上部署一个应用,B服务器上部署一个应用,A服务器上的应用想调用B服务器上的应用提供的方法,由于两个应用不在一个内存空间,不能直接调用,所以需要通过网络来表达调用的语义和传达调用的数据。RPC并不是一个具体的技术,而是指整个网络远程调用过程。
RPC是一个泛化的概念,严格来说一切远程过程调用手段都属于RPC范畴。各种开发语言都有自己的RPC框架。 Java中的RPC框架比较多,广泛使用的有RMI、Hessian、Dubbo等。 *即dubbo 是javaRPC框架成员之一。

dubbo的简介

Apache Dubbo是一款高性能的Java RPC框架。其前身是阿里巴巴公司开源的一个高性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。Dubbo 提供了六大核心能力:面向接口代理的高性能RPC调用,智能容错和负载均衡,服务自动注册和发现,高度可扩展能力,运行期流量调度,可视化的服务治理与运维。

dubbo 架构

在这里插入图片描述

节点角色名称
Provider暴露服务的服务提供方
Consumer调用远程服务的服务消费方
Registry服务注册与发现的注册中心
Monitor统计服务的调用次数和调用时间的监控中心(监控中心并不是必须的)
Container服务运行容器

虚线都是异步访问,实线都是同步访问
蓝紫色色虚线:在启动时完成的功能
蓝绿色虚线(实线)都是程序运行过程中执行的功能

执行步骤

  1. 服务容器负责启动,加载,运行服务提供者。
  2. 服务提供者在启动时,向注册中心注册自己提供的服务。
  3. 服务消费者在启动时,向注册中心订阅自己所需的服务。
  4. 注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
  5. 服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
  6. 服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
服务注册中心

Zookeeper 是 Apache Hadoop 的子项目,是一个树型的目录服务,支持变更推送,适合作为 Dubbo 服务的注册中心,工业强度较高,可用于生产环境,并推荐使用 。

zookeeper 目录架构

在这里插入图片描述

基本工作流程
  1. 服务提供者(Provider)启动时: 向 /dubbo/com.foo.BarService/providers 目录下写入自己的 URL 地址
  2. 服务消费者(Consumer)启动时: 订阅 /dubbo/com.foo.BarService/providers 目录下的提供者 URL 地址。并向 /dubbo/com.foo.BarService/consumers 目录下写入自己的 URL 地址
  3. 监控中心(Monitor)启动时: 订阅 /dubbo/com.foo.BarService 目录下的所有提供者和消费者 URL 地址
zookeeper的下载

zookeeper是常用的apache工具,下载可以直接上镜像即可。
在这里插入图片描述

zookeeper安装

上传到linux

rz

在这里插入图片描述
查看是否有zookeeper运行

ps -ef | grep zookeeper

若果界面干净就可以安装zookeeper
将压缩包解压解压到指定目录

tar -zxvf apache-zookeeper-3.6.2-bin.tar.gz -C /usr/local/

在zookeeper中建立data文件夹,便于存储数据

mkdir data

在这里插入图片描述
进入conf

cd conf

重命名 zoo_sample.cfg为 zoo.cfg。

mv zoo_sample.cfg zoo.cfg
###  或者采用
cp zoo_sample.cfg zoo.cfg  #### 源文件不删除

编辑 zoo.cfg

vim   zoo.cfg

在这里插入图片描述
保存 esc+wq!即可。

zookeeper的启动和停止

进入zookeeper的bin目录

cd bin

启动本zookeeper
在这里插入图片描述

./zkServer.sh start

在这里插入图片描述
查看zookeeper是否运行

ps -ef | grep zookeeper
####或者采用
./zkServer.sh status

在这里插入图片描述
停止zookeeper再次查看状态

./zkServer.sh stop

在这里插入图片描述
zookeeper重启
在这里插入图片描述

dubbo管理控制台

我们在开发时,需要知道Zookeeper注册中心都注册了哪些服务,有哪些消费者来消费这些服务。我们可以通过部署一个管理中心来实现。其实管理中心就是一个web应用,部署到tomcat即可。除了这种思路外,我们还可以参考 dubbo管理工具之dubbo-admin安装使用,这篇文章也写得非常详细,这篇文章是直接运行在将dubbo-admin直接在idea中运行。

控制台安装

何制作war包和安装控制台也可以参考这篇文章
(1)将dubbo-admin-2.6.0.war文件复制到tomcat的webapps目录下

(2)启动tomcat,此war文件会自动解压

(3)修改WEB-INF下的dubbo.properties文件,注意dubbo.registry.address对应的值需要对应当前使用的Zookeeper的ip地址和端口号

​	dubbo.registry.address=zookeeper://192.168.168.128:2181
​	dubbo.admin.root.password=root
​	dubbo.admin.guest.password=guest

(4)重启tomcat

使用

默认用户root和guest,直接采用root登录即可默认密码也是root。

在这里插入图片描述
在这里插入图片描述
小猿的服务一致处于开启状态,所以在服务列表中会自动展现。

doubbo的应用

案例目录结构
在这里插入图片描述

父工程pom文件。
<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>

    <groupId>com.feitian</groupId>
    <artifactId>mavendubbo</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>dubboprovider</module>
        <module>dubboconsumer</module>
        <module>dubbodao</module>
    </modules>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <spring.version>5.0.5.RELEASE</spring.version>
        <log4j.version>1.2.17</log4j.version>
        <slf4j-log4j12.version>1.7.7</slf4j-log4j12.version>
        <commons-logging.version>1.2</commons-logging.version>
        <mysql-connector-java.version>5.1.47</mysql-connector-java.version>
        <druid.version>1.1.6</druid.version>
        <mybatis-spring.version>1.3.2</mybatis-spring.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-beans</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-core</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jdbc</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aop</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-web</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-expression</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-aspects</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-jms</artifactId>
                <version>${spring.version}</version>
            </dependency>
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context-support</artifactId>
                <version>${spring.version}</version>
            </dependency>


            <dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
                <version>${mysql-connector-java.version}</version>
            </dependency>

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>${druid.version}</version>
            </dependency>

            <dependency>
                <groupId>org.mybatis</groupId>
                <artifactId>mybatis-spring</artifactId>
                <version>${mybatis-spring.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

注意父工程可能内导入的jar包原型可能不是全部都有用。

dubboprovider

目录结构
在这里插入图片描述

dubboprovider pom文件
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>mavendubbo</artifactId>
        <groupId>com.feitian</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>dubboprovider</artifactId>
    <packaging>war</packaging>

    <dependencies>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>

        <dependency>
            <groupId>com.feitian</groupId>
            <artifactId>dubbodao</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!-- 指定端口 -->
                    <port>8081</port>
                    <!-- 请求路径 -->
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

dubboprovider 需要依赖dubbodao 的jar包。

HiPyService
public interface HiPyService {
    public String  hiPyService(String name);
}
HiPyServiceImpl
/*@Service(protocol = "dubbo", interfaceClass = HiPyService.class, loadbalance="random")*/
@Service
public class HiPyServiceImpl implements HiPyService {
    @Override
    public String hiPyService(String name) {
        return  "port8081hello" + name;
    }
}

此处需要注意的@Service注解需要用dubbo下面注解。

applicationContext-service.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: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.xsd
         http://www.springframework.org/schema/mvc
         http://www.springframework.org/schema/mvc/spring-mvc.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.xsd">
    <!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 -->
    <dubbo:application name="dubbo_provider" />
    <!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址-->
    <dubbo:registry address="zookeeper://192.168.168.128:2181"/>
    <!-- 注册  协议和port   端口默认是20880 -->
    <dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>
    <!-- 扫描指定包,加入@Service注解的类会被发布为服务  -->
    <dubbo:annotation package="com.feitian.service" />
    <!--<bean id="hiPyService" class="com.feitian.service.impl.HiPyServiceImpl"/>
    <dubbo:service interface="com.feitian.service.HiPyService" ref="hiPyService"/>-->
</beans>

需要服务系统者将服务提供给注册中心。

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
        <display-name>Archetype Created Web Application</display-name>
        <context-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath*:applicationContext*.xml</param-value>
        </context-param>
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <!-- 防止Spring内存溢出监听器 -->
        <listener>
            <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
        </listener>
</web-app>

在服务提供者tomcat服务器启动时,需要用监听器将服务添加到注册中心。

log4j配置文件
### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.err
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file mylog.log ###
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=c:/mylog.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###
log4j.rootLogger=debug, stdout

需要观察日志,加入日志配置文件,zookeeper中已经导入日志依赖,无需再次导入。
在这里插入图片描述

dubboconsummer
目录结构

在这里插入图片描述

pom文件

pom文件与dubboprovider基本一致,需要改tomcat插件端口

<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>mavendubbo</artifactId>
        <groupId>com.feitian</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dubboconsumer</artifactId>
    <packaging>war</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

        <!-- dubbo相关 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.7</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

        <!--<dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
        </dependency>-->

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <!-- 指定端口 -->
                    <port>8083</port>
                    <!-- 请求路径 -->
                    <path>/</path>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
controller
@Controller
@RequestMapping("/hiPPyController")
public class PyController {
    /*@Reference(check = false,loadbalance = "random")*/
   /* @Autowired*/
    @Reference
    private HiPyService hiPyService;

    @RequestMapping("/hiPython")
    @ResponseBody
    public String hiPython(String name){
        return hiPyService.hiPyService(name);
    }
}
HiPyService
public interface HiPyService {
    public String  hiPyService(String name);
}

需要将dubboprovider 的HiPyService接口拷贝一份,但拷贝是否构成了整个案例的代码冗余呢?

applicationContext_web.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: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.xsd
         http://www.springframework.org/schema/mvc
         http://www.springframework.org/schema/mvc/spring-mvc.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.xsd">
    <!-- 当前应用名称,用于注册中心计算应用间依赖关系,注意:消费者和提供者应用名不要一样 -->
    <dubbo:application name="dubbo_consummer" />
    <!-- 连接服务注册中心zookeeper ip为zookeeper所在服务器的ip地址-->
    <dubbo:registry address="zookeeper://192.168.168.128:2181"/>
    <!-- 扫描指定包,加入@Service注解的类会被发布为服务  -->
    <dubbo:annotation package="com.feitian.controller" />
    <!--直接注入即可相当于替代了包扫描和reference标签-->
    <!--<dubbo:reference id="hiPyService" interface="com.feitian.service.HiPyService" />-->
    <!--启动不检查-->
    <dubbo:consumer check="false"/>

</beans>

此处注意的是不再需要声明远程调用协议,如果开启了启动不检查,那么就无需顾忌provider和consummer的顺序了。

web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:applicationContext_web.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>

一般在前端控制器初始化时,将服务需求注册到服务中心。

日志文件

日志文件保持与provider一致即可。

dubbodao
文件目录

在这里插入图片描述

dubbodao pom配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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">
    <parent>
        <artifactId>mavendubbo</artifactId>
        <groupId>com.feitian</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>dubbodao</artifactId>
    <packaging>jar</packaging>


    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

        <!-- dubbo相关 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dubbo</artifactId>
            <version>2.6.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.zookeeper</groupId>
            <artifactId>zookeeper</artifactId>
            <version>3.4.7</version>
        </dependency>
        <dependency>
            <groupId>com.github.sgroschupf</groupId>
            <artifactId>zkclient</artifactId>
            <version>0.1</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.12.1.GA</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
        </dependency>

        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
        </dependency>
    </dependencies>
</project>
applicationContext-dao.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: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"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/mvc
         http://www.springframework.org/schema/mvc/spring-mvc.xsd
         http://code.alibabatech.com/schema/dubbo
         http://code.alibabatech.com/schema/dubbo/dubbo.xsd
          http://www.springframework.org/schema/tx
         http://www.springframework.org/schema/tx/spring-tx.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd">

    <context:property-placeholder location="jdbc.properties"/>
    <!--配置数据源信息,使用druid连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- 事务管理器  -->
    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <!--开启事务控制的注解支持-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

此处要加入事务管理器和数据库的一些配置,注意此处只是为了生成数据源进行事务管理,而非真正的操作数据库。

properties配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root

在这里插入图片描述
在这里插入图片描述
可以看出案例成功运行。

dubbo配置文件解析

包扫描
 <!-- 扫描指定包,加入@Service注解的类会被发布为服务  -->
    <dubbo:annotation package="com.feitian.service" />

服务提供者和服务消费者都需要配置,表示包扫描,作用是扫描指定包(包括子包)下的类。如果不使用包扫描,也可以通过如下配置的方式来发布服务:

<bean id="hiPyService" class="com.feitian.service.impl.HiPyServiceImpl"/>
    <dubbo:service interface="com.feitian.service.HiPyService" ref="hiPyService"/>

相当于替代了

<dubbo:annotation package="com.feitian.service" />

作为服务消费者,可以通过如下配置来引用服务:

<dubbo:reference id="hiPyService" interface="com.feitian.service.HiPyService" />

在接口上加上@Autowired

    @Autowired
    private HiPyService hiPyService;

相当于替代了了dubbo的@Reference标签。

上面这种方式发布和引用服务,一个配置项(dubbo:service、dubbo:reference)只能发布或者引用一个服务,如果有多个服务,这种方式就比较繁琐了。推荐使用包扫描方式。

dubbo协议

一般dubbo的默认protocol为dubbo,一般建议在provider方指定协议。

<!-- 注册  协议和port   端口默认是20880 -->
    <dubbo:protocol name="dubbo" port="20881"></dubbo:protocol>

Dubbo支持的协议有:dubbo、rmi、hessian、http、webservice、rest、redis等。推荐使用的是dubbo协议。

dubbo 协议采用单一长连接和 NIO 异步通讯,适合于小数据量大并发的服务调用,以及服务消费者机器数远大于服务提供者机器数的情况。 不适合传送大数据量的服务,比如传文件,传视频等,除非请求量很低。也可以在同一个工程中配置多个协议,不同服务可以使用不同的协议,例如:

<!-- 多协议配置 -->
<dubbo:protocol name="dubbo" port="20881" />
<dubbo:protocol name="rmi" port="1099" />
<!-- 使用dubbo协议暴露服务 -->
<dubbo:service interface="com.feitian.service.HelloService" ref="helloService" protocol="dubbo" />
<!-- 使用rmi协议暴露服务 -->
<dubbo:service interface="com.feitian.service.DemoService" ref="demoService" protocol="rmi" /> 

也可以通过在注解中配置协议,指定所要的RPC协议

@Service(protocol = "rmi")
public class HiPyServiceImpl implements HiPyService {
    @Override
    public String hiPyService(String name) {
        return  "hello" + name;
    }
}
启动时检查

默认情况下 服务提供方和服务消费方启动有先后顺序,会检查对应的服务提供方有没有注册服务,若没有就会报错,这种情况就给开发者带来了困扰,所以在开发阶段建议停止检查则在服务消费方引入一下配置:

<dubbo:consumer check="false"/>

也可用 @Reference(check = false)来替代删除xml配置文件。如果不配置默认check值为true。Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,以便上线时,能及早发现问题。可以通过将check值改为false来关闭检查。

建议在开发阶段将check值设置为false,在生产环境下改为true。

负载均衡

负载均衡(Load Balance):本质上就是将请求分摊到多个操作单元上进行执行,从而共同完成工作任务。

在集群负载均衡时,Dubbo 提供了多种均衡策略(包括随机、轮询、最少活跃调用数、一致性Hash),缺省为random随机调用。

配置负载均衡策略,既可以在服务提供者一方配置,也可以在服务消费者一方配置,如下:

负载均衡小案例
服务消费方
@Controller
@RequestMapping("/hiPPyController")
public class PyController {
    @Reference(check = false,loadbalance = "random")
   /* @Autowired*/
    private HiPyService hiPyService;

    @RequestMapping("/hiPython")
    @ResponseBody
    public String hiPython(String name){
        return hiPyService.hiPyService(name);
    }
}
服务提供方
@Service(protocol = "dubbo",loadbalance="random")
/*@Service*/
@Transactional
public class HiPyServiceImpl implements HiPyService {
    @Override
    public String hiPyService(String name) {
        return  "port8081hello" + name;
    }
}

注意要修改dubbo协议端口
在这里插入图片描述
在这里插入图片描述
由此就可以是此案consumer随机调用provider提供的service。

Dubbo的发布与事务代理问题

如果在服务提供者类上加入@Transactional事务控制注解后,服务就发布不成功了。 原因是事务控制的底层原理是为服务提供者类创建代理对象,而默认情况下Spring是基于JDK动态代理方式创建代理对象,而此代理对象的完整类名为com.sun.proxy.$Proxy42(最后两位数字不是固定的),导致Dubbo在发布服务前进行包匹配时无法完成匹配,进而没有进行服务的发布。

修改案例,引入dao
在这里插入图片描述

修改dubboprovider的HiPyServiceImpl
@Service(protocol = "dubbo", loadbalance="random")
/*@Service*/
@Transactional
public class HiPyServiceImpl implements HiPyService {
    @Override
    public String hiPyService(String name) {
        return  "port8081hello" + name;
    }
}

启动provider和consummer
在这里插入图片描述
在这里插入图片描述
访问报错
在这里插入图片描述
其奥妙就在这个类中AnnotationBean这个类中。
在这里插入图片描述
dubbo对于服务的发布最终是通过AnnotationBean的postProcessAfterInitialization方法进行处理。
当以debug方式启动时,首先会进入下年的方法
在这里插入图片描述
然后会进入

在这里插入图片描述

在两种方法中都调用了下面的方法

private boolean isMatchPackage(Object bean) {
        if (this.annotationPackages != null && this.annotationPackages.length != 0) {
            String beanClassName = bean.getClass().getName();
            String[] arr$ = this.annotationPackages;
            int len$ = arr$.length;

            for(int i$ = 0; i$ < len$; ++i$) {
                String pkg = arr$[i$];
                if (beanClassName.startsWith(pkg)) {
                    return true;
                }
            }
            return false;
        } else {
            return true;
        }
    }

调试过程中发现有如下问题
在这里插入图片描述

解决问题的关键
  1. 指定cglib代理
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
  1. 指定代理接口
@Service(protocol = "dubbo", interfaceClass = HiPyService.class, loadbalance="random")
@Transactional
public class HiPyServiceImpl implements HiPyService {
    @Override
    public String hiPyService(String name) {
        return  "port8081hello" + name;
    }
}

发布成功
在这里插入图片描述
访问发信可以正常调用。

dubbo常见问题

思考一: 上面的Dubbo入门案例中我们是将HiPyService接口从服务提供者工程(dubboprovider)复制到服务消费者工程(dubboconsumer)中,这种做法是否合适?还有没有更好的方式?

答: 同一个接口被复制了两份,项目代码冗余严重,不利于后期维护。更好的方式是单独创建一个maven工程,将此接口创建在这个maven工程中。需要依赖此接口的工程只需要在自己工程的pom.xml文件中引入maven坐标即可。

思考二: 在服务消费者工程(dubboconsumer)中只是引用了HiPyService接口,并没有提供实现类,Dubbo是如何做到远程调用的?

答: Dubbo底层是基于代理技术为HiPyService接口创建代理对象,远程调用是通过此代理对象完成的。可以通过开发工具的debug功能查看此代理对象的内部结构。另外,Dubbo实现网络传输底层是基于Netty框架完成的。

思考三: 上面的Dubbo入门案例中我们使用Zookeeper作为服务注册中心,服务提供者需要将自己的服务信息注册到Zookeeper,服务消费者需要从Zookeeper订阅自己所需要的服务,此时Zookeeper服务就变得非常重要了,那如何防止Zookeeper单点故障呢?

答: Zookeeper其实是支持集群模式的,可以配置Zookeeper集群来达到Zookeeper服务的高可用,防止出现单点故障。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值