Dubbo分布式服务框架,springboot+dubbo+zookeeper

一Dubbo的简易介绍

1.Dubbo是什么?

Dubbo是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。

简单的说,dubbo就是个服务框架,如果没有分布式的需求,其实是不需要用的,只有在分布式的时候,才有dubbo这样的分布式服务框架的需求,并且本质上是个服务调用的东西,说白了就是个远程服务调用的分布式框架(告别Web Service模式中的WSdl,以服务者与消费者的方式在dubbo上注册)。

其核心部分包含:

1. 远程通讯:

提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。

2. 集群容错:

提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。

3. 自动发现

基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。

2.Dubbo能做什么?

1.透明化的远程方法调用

就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。

2.软负载均衡及容错机制

可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3. 服务自动注册与发现

不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。

Dubbo采用全spring配置方式,透明化接入应用,对应用没有任何API侵入,只需用Spring加载Dubbo的配置即可,Dubbo基于Spring的Schema扩展进行加载。

3.Dubbo核心组件

Dubbo分布式服务框架,springboot+dubbo+zookeeper_第1张图片

1)注册中心(registry)

生产者在此注册并发布内容,消费者在此订阅并接收发布的内容。

2)消费者(consumer)

客户端,从注册中心获取到方法,可以调用生产者中的方法。

3)生产者(provider)

服务端,生产内容,生产前需要依赖容器(先启动容器)。

4)容器(container)

生产者在启动执行的时候,必须依赖容器才能正常启动(默认依赖的是spring容器),

5)监控(Monitor)

统计服务的调用次数与时间等。

二.springboot+dubbo+zookeeper整合使用

1.在Linux中安装zookeeper实现服务注册

在这里插入图片描述

进入到镜像中

[root ~]# docker exec -it 46c8d188683b bash

查看zookeeper中的,服务情况
Dubbo分布式服务框架,springboot+dubbo+zookeeper_第2张图片
查看已经注册存在的服务

在这里插入图片描述

2.服务层中service,使用dubbo中的@Service注解

Dubbo分布式服务框架,springboot+dubbo+zookeeper_第3张图片

3.Providor服务提供者

Dubbo分布式服务框架,springboot+dubbo+zookeeper_第4张图片
3.0.application.yml

dubbo:
  provider:
    application: dubbo-provider
  registry:
    address: zookeeper://192.168.58.128:2181
  scan:
    base-packages:
      - com.tjetc.service
  protocol:
    name: dubbo #使用dubbo协议
    port: 20880 #协议端口为20880
server:
  port: 8081
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://192.168.58.128:3306/springboot?serverTimezone=GMT%2B8
    username: root
    password: root
mybatis:
  type-aliases-package: com.tjetc.domain
logging:
  level:
    com.tjetc.mapper: debug

3.1.ProvidorApplication

import com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


//开启dubbo服务注册

("com.tjetc.mapper")
public class ProvidorApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProvidorApplication.class, args);
    }

}

3.2.ProductServiceImpl,@Service使用dubbo中的注解

import com.alibaba.dubbo.config.annotation.Service;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.tjetc.domain.Product;
import com.tjetc.mapper.ProductMapper;
import com.tjetc.service.ProductService;
import org.springframework.stereotype.Component;


import javax.annotation.Resource;
import java.util.List;


public class ProductServiceImpl implements ProductService {

    
    private ProductMapper productMapper;
    
    public void add(Product product) {
        productMapper.add(product);
    }

    
    public PageInfo<Product> list(String name, Integer pageNum, Integer pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        List<Product> list=productMapper.list(name);
        PageInfo<Product> pageInfo = new PageInfo<>(list);
        System.out.println("pageInfo.getList() = " + pageInfo.getList());
        return pageInfo;
    }

    
    public List<Product> listByName(String name) {
        return productMapper.listByName(name);
    }

    
    public Product findById(Integer id) {
        return productMapper.findById(id);
    }

    
    public void update(Product product) {
        productMapper.update(product);
    }

    
    public int del(Integer id) {
        return productMapper.del(id);
    }
}

4.mapper模块,代码省略

Dubbo分布式服务框架,springboot+dubbo+zookeeper_第5张图片
5.实体类对象模块domain,代码省略

Dubbo分布式服务框架,springboot+dubbo+zookeeper_第6张图片

6.Service服务接口,代码省略
Dubbo分布式服务框架,springboot+dubbo+zookeeper_第7张图片

7.consumer,服务消费者

