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

news2024/9/23 9:35:11

一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核心组件

在这里插入图片描述

1)注册中心(registry)

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

2)消费者(consumer)

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

3)生产者(provider)

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

4)容器(container)

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

5)监控(Monitor)

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

二.springboot+dubbo+zookeeper整合使用

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

在这里插入图片描述

进入到镜像中

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

查看zookeeper中的,服务情况
在这里插入图片描述
查看已经注册存在的服务

在这里插入图片描述

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

在这里插入图片描述

3.Providor服务提供者

在这里插入图片描述
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模块,代码省略

在这里插入图片描述
5.实体类对象模块domain,代码省略

在这里插入图片描述

6.Service服务接口,代码省略
在这里插入图片描述

7.consumer,服务消费者

在这里插入图片描述

7.0.ComsumerApplication
在这里插入图片描述

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<Product> 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>

效果截图

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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/735524.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

N天爆肝数据库——MySQL(1)

数据库概念理解 数据库 DB 存储数据的仓库 数据库管理系统 DBMS 操纵和管理数据库的大型软件 SQL 操作关系型数据库的编程语言&#xff0c;定义了用一套操作关系型数据库同意标准 学习 SQL 的作用 SQL 是一门 ANSI 的标准计算机语言&#xff0c;用来访问和操作数据库系统。S…

在北京买房究竟需要多少钱?

无论是来北京前&#xff0c;还是来北京后&#xff0c;每每提起北京的房价&#xff0c;大家都会说出三个字「买不起」。 确实&#xff0c;北京房价非常贵&#xff0c;但是究竟「贵」到什么程度&#xff0c;我们却无法说出一个数。 几年前&#xff0c;我研三还没毕业时&#xf…

Linux高频常用指令汇总

目录 认识 Linux 目录结构 绝对路径&#xff1a;以根目录开头的, 称为绝对路径 相对路径&#xff1a;不是根目录开头的,称为相对路径 ls pwd cd mkdir touch cat echo rm cp mv vim编辑器 1、进入文件 2、进行编辑模式 3、保存退出 重要的几个热键[Tab],[ct…

SpringBoot中间件——封装限流器

背景 通常能知道一个系统服务在正产增速下流量大小&#xff0c;扩容与压测也是基于此。若有突发或者恶意攻击访问&#xff0c;都要将流量拦截在外。这部分功能不属于业务侧&#xff0c;它是通用非业务的共性需求&#xff0c;所以我们将共性抽取为限流中间件。 方案设计 图解&…

基于微信小程序的高校食堂点餐系统设计与实现(Java+spring boot+MySQL+微信小程序)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于微信小程序的高校食堂点餐系统设计与实现&#xff08;Javaspring bootMySQL微信小程序&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java…

指针-->笔试题(必备)

前言&#xff1a; 目录 前言&#xff1a; 本章介绍的指针笔试题是有点难度的&#xff0c;得花费一点时间来理解&#xff0c;并且我们在做题目的时候需要画图来理解。 文章目录 笔试题1 笔试题2 笔试题3 笔试题4 笔试题5 笔试题6 笔试题7 笔试题8 笔试题1 int main() {int a[5…

uniapp下载和上传照片

利用uniapp开发的时候&#xff0c;需要下载和上传照片&#xff0c;在H5和微信小程序中的写法不一样。 H5环境下 浏览器中下载就是模拟超链接下载。也不需要获取什么权限&#xff0c;比较简单。 // #ifdef H5 this.isLoading true; let oA document.createElement("a&…

[软件工具]姓氏谐音梗随机生成工具使用教程

首先我们打开软件 输入姓氏和生成数即可开始生成&#xff0c;注意生成数可以随便填&#xff0c;软件会自动按最大数生成&#xff0c;比如你设置生成数位10000则可能只会生成500个&#xff0c;因为软件内置只有这么多。单次生成不重复&#xff0c;生成效果可以访问视频教程&…

MySQL多表查询练习

