SpringCloudAlibaba技术栈-Dubbo

embedded/2024/12/27 7:09:37/

1、什么是Dubbo?

简单来说,dubbo就像是个看不见的手,负责专门从注册中心nacos调用注册到nacos上面的服务的,因为在微服务环境下不同的功能模块可能在不同的服务器上。dubbo调用服务就像是在调用本地的服务一样。

分布式调用与高并发处理 Dubbo分布式调用_分布式之间的调用-CSDN博客

2、Dubbo实现

(1)创建父项目

添加相关依赖

<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.zj</groupId><artifactId>Dubbo_demo2</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>Dubbo_demo2</name><url>http://maven.apache.org</url><properties><dubbo.version>3.2.4</dubbo.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>17</java.version><spring-boot.version>3.0.2</spring-boot.version><spring-cloud.version>2022.0.0</spring-cloud.version><spring-cloud-alibaba.version>2022.0.0.0</spring-cloud-alibaba.version><lombok.version>1.8.28</lombok.version></properties><dependencyManagement><dependencies><!-- SpringCloud 微服务 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency><!-- SpringCloud Alibaba 微服务 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${spring-cloud-alibaba.version}</version><type>pom</type><scope>import</scope></dependency><!-- SpringBoot 依赖配置 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><!-- lombok 依赖配置 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>${lombok.version}}</version></dependency><!-- Dubbo --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-bom</artifactId><version>${dubbo.version}</version><type>pom</type><scope>import</scope></dependency><!-- bootstrap 启动器 --><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope></dependency></dependencies></dependencyManagement></project>

(2)创建子模块interface

添加下面的依赖文件,为啥要添加mybatis依赖呢?因为有些时候需要指定实体类对应的表和实体类和表字段之间的对应关系等。lombok就是为了生成实体类的get\set等方法。

        <!-- Mybatis plus 依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.1.0</version></dependency><!--lombok依赖--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.28</version></dependency>

在test数据库创建User表