Dubbo分布式服务框架,springboot+dubbo+zookeeper_第8张图片

7.0.ComsumerApplication
Dubbo分布式服务框架,springboot+dubbo+zookeeper_第9张图片

7.1.ProductController

import com.alibaba.dubbo.config.annotation.Reference;
import com.github.pagehelper.PageInfo;
import com.tjetc.domain.Product;
import com.tjetc.service.ProductService;
import com.tjetc.utils.FastDfsClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;



import java.io.IOException;
import java.util.List;


("/product")
public class ProductController {

    ("${fastdfs}")
    private String fastdfs;

    
    private ProductService productService;


    ("/add")
    public String add(){
        return "add";
    }
    ("/add")
    public String add(Product product, MultipartFile photo){
        System.out.println("photo = " + photo);
        System.out.println("product = " + product);
        if (photo!=null && photo.getSize()>0){
            String filename = photo.getOriginalFilename();
            String extName = filename.substring(filename.lastIndexOf(".")+1);
            FastDfsClient fastDfsClient = new FastDfsClient("classpath:client.properties");
            try {
                //7. 显示上传的结果(file_id 也就是文件的路径)
                String path = fastDfsClient.upload(photo.getBytes(), extName);
                System.out.println("path = " + path);
                product.setPhotopath(fastdfs+path);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        System.out.println("product = " + product);
        productService.add(product);

        return "redirect:/product/list";
    }

    ("/list")
    public String list((defaultValue = "") String name,
                       (defaultValue = "1") Integer pageNum,
                       (defaultValue = "3") Integer pageSize, Model model){

        System.out.println(productService);
        PageInfo<Product> pageInfo=productService.list(name,pageNum,pageSize);
        List<Product> list = pageInfo.getList();
        for (Product product : list) {
            System.out.println("product = " + product);
        }
        /*List list = productService.listByName(name);
        System.out.println("list = " + list);*/
        model.addAttribute("page",pageInfo);
        model.addAttribute("list",list);
        model.addAttribute("name",name);
        return "list";
    }

    ("/findById")
    public String findById(Integer id,Model model){
        Product product=productService.findById(id);
        model.addAttribute("p",product);
        return "update";
    }

    ("/update")
    public String update(Product product,MultipartFile photo){
        if (photo!=null && photo.getSize()>0){
            String fileName=photo.getOriginalFilename();
            String extName=fileName.substring(fileName.lastIndexOf(".")+1);
            FastDfsClient fastDfsClient = new FastDfsClient("classpath:client.properties");
            try {
                String path = fastDfsClient.upload(photo.getBytes(), extName);
                product.setPhotopath(fastdfs+path);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        productService.update(product);
        return "redirect:/product/list";
    }
    ("/del")
    public String del(Integer id){
        int i=productService.del(id);
        return "redirect:/product/list";
    }


}

7.2.FastDfsClient集合文件系统工具类

import org.csource.common.MyException;
import org.csource.common.NameValuePair;
import org.csource.fastdfs.*;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

/**
 * FastDFS上传文件的工具类
 */
public class FastDfsClient {
    //声明4个成员变量
    private TrackerClient trackerClient=null;
    private TrackerServer trackerServer=null;

    // 4. 声明存储服务端storage
    private StorageServer storageServer=null;
    private StorageClient1 storageClient=null;

    /*
     * 根据配置文件初始化4个成员变量
     * */
    public FastDfsClient(String config) {
        Properties properties = new Properties();
        if (config.contains("classpath:")) {
            try {
                config=config.replaceAll("classpath:","");
                System.out.println("config = " + config);
                // 使用ClassLoader加载properties配置文件生成对应的输入流
                InputStream in = this.getClass().getClassLoader().getResourceAsStream(config);
                // 使用properties对象加载输入流
                properties.load(in);
                System.out.println("properties = " + properties);

                // 1. 加载配置文件
                ClientGlobal.initByProperties(properties);

            } catch (IOException e) {
                e.printStackTrace();
            } catch (MyException e) {
                e.printStackTrace();
            }
        }else {
            try {
                ClientGlobal.initByProperties(config);
            } catch (IOException e) {
                e.printStackTrace();
            } catch (MyException e) {
                e.printStackTrace();
            }
        }

        // 2. 创建tracker的客户端
        this.trackerClient = new TrackerClient();
        try {
            // 3. 通过客户端得到服务端连接对象
            this.trackerServer = trackerClient.getConnection();
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 5. 获取存储服务器的storage客户端对象
        this.storageClient = new StorageClient1(trackerServer, storageServer);
    }
    public FastDfsClient() {
    }
    public String upload(String filename, String extName, NameValuePair[] metas){
        try {
            return storageClient.upload_file1(filename, extName, metas);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
        }
        return null;
    }
    public String upload(String filename,String exName){
        return this.upload(filename, exName,null);
    }

    /**
     * *根据文件的内容上传*
     * @paramcontent文件内容byte[]*
     * @paramextName文件扩展名
     * *@parammetas参数*@return
     */
    public String upload(byte[] content,String extNAme,NameValuePair[] metas){
        try {
            return storageClient.upload_file1(content, extNAme, metas);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (MyException e) {
            e.printStackTrace();
        }
        return null;
    }
    public String upload(byte[] content,String extName){
        return this.upload(content, extName,null);

    }

    public static void main(String[] args) {

        // 外部普通类

        System.out.println("方法名 类名");

        System.out.println("getName " + FastDfsClient.class.getName());

        System.out.println("getCanonicalName " + FastDfsClient.class.getCanonicalName());

        System.out.println("getSimpleName " + FastDfsClient.class.getSimpleName());

        System.out.println();


        //用代码实现:得到类路径的真实路径
        String path = FastDfsClient.class.getClassLoader().getResource("").getPath();
        System.out.println("path = " + path);
    }

}

7.3.client.properties

fastdfs.tracker_servers=192.168.58.128:22122

7.4.application.yml

fastdfs: http://192.168.58.128/
dubbo:
  application:
    name: dubbo-consumer
  registry:
    address: zookeeper://192.168.58.128:2181
  protocol:
    name: dubbo #使用dubbo协议
    port: 20880 #协议端口为20880

server:
  port: 8082
spring:
  servlet:
    multipart:
      # 设置 上传文件的大小
      max-file-size: 20MB
      # 设置 整个请求的大小
      max-request-size: 20MB

7.5.list.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style type="text/css">
        table{
            width: 700px;
            border-collapse: collapse;
            text-align: center;
        }
        th,td{
            border: 1px solid #CCCCCC;
        }
    </style>
    <script type="text/javascript">
        function fenye(pageNum) {
            alert(document.getElementById("pageSize").value)
            location.href="/product/list?pageNum="+pageNum+"&name="+document.getElementById("name").value;
        }
        function findById(id) {
            location.href="/product/findById?id="+id;
        }
        function del(id) {
            location.href="/product/del?id="+id;
        }
    </script>
</head>
<body>
<div>
    <input type="text" id="name" th:value="${name}" placeholder="请输入商品名称">
    <button th:onclick="fenye(1)">查询</button>
</div>
<table>
    <tr>
        <th>编号</th>
        <th>名称</th>
        <th>单价</th>
        <th>时间</th>
        <th>美照</th>
        <th>操作</th>
    </tr>
    <tr th:each="p:${list}">
        <td th:text="${p.id}"></td>
        <td th:text="${p.name}"></td>
        <td th:text="${p.price}"></td>
        <td th:text="${#dates.format(p.time)}"></td>
        <td>
            <img th:src="${p.photopath}" width="100px">
        </td>
        <td>
            <button th:onclick="|findById(${p.id})|">编辑</button>
            <button th:onclick="|del(${p.id})|">删除</button>
        </td>
    </tr>
    <tr>
        <td colspan="10">
            <button th:onclick="|fenye(1)|">首页</button>
            <button th:onclick="|fenye(${page.prePage})|">上一页</button>
            当前页<span th:text="${page.pageNum}"></span>/<span th:text="${page.pages}"></span>
            <button th:onclick="|fenye(${page.nextPage})|">下一页</button>
            <button th:onclick="|fenye(${page.pages})|">尾页</button>
            每页<select id="pageSize" th:onclick="fenye(1)">
                <option value="3">3</option>
                <option value="6">6</option>
                <option value="9">9</option>
            </select>条数据
            总记录数:<span th:text="${page.total}"></span>
        </td>
    </tr>
</table>
</body>
</html>

效果截图

Dubbo分布式服务框架,springboot+dubbo+zookeeper_第10张图片
Dubbo分布式服务框架,springboot+dubbo+zookeeper_第11张图片

Dubbo分布式服务框架,springboot+dubbo+zookeeper_第12张图片

你可能感兴趣的:(java-zookeeper,dubbo,spring,boot)