多表连接查询 use mydb3; -- 创建部门表 create table if not exists dept3( deptno varchar(20) primary key , -- 部门号 name varchar(20) -- 部门名字 );-- 创建员工表 create table if not exists emp3( eid varchar(20) primary key , -- 员工编号 ename varchar(20), --…

数仓建设中最常用模型--Kimball维度建模详解

数仓建模首推书籍《数据仓库工具箱&#xff1a;维度建模权威指南》&#xff0c;本篇文章参考此书而作。文章首发公众号&#xff1a;五分钟学大数据&#xff0c;公众号后台发送“维度建模”即可获取此书籍第三版电子书 先来介绍下此书&#xff0c;此书是基于作者 60 多年的实际业…

leetcode:174. 地下城游戏:动态规划法

174. 地下城游戏 - 力扣&#xff08;Leetcode&#xff09; 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里&#xff0c;他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初…

史上最全Windows下VScode配置大全

文章目录 1、安装Vscode下载安装配置C和中文 2、安装MinGW-w643、检查是否配置成功 1、安装Vscode 下载安装 首先先下载VSCODE&#xff1a; 链接: VScode下载 下载好安装包以后&#xff0c;直接在自己指定目录安装&#xff1a; 配置C和中文 打开VScode的左下角位置&#…

Proteus 8.13安装教程

不涉及版权问题。 1、双击“Proteus 8.13 SP0 Pro.exe”开始安装 2、按照安装向导进行操作&#xff0c;等待安装成功 1&#xff09;选择“Browse"自定义安装路径&#xff0c;再点击&#xff1a;Next 2&#xff09;点击&#xff1a;Next 3&#xff09;等待一段时间&#xf…

C#学习之路-判断

判断结构要求程序员指定一个或多个要评估或测试的条件&#xff0c;以及条件为真时要执行的语句&#xff08;必需的&#xff09;和条件为假时要执行的语句&#xff08;可选的&#xff09;。 下面是大多数编程语言中典型的判断结构的一般形式&#xff1a; 判断语句 语句描述if …

闪烁灯光门铃电路设计

闪烁灯光门铃不仅具有门铃的声音还可以通过家里的门灯发出闪烁的灯光&#xff0c;适合用于室内嘈杂环境时使用&#xff0c;也适用于有聋哑人的家庭。 一、电路工作原理 电路原理如图 30 所示。 由基本的门铃电路和灯光、声音延迟控制电路两部分组成。按下门铃按钮 SB&#x…

C语言每日一题之旋转数求最小值

hello&#xff0c;今天我们分享一道题目&#xff0c;是牛客网上的一道题 求旋转数组中的最小值https://www.nowcoder.com/practice/9f3231a991af4f55b95579b44b7a01ba?tpId13&tqId23269&ru/ta/coding-interviews&qru/ta/coding-interviews/question-ranking 那我…

创新指南 | 用这8种商业分析模型,让你得到靠谱的业务创新灵感

当我们想要创新时&#xff0c;往往需要有实际的依据来支撑我们的想法。商业咨询顾问通常被认为是聪明的人&#xff0c;他们拥有模型化的分析思维&#xff0c;这种思维方式可以帮助他们更好地理解市场、竞争对手和客户需求。商业分析思维是一种系统性的思考方式&#xff0c;它可…

P1 第一章 电路模型与电路定律

1、什么是电路模型&#xff1f; 实际电路与电路模型间的关系&#xff1f;建立在相同的电路理论基础之上。 实际电路定义&#xff1a;由电工设备和电气器件&#xff0c;按照预期目的连接构成的&#xff0c;电流的通路。 实际电路的功能&#xff1a;能量方面&#xff0c;可以传输…

【计算机网络】第三章 数据链路层(MAC地址 IP地址 ARP协议)

文章目录 3.7.1 MAC地址3.7.2 IP地址3.7.3 ARP协议 3.7.1 MAC地址 MAC地址&#xff08;Media Access Control address&#xff09;是网络设备&#xff08;如网卡、无线网卡&#xff09;在数据链路层上的唯一标识符。以下是有关MAC地址的一些要点&#xff1a; 描述&#xff1a…

超详细,Jmeter性能测试-模拟100个用户并发(实战)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 100个真实的用户 …