create database test;
CREATE TABLE user(id 
BIGINT(20) NOT NULL COMMENT '主键ID',name VARCHAR(30) NULL DEFAULT NULL COMMENT 
'姓名',age INT(11) NULL DEFAULT NULL COMMENT '年
龄',PRIMARY KEY (id));

在interface下创建User实体类

java">@TableName("user")
@Data
public class User {private Long id;private String name;private Integer age;
}

创建结果集

java">package com.zj.common;import java.io.Serializable;/*结果集*/
/*实现序列化因为dubbo传输的是二进制数据*/
public class CommonResult<T> implements Serializable {private Integer code;
private String msg;
private T data;}

创建IUserService接口

java">package com.zj.service;import com.zj.common.CommonResult;
import com.zj.pojo.User;/*用户接口*/
public interface IUserService {CommonResult<User> createUser(User user);CommonResult<User> findAllUser(User user);CommonResult<User> updateUser(User user);CommonResult<User> deleteUser(Long id);}

(3)创建子模块user-service

这个模块就是对用户业务的具体实现,这里面的业务是需要注册到nacos上面的。

添加依赖文件

    <dependencies><!--springboot依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--dubbo整合spring boot的依赖包--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId></dependency><!--dubbo注册到nacos上的依赖包--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-registry-nacos</artifactId></dependency><!-- Mybatis plus 依赖 --><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.7</version></dependency><!--MySQL 数据库依赖 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.49</version></dependency><!--接口的依赖--><dependency><groupId>com.zj</groupId><artifactId>1interface</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>

创建mapper层获取数据库的数据。

java">package com.zj.mapepr;import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.zj.pojo.User;public interface UserMapper extends BaseMapper<User> {}

别忘了在启动类上添加上这三个注解。

java">@EnableDubbo
@MapperScan("com.zj.mapper")
@SpringBootApplication
public class userService
{public static void main( String[] args ){SpringApplication.run(userService.class, args);}
}

 @EnableDubbo注解是使用Dubbo进行服务化开发的关键注解,它使得Spring Boot应用能够方便地集成和使用Dubbo框架提供的分布式服务能力。

当你将这个注解添加到你的Spring Boot应用的配置类上时,它会做以下几件事情:

  1. 开启Dubbo自动配置:它会触发Spring Boot的自动配置机制,自动配置Dubbo相关的Bean。

  2. 服务暴露:在Spring容器中,标注了@Service(注意这里不是Spring的@Service,而是Dubbo的@Service注解)的类会被识别为Dubbo服务,并且会被注册到注册中心(比如Zookeeper),从而可以被其他服务发现和调用。

  3. 服务引用:它允许你的应用通过Dubbo去引用其他服务。通常是通过@Reference注解来注入其他Dubbo服务。

  4. 配置加载:它会加载Dubbo相关的配置,这些配置可以是写在application.propertiesapplication.yml文件中,也可以是通过其他方式定义的Dubbo配置类。

  5. 依赖注入:它支持将Dubbo的Reference(服务引用)注入到Spring管理的Bean中,使得远程服务调用就像调用本地方法一样简单。

  6. 服务监控@EnableDubbo还负责集成Dubbo的监控功能,比如可以通过配置将服务的调用次数、调用时间等信息发送到监控中心。

创建service层实现IUserService接口,并将该业务注册到nacos上。

java">package com.zj.service;import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.zj.common.CommonResult;
import com.zj.mapper.UserMapper;
import com.zj.pojo.User;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;import java.util.List;/*用户的业务层*/
@DubboService   //将该业务发布到注册中心nacos
public class UserServiceImpl implements IUserService{@Autowiredprivate UserMapper userMapper;/*添加用户*/@Overridepublic CommonResult<User> createUser(User user) {CommonResult<User> userCommonResult = new CommonResult<>();int insert = userMapper.insert(user);if(insert > 0){userCommonResult.setCode(200);  //结果的编码userCommonResult.setMsg("success");  //结果的描述}else {userCommonResult.setCode(500);userCommonResult.setMsg("fail");}return userCommonResult;}/*查询用户,这个地方不能加泛型*/@Overridepublic CommonResult findAllUser(User user) {CommonResult userCommonResult = new CommonResult<>();//查询条件构造器LambdaQueryWrapper<User> lqw = new LambdaQueryWrapper<>();//id不为空的话使用id查询lqw.eq(user.getId() != null,User::getId,user.getId());//name不为空的话使用id查询lqw.eq(user.getName() != null,User::getName,user.getName());//age不为空的话使用id查询lqw.eq(user.getAge() != null,User::getAge,user.getAge());//查询用户List<User> users = userMapper.selectList(lqw);userCommonResult.setCode(200);userCommonResult.setMsg("success");userCommonResult.setData(users);return userCommonResult;}//更新用户@Overridepublic CommonResult updateUser(User user) {CommonResult userCommonResult = new CommonResult<>();if(user.getId() == null){userCommonResult.setCode(500);userCommonResult.setMsg("id = null");return userCommonResult;}/*条件构造器*/LambdaUpdateWrapper<User> lqw = new LambdaUpdateWrapper<>();lqw.set(user.getName() != null, User::getName, user.getName()).set(user.getAge() != null, User::getAge, user.getAge()).eq(User::getId, user.getId());//更新int update = userMapper.update(null, lqw);if(update > 0){userCommonResult.setCode(200);userCommonResult.setMsg("success");}else {userCommonResult.setCode(500);userCommonResult.setMsg("fail");}return userCommonResult;}//删除@Overridepublic CommonResult<User> deleteUser(Long idr) {CommonResult<User> userCommonResult = new CommonResult<>();if(idr == null){userCommonResult.setCode(500);userCommonResult.setMsg("id = null");return userCommonResult;}int i = userMapper.deleteById(idr);if(i > 0){userCommonResult.setCode(200);userCommonResult.setMsg("success");}else {userCommonResult.setCode(500);userCommonResult.setMsg("fail");}return userCommonResult;}}

需要注意的是查询全部的用户的时候不能写泛型,因为查询出来的不是User而是个List。 

创建user-service模块的配置文件application.yml文件

java">dubbo:application:
#    项目名称name: user-service
#    通讯协议protocol:name: dubbo
#    端口号 设置端口为 -1 表示 dubbo 自动扫描并使用可用端口(从20880开始递增),避免了端口冲突的问题。port: -1registry:
#    服务的注册地址address: nacos://192.168.66.100:8848server:port: 8001#配置数据源
spring:datasource:driver-class-name: com.mysql.jdbc.Driverurl: jdbc:mysql://192.168.66.100:3306/test?serverTimezone=UTCusername: rootpassword: 123456

 (4)服务接口测试

启动user-service模块

创建测试项目,使apifox测试,选择Dubbo类型的项目。

 导入接口数据,注意导入的是nacos的数据。

(5)创建消费者模块

导入消费者模块的依赖

 <dependencies><!--thymeleaf--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><!--springboot依赖--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--dubbo整合spring boot的依赖包--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId></dependency><!--dubbo注册到nacos上的依赖包--><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-registry-nacos</artifactId></dependency><!--这个不能忘记,因为在消费者模块中也就是consume中需要使用userService模块的服务--><dependency><groupId>com.zj</groupId><artifactId>1interface</artifactId><version>1.0-SNAPSHOT</version></dependency></dependencies>

添加配置文件。

消费者也是需要调用nacos中的服务的因此也需要将服务注册到nacos上。因此需要添加下面的配置,除此之外还需要添加Thymeleaf的配置。

spring-boot很多配置都有默认配置,比如默认页面映射路径为:classpath:/templates/*.html

同样静态文件路径为:classpath:/static/
 

thymeleaf是前端的页面因此这里创建子模块是consume是专门消费服务的,也就是前台发请求显示页面的模块。

在consume 模块的resource目录下创建template文件夹和static文件夹。

dubbo:application:name: consume-serviceprotocol:name: dubboregistry:address: nacos://192.168.66.100:8848
server:port: 8002spring:thymeleaf:cache: falsemode: HTML5encoding: utf-8content-type: text/html

在templates下面创建视图页面。

首页

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>首页</title>
</head>
<body><a href="/addUser">添加用户</a>
<a href="/user/showUser">查询用户</a></body>
</html>

添加用户

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>添加用户</title>
</head>
<body><form action="/user/addUser" method="post"><input type="hidden" name="id" value="0">用户名字:<input type="text" name="name" placeholder="请输入名字">用户年龄:<input type="text" name="age" placeholder="请输入年龄"><input type="submit" value="添加用户">
</form></body>
</html>>

OK页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<link rel="shortcut icon" href="../resources/favicon.ico" th:href="@{/static/favicon.ico}"/>
<head><meta charset="UTF-8"><title>成功页面</title>
</head>
<body>
操作成功请<a href="/index">返回</a>
</body>
</html>

error页面

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
执行失败<a href="/index">返回</a>
</body>
</html>

显示用户信息

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>查询用户</title>
</head>
<body><table><tr><td>序号</td><td>名字</td><td>用户年龄</td><td>操作</td></tr><tr th:each="u : ${users}"><td th:text="${u.id}"></td><td th:text="${u.name}"></td><td th:text="${u.age}"></td><td><a th:href="@{/user/delete(id=${u.id})}">删除</a><a th:href="@{/user/toUpdate(id=${u.id})}">更新</a></td></tr>
</table></body>
</html>

更新用户页面。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head><meta charset="UTF-8"><title>更新用户</title>
</head>
<body><form action="/user/update" method="post"><input type="hidden" name="id" th:value="${user.id}">用户名字:<input type="text" name="name" placeholder="请输入名字" th:value="${user.name}">用户年龄:<input type="text" name="age" placeholder="请输入年龄" th:value="${user.age}"><input type="submit" value="更新用户">
</form>
</body>
</html>

然后创建两个controller,一个负责页面跳转的。

java">package com.zj.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;/*视图层控制器*/
@Controller
public class IndexController {/*页面跳转*/@GetMapping("/{page}")public String index(@PathVariable String page) {return page;}/*忽略favicon*/@GetMapping("favicon.ico")@ResponseBodyvoid noFavicon() {}}

 一个负责处理具体的业务请求的。

java">package com.zj.controller;import com.zj.common.CommonResult;
import com.zj.pojo.User;
import com.zj.service.IUserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.DeleteMapping;
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.servlet.ModelAndView;import java.util.List;@Controller
@RequestMapping("/user")
public class UserController {//远程调用添加用户的操作,添加用户的服务是user-service模块提供的,需要注意的是要引入interface模块依赖@DubboReferenceprivate IUserService userService;/*添加用户*/@PostMapping("/addUser")public String addUser(User user){CommonResult<User> result = userService.createUser(user);//判断是不是添加成功if (result.getCode() == 200){return "redirect:/ok";}else {return "redirect:/error";}}/*查询用户*/@GetMapping("/showUser")public ModelAndView selectUser(){//既要返回视图还需要返回结果ModelAndView modelAndView = new ModelAndView();User user1 = new User();CommonResult<User> allUser = userService.findAllUser(user1);//视图添加数据modelAndView.addObject("users",allUser.getData());//返回视图modelAndView.setViewName("showUser");return modelAndView;}/*根据id查询数据跳转到更新数据的页面*/@GetMapping("/toUpdate")public ModelAndView toUpdateUser(Long id){ModelAndView modelAndView = new ModelAndView();User user = new User();user.setId(id);CommonResult allUser = userService.findAllUser(user);List<User> data = (List<User>)allUser.getData();if (data.size() > 0){modelAndView.addObject("user",data.get(0));  //取出第一个数据modelAndView.setViewName("update");}return modelAndView;}/*更新用户*/@PostMapping("/update")public String updateUser(User user){System.out.println("user:"+user);CommonResult<User> userCommonResult = userService.updateUser(user);if (userCommonResult.getCode() == 200){return "redirect:/ok";}else{return "redirect:/error";}}/*删除用户*/@GetMapping("/delete")public String deleteUser(Long id){CommonResult<User> userCommonResult = userService.deleteUser(id);if (userCommonResult.getCode() == 200){return "redirect:/ok";}else {return "redirect:/error";}}
}

需要注意的就是这个@DubboReference注解,就是获取nacos的服务实例,注入到userService变量中。

另外根据id查询用户的时候需要注意的是查询结果是个List所以取出第一个来。

最后启动类加注解。

java">/*告诉 Spring Boot 不要自动配置数据源。使用我配置的数据源。*/
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@EnableDubbo
public class userConsume
{public static void main( String[] args ){SpringApplication.run(userConsume.class, args);}
}

 @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})第一次碰到这个注解,不叫的话会出错。

最后是配置文件。

java">dubbo:application:name: consume-serviceprotocol:name: dubboregistry:address: nacos://192.168.66.100:8848
server:port: 8002#配置视图
spring:thymeleaf:cache: falsemode: HTML5encoding: utf-8content-type: text/html

最后启动user-service模块和user-consum模块,在浏览器输入locahost:8082/index就行啦。

详细的项目代码已经上传。


http://www.ppmy.cn/embedded/149116.html

相关文章

在算力魔方上运行Genesis:一款颠覆性开源生成式物理引擎!

作者&#xff1a;算力魔方创始人 刘力 一&#xff0c;Genesis简介 Genesis是一款由19个顶尖科研机构联手打造的&#xff0c;用于通用机器人、具身智能和物理 AI 应用的开源生成式物理引擎。它可以生成整个世界&#xff0c;包括相机运动、机器人任务和交互式 3D 场景等。其特点有…

电脑出现 0x0000007f 蓝屏问题怎么办,参考以下方法尝试解决

电脑蓝屏是让许多用户头疼的问题&#xff0c;其中出现 “0x0000007f” 错误代码更是较为常见且棘手。了解其背后成因并掌握修复方法&#xff0c;能帮我们快速恢复电脑正常运行。 一、可能的硬件原因 内存问题 内存条长时间使用可能出现物理损坏&#xff0c;如金手指氧化、芯片…

【ue5学习笔记2】在场景放入一个物体的蓝图输入事件无效?

在场景放入一个物体的蓝图输入事件无效&#xff0c;那是因为你不知道gameMode这个东西这是一个用于设定游戏股则的东西&#xff0c; 就好比你的控制对象&#xff0c;你输入无效是没有指定你当前关卡中指定的控制对象是它。操作方法如下&#xff1a; 1.创建一个gameMode蓝图类并…

嵌入式学习-QT-Day04

嵌入式学习-QT-Day04 四、基本组件 1、Designer设计师 2、布局Layout 3、QWidget类 4、界面文件与C代码的关系 5、QLabel标签 5.1 基本属性 5.2 添加资源库 5.3 使用资源库 5.4 使用代码添加图片 5.5 使用代码添加动态图 6、QAbstractButton按钮类 7、QLineEdit 单行文本输入框…

使用Docker启动Linux Riscv版

目标&#xff1a;使用Docker启动Linux Riscv版 以前主要是使用qemu来启动RISCV系统&#xff0c;比如在Linux和FreeBSD系统下&#xff0c;都可以安装QEMU&#xff0c;然后用QEMU仿真RISCV环境。 这回&#xff0c;就用Docker来启动RISCV系统。跟qemu相比&#xff0c;Docker更加…

使用驱动器光盘需格式化:深度解析与数据恢复全攻略

一、驱动器光盘需格式化的现象概述 在日常使用驱动器光盘的过程中&#xff0c;用户可能会遇到系统提示“驱动器中的磁盘未被格式化&#xff0c;是否现在格式化&#xff1f;”的警告。这一提示通常意味着光盘上的文件系统已损坏或无法被系统正常识别&#xff0c;导致无法读取光…

《Eclipse 创建 Java 项目》

《Eclipse 创建 Java 项目》 介绍 Eclipse 是一个流行的集成开发环境&#xff08;IDE&#xff09;&#xff0c;广泛用于 Java 应用程序的开发。在本教程中&#xff0c;我们将逐步介绍如何在 Eclipse 中创建一个新的 Java 项目&#xff0c;以及如何配置和运行该项目。 先决条…

Docker服务发现新纪元:探索Consul的无限魅力

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 •座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元个人主页&#xff1a;团儿.-CSDN博客 目录 前言&…