Dubbo
目录
引入相关依赖(dubbo、zookeeper、Dubbo_api)
编写service层代码(这里的@Service就是Spring的注解)
编写PageController(该控制层的作用就是跳转到对应页面)
部分图片来自百战尚学堂
什么是分布式系统
分布式就是很多“人”一起干不一样的事,合起来就是一件大事,意思就是一个大的业务系统,拆分成一个个小的业务模块,分别部署到不同的机器上
优点:解耦,代码复用性更高,独立部署,独立测试
单机架构、集群架构、分布式架构
单机架构就是一个“人”干所有事,集群架构就是多个“人”干相同的事,分布式架构就是不同的“人”干不同的事,但是合起来就是在干一件大事
单机架构的缺点就是当这个“人”出了一些故障,那么整个系统都将崩溃,代码耦合度较高,复用性不高,测试起来复杂。优点就是体系小,开发快,集群架构也是类似的
分布式架构的优点就是代码耦合度低,没有单点故障问题,一个“人”出错了,并不会影响其他“人”,代码复用性高,测试方便。缺点就是会导致体系变得庞大
Dubbo的概念
Dubbo是一个RPC框架,作用就是让远程调用像本地调用一样简单、方便,通常使用Zookeeper Dubbo实现分布式系统
什么是RPC:RPC让你用别人家的东西就像自己家的一样。
RPC两个作用:
- 屏蔽远程调用跟本地调用的区别,让我们感觉就是调用项目内的方法
- 隐藏底层网络通信的复杂性,让我们更加专注业务逻辑。
常用的RPC框架
RPC是一种技术思想而非一种规范或协议。
常见 RPC 技术和框架:
- 阿里的 Dubbo/Dubbox、Google gRPC、Spring Cloud。
Dubbo的核心组件
注册中心Registry
在Dubbo微服务体系中,注册中心是其核心组件之一。Dubbo通过注册中心实现了分布式环境中各服务之间的注册与发现,是各个分布式节点之间的纽带。
其主要作用如下:
- 动态加入:一个服务提供者通过注册中心可以动态地把自己暴露给其他消费者,无须消费者逐个去更新配置文件。
- 动态发现:一个消费者可以动态地感知新的配置、路由规则和新的服务提供者,无须重启服务使之生效。
- 动态调整:注册中心支持参数的动态调整,新参数自动更新到所有相关服务节点。
- 统一配置:避免了本地配置导致每个服务的配置不一致问题。
服务提供者Provider
服务的提供方
服务消费者Consumer
调用远程服务的服务消费方
监控中心Monitor
主要负责监控统计调用次数和调用时间等。
Dubbo的常用注解
@Service、@Reference
@Service:将类注册到注册中心
@Reference:将类从注册中心拉取到本地
Dubbo的高级特性
高级特性其实就是@Service、@Reference注解的一些属性
序列化特性安全
网络传输数据都是以二进制的形式进行传输的,但调用方请求的出入参数都是对象,此时就需要这些对象实现了Serializable方法,即可序列化,这样才能在网络中传输
打个比方:就像送快递一样,你的货物就相当于那个对象,货物需要打包相当于对象需要序列化为二进制,当对象到你手上的时候就是一串二进制,就像快递包到了你手上一样,此时就需要拆开快递包即可拿到自己的货物,就相当于反序列化一样将二进制变回对象
地址缓存
注册中心挂了,服务是否可以正常访问?
答案:
因为dubbo服务消费者在第一次调用时,会将服务提供方地址缓存到本地,以后在调用则不会访问注册中心。服务提供者地址发生变化时,注册中心会通服务消费者。
超时机制
问题:
- 服务消费者在调用服务提供者的时候发生了阻塞、等待的情形,这个时候,服务消费者会一直等待下去。
- 在某个峰值时刻,大呈的请求都在同时请求服务消费者,会造成线程的大呈堆积,势必会造成雪崩。
- dubbo利用超时机制来解决这个问题,设置一个超时时间,在这个时间段内,无法完成服务访问,则自动断开连接。
服务生产者端配置超时时间
使用timeout属性配置超时时间,默认值1000,单位毫秒。
@Service(timeout = 3000) //当前服务3秒超时
消费端配置超时时间
@Reference(timeout=2000)// 远程注入
private IOrderService iOrderService;
重试机制
超时问题:
如果出现网络抖动,则会出现请求失败。
如何解决
Dubbo提供重试机制来避免类似问题的发生。
重试机制配置
@Service(timeout = 3000,retries = 2)
多版本灰度发布
Dubbo提供多版本的配置,方便我们做服务的灰度发布,或者是解决不兼容的问题。
灰度发布(金丝雀发布):
当出现新功能时,会让一部分用户先使用新功能,用户反馈没问题时,再将所有用户迁移到新功能。
版本迁移步骤
- 在低压力时间段,先升级一半提供者为新版本
- 再将所有消费者升级为新版本
- 然后将剩下的一半提供者升级为新版本
多版本配置
老版本服务提供者配置
@Service(version = "1.0.0") 设置版本为1.0
新版本服务提供者配置
@Service(version = "2.0.0") 设置版本为2.0
新版本服务消费者配置
@Reference(version="2.0.0") 代表拉取的是2.0版本的该对象
private IOrderService iOrderService;// 订单服务
如果不需要区分版本,可以按照以下的方式配置 :
@Reference(version="*")
private IOrderService iOrderService;// 订单服务
负载均衡
Dubbo是一个分布式服务框架,能避免单点故障和支持服务的横向扩容。一个服务通常会部署多个实例。
问题:
订单服务生产者会出现单点故障。
如何从多个服务 Provider 组成的集群中挑选出一个进行调用,就涉及到一个负载均衡的策略。
Dubbo内置负载均衡策略
- RandomLoadBalance:随机负载均衡,随机的选择一个,默认负载均衡。
- RoundRobinLoadBalance:轮询负载均衡。
- LeastActiveLoadBalance:最少活跃调用数,相同活跃数的随机。
- ConsistentHashLoadBalance:一致性哈希负载均衡,相同参数的请求总是落在同一台机器上。
负载均衡策略配置
如果不指定负载均衡,默认使用随机负载均衡。我们也可以根据自己的需要,显式指定一个负载均衡。
生产者服务
@Service(timeout=3000,retries=3,loadbalance="roundrobin")
消费者服务
@Reference(timeout=2000,loadbalance="roundrobin")
参数:
- random:随机负载均衡
- leastactive:最少活跃调用数,相同活跃数的随机
- roundrobin:轮询负载均衡
- consistenthash:一致性哈希负载均衡
集群容错
Dubbo框架为服务集群容错提供了一系列好的解决方案,在此称为dubbo服务集群容错模式。
容错模式
- Failover Cluster:失败重试。默认值。当出现失败,重试其它服务器,默认重试2次,使用retries配置。一般用于读操作
- Failfast Cluster : 快速失败,只发起一次调用,失败立即报错。通常用于写操作。
- Failsafe Cluster : 失败安全,出现异常时,直接忽略。返回一个空结果。日志不重要操作。
- Failback Cluster : 失败自动恢复,后台记录失败请求,定时重发。非常重要的操作。
- Forking Cluster:并行调用多个服务器,只要有一个成功即返回。
- Broadcast Cluster:广播调用所有提供者,逐个调用,任意一台报错则报错。 同步要求高的可以使用这个模式。
集群容错配置
在消费者服务配置
@Reference(cluster = "failover")
private IOrderService iOrderService;
服务降级
服务降级,当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略的降级,以此释放服务器资源以保证核心任务的正常运行。
两种场景:
- 当下游的服务因为某种原因响应过慢,下游服务主动停掉一些不太重要的业务,释放出服务器资源,增加响应速度!
- 当下游的服务因为某种原因不可用,上游主动调用本地的一些降级逻辑,避免卡顿,迅速返回给用户!
为什么需要降级
当访问量剧增、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。
服务降级方式
第一种
mock=force:return null
含义:
表示消费方对该服务的方法调用都直接返回null值,不发起远程调用。用来屏蔽不重要服务不可用时对调用方的影响。
第二种
mock=fail:return null
含义:
表示消费方对该服务的方法调用在失败后,再返回null值,不抛异常。用来容忍不重要服务不稳定时对调用方的影响。
服务降级演示
@Reference(timeout = 2000,mock = "force:return null")
private IOrderService iOrderService;
服务限流
并发控制
@Service(executes = 10)
注意:
服务端并发执行(或占用线程池线程数)不能超过10个
连接控制
@Service(actives= 10)
注意:
占用连接的请求的数不能超过10个。
结果缓存
//通过注解中的cache属性配置结果缓存机制
@Reference(cache="lru")
Dubbo实战
项目介绍
需求:完成用户的增删改查操作
技术栈:
前端:html、thymeleaf
分布式:Dubbo、Zookeeper、SpringMVC
持久化:MySql、MyBatisPlus
项目架构:
搭建架构
1、在Dubbo_father的pom文件中定义需要用的依赖的版本并配置jdk版本,在配置中有一个标签叫做dependencyManagement,这个标签的作用就是声明该依赖的版本,当子模块引入该依赖时,无需定义版本,可以直接使用父项目定义好的版本
-
-
<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.itbaizhan</groupId>
-
<artifactId>Dubbo_father</artifactId>
-
<packaging>pom</packaging>
-
<version>1.0-SNAPSHOT</version>
-
<modules>
-
<module>Dubbo_producer</module>
-
<module>Dubbo_api</module>
-
<module>dubbo_consumer</module>
-
</modules>
-
-
<properties>
-
<dubbo.spring.starter.version>2.7.6</dubbo.spring.starter.version>
-
<dubbo.registry.zookeeper.version>2.7.6</dubbo.registry.zookeeper.version>
-
<mybatisplus.spring.starter.version>3.5.0</mybatisplus.spring.starter.version>
-
<mysql.connector.version>5.1.49</mysql.connector.version>
-
</properties>
-
-
<!-- 通过management提前声明这些依赖所使用的版本,等子项目使用的时候即可不需要定义版本,直接使用父项目声明的版本 -->
-
<dependencyManagement>
-
<dependencies>
-
<!-- Dubbo 依赖 -->
-
<dependency>
-
<groupId>org.apache.dubbo</groupId>
-
<artifactId>dubbo-spring-boot-starter</artifactId>
-
<version>${dubbo.spring.starter.version}</version>
-
</dependency>
-
<!-- zookeeper 注册中心 依赖 -->
-
<dependency>
-
<groupId>org.apache.dubbo</groupId>
-
<artifactId>dubbo-registry-zookeeper</artifactId>
-
<version>${dubbo.registry.zookeeper.version}</version>
-
</dependency>
-
<!-- Mybatis plus 依赖 -->
-
<dependency>
-
<groupId>com.baomidou</groupId>
-
<artifactId>mybatis-plus-boot-starter</artifactId>
-
<version>${mybatisplus.spring.starter.version}</version>
-
</dependency>
-
<!--MySQL 数据库依赖 -->
-
<dependency>
-
<groupId>mysql</groupId>
-
<artifactId>mysql-connector-java</artifactId>
-
<version>${mysql.connector.version}</version>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
-
<!-- 设置jdk版本 -->
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.apache.maven.plugins</groupId>
-
<artifactId>maven-compiler-plugin</artifactId>
-
<version>3.1</version>
-
<configuration>
-
<source>11</source>
-
<target>11</target>
-
</configuration>
-
</plugin>
-
</plugins>
-
</build>
-
-
-
-
</project>
因为Dubbo_consumer模块是SpringBoot项目,所以他的父项目是SpringBoot的起步依赖spring-boot-stater-parent,所以我们需要添加第二个父项目,通过dependencyManagement标签即可实现
-
-
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
-
<modelVersion>4.0.0</modelVersion>
-
<parent>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>2.7.11</version>
-
<relativePath/> <!-- lookup parent from repository -->
-
</parent>
-
<!-- 引入第二个父亲 -->
-
<dependencyManagement>
-
<dependencies>
-
<dependency>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>Dubbo_father</artifactId>
-
<type>pom</type>
-
<version>1.0-SNAPSHOT</version>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>dubbo_consumer</artifactId>
-
<version>0.0.1-SNAPSHOT</version>
-
<name>dubbo_consumer</name>
-
<description>Demo project for Spring Boot</description>
-
<properties>
-
<java.version>11</java.version>
-
</properties>
-
<dependencies>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-thymeleaf</artifactId>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-web</artifactId>
-
</dependency>
-
-
<dependency>
-
<groupId>org.projectlombok</groupId>
-
<artifactId>lombok</artifactId>
-
<optional>true</optional>
-
</dependency>
-
<dependency>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-test</artifactId>
-
<scope>test</scope>
-
</dependency>
-
</dependencies>
-
-
<build>
-
<plugins>
-
<plugin>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-maven-plugin</artifactId>
-
<configuration>
-
<excludes>
-
<exclude>
-
<groupId>org.projectlombok</groupId>
-
<artifactId>lombok</artifactId>
-
</exclude>
-
</excludes>
-
</configuration>
-
</plugin>
-
</plugins>
-
</build>
-
-
</project>
编写pojo实体类
创建数据库和表
-
创建数据库
-
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)
-
);
创建User实体类(User实体类需要实现Serializable接口,前面有提到过)
-
package com.itbaizhan.pojo;
-
-
import lombok.AllArgsConstructor;
-
import lombok.Data;
-
import lombok.NoArgsConstructor;
-
-
import java.io.Serializable;
-
-
/**
-
* 用户实体类
-
*/
-
-
-
-
public class User implements Serializable {
-
public Long id;//用户id
-
public String name;//用户名字
-
public int age;//用户年龄
-
}
mapper模块引入pojo模块
编写mapper持久层接口
引入MybatisPlus和mysql依赖
-
-
<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>Dubbo_producer</artifactId>
-
<groupId>com.itbaizhan</groupId>
-
<version>1.0-SNAPSHOT</version>
-
</parent>
-
<modelVersion>4.0.0</modelVersion>
-
-
<artifactId>mapper</artifactId>
-
-
<dependencies>
-
<!-- 引入pojo -->
-
<dependency>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>pojo</artifactId>
-
<version>1.0-SNAPSHOT</version>
-
</dependency>
-
<!-- MyBatisPlus依赖 -->
-
<dependency>
-
<groupId>com.baomidou</groupId>
-
<artifactId>mybatis-plus-boot-starter</artifactId>
-
</dependency>
-
<!-- MySql依赖 -->
-
<dependency>
-
<groupId>mysql</groupId>
-
<artifactId>mysql-connector-java</artifactId>
-
</dependency>
-
</dependencies>
-
</project>
编写UserMapper
-
package com.itbaizhan.mapper;
-
-
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
-
import com.itbaizhan.pojo.User;
-
-
public interface UserMapper extends BaseMapper<User> {
-
}
编写producer生产者代码
将producer修改为SpringBoot项目,因为SpringBoot项目的父类是spring-boot-stater-parent,而本身项目的父类是dubbo_producer,所以需要通过dependencyManagement引入第二个父项目
-
-
<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>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>2.7.11</version>
-
<relativePath/> <!-- lookup parent from repository -->
-
</parent>
-
-
<dependencyManagement>
-
<dependencies>
-
<!-- 引入第二个父项目 -->
-
<dependency>
-
<artifactId>Dubbo_producer</artifactId>
-
<groupId>com.itbaizhan</groupId>
-
<version>1.0-SNAPSHOT</version>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
<modelVersion>4.0.0</modelVersion>
-
-
<artifactId>producer</artifactId>
-
-
-
</project>
引入mapper模块,通过依赖传递的方式引入pojo模块
-
<dependencies>
-
<dependency>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>mapper</artifactId>
-
<version>1.0-SNAPSHOT</version>
-
</dependency>
-
</dependencies>
编写启动类并扫描持久层接口创建相应的实现类放到spring容器中
-
package com.itbaizhan.producer;
-
-
import org.springframework.boot.SpringApplication;
-
import org.springframework.boot.autoconfigure.SpringBootApplication;
-
-
-
-
public class ProducerApplication {
-
public static void main(String[] args) {
-
SpringApplication.run(ProducerApplication.class,args);
-
}
-
}
配置数据源
-
spring:
-
datasource:
-
driver-class-name: com.mysql.jdbc.Driver
-
url: jdbc:mysql://192.168.138.101/test
-
username: root
-
password: 123456
编写api模块代码
添加pojo模块依赖
-
-
<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>Dubbo_father</artifactId>
-
<groupId>com.itbaizhan</groupId>
-
<version>1.0-SNAPSHOT</version>
-
</parent>
-
<modelVersion>4.0.0</modelVersion>
-
-
<artifactId>Dubbo_api</artifactId>
-
<dependencies>
-
<dependency>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>pojo</artifactId>
-
<version>1.0-SNAPSHOT</version>
-
</dependency>
-
</dependencies>
-
-
-
</project>
编写api模块service层接口(该接口的作用是定义producer模块的service规范)
-
package com.itbaizhan.service;
-
-
import com.itbaizhan.pojo.User;
-
-
import java.util.List;
-
-
public interface UserService {
-
//新增用户
-
public void add(User user);
-
-
//根据id删除用户
-
public void delete(Long userId);
-
-
//根据id修改用户
-
public void update(User user);
-
-
//查询所有用户
-
public List<User> selectAll();
-
//根据id查询用户
-
public User selectById();
-
-
}
producer模块引入相关依赖
-
-
<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>
-
<groupId>org.springframework.boot</groupId>
-
<artifactId>spring-boot-starter-parent</artifactId>
-
<version>2.7.11</version>
-
<relativePath/> <!-- lookup parent from repository -->
-
</parent>
-
-
<dependencyManagement>
-
<dependencies>
-
<!-- 引入第二个父项目 -->
-
<dependency>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>Dubbo_father</artifactId>
-
<type>pom</type>
-
<version>1.0-SNAPSHOT</version>
-
<scope>import</scope>
-
</dependency>
-
</dependencies>
-
</dependencyManagement>
-
-
<modelVersion>4.0.0</modelVersion>
-
-
<artifactId>producer</artifactId>
-
-
<dependencies>
-
<dependency>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>mapper</artifactId>
-
<version>1.0-SNAPSHOT</version>
-
</dependency>
-
<!-- 引入dubbo -->
-
<dependency>
-
<groupId>org.apache.dubbo</groupId>
-
<artifactId>dubbo-spring-boot-starter</artifactId>
-
</dependency>
-
<!-- 引入zookeeper -->
-
<dependency>
-
<groupId>org.apache.dubbo</groupId>
-
<artifactId>dubbo-registry-zookeeper</artifactId>
-
</dependency>
-
<!-- 引入dubbo_api模块 -->
-
<dependency>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>Dubbo_api</artifactId>
-
<version>1.0-SNAPSHOT</version>
-
</dependency>
-
</dependencies>
-
</project>
编写producer模块service层代码(类的上方需要添加Dubbo的@Service注解,将该类注册到注册中心)
-
package com.itbaizhan.producer.service;
-
-
import com.itbaizhan.mapper.UserMapper;
-
import com.itbaizhan.pojo.User;
-
import org.apache.dubbo.config.annotation.Service;
-
import org.springframework.beans.factory.annotation.Autowired;
-
-
import java.util.List;
-
-
-
public class UserService implements com.itbaizhan.service.UserService {
-
-
-
private UserMapper userMapper;
-
-
/**
-
* 添加用户
-
* @param user
-
*/
-
-
public void add(User user) {
-
userMapper.insert(user);
-
}
-
-
/**
-
* 根据id删除用户
-
* @param userId
-
*/
-
-
public void delete(Long userId) {
-
userMapper.deleteById(userId);
-
}
-
-
/**
-
* 根据id修改用户
-
* @param user
-
*/
-
-
public void update(User user) {
-
userMapper.updateById(user);
-
}
-
-
/**
-
* 查询所有用户
-
* @return
-
*/
-
-
public List<User> selectAll() {
-
return userMapper.selectList(null);
-
}
-
-
/**
-
* 根据id查询用户
-
* @param userId
-
* @return
-
*/
-
-
public User selectById(Long userId) {
-
return userMapper.selectById(userId);
-
}
-
}
配置dubbo和zookeeper
-
dubbo:
-
#项目名字
-
application:
-
name: myProducer
-
#注册中心地址
-
registry:
-
address: zookeeper://192.168.138.101:2181
-
timeout: 50000
-
#端口号和协议名
-
protocol:
-
port: 20880
-
name: dubbo
-
#扫描的包
-
scan:
-
base-packages: com.itbaizhan.producer.service
运行producer模块启动类,通过dubbo-admin查看是否注册到了注册中心
编写consumer消费者代码
引入相关依赖(dubbo、zookeeper、Dubbo_api)
-
<!-- 引入dubbo -->
-
<dependency>
-
<groupId>org.apache.dubbo</groupId>
-
<artifactId>dubbo-spring-boot-starter</artifactId>
-
</dependency>
-
<!-- 引入zookeeper -->
-
<dependency>
-
<groupId>org.apache.dubbo</groupId>
-
<artifactId>dubbo-registry-zookeeper</artifactId>
-
</dependency>
-
<!-- 引入dubbo_api模块 -->
-
<dependency>
-
<groupId>com.itbaizhan</groupId>
-
<artifactId>Dubbo_api</artifactId>
-
<version>1.0-SNAPSHOT</version>
-
</dependency>
编写service层代码(这里的@Service就是Spring的注解)
通过@Reference拉取Dubbo_api模块的UserService,那么此时会有小伙伴问了:我们注册的是producer模块的UserService,为什么拉取的确实Dubbo_api模块的UserService呢?
这是因为采用了jdk动态代理的模式,就是拉取这个接口的实现类,以接口引用的方式实现调用
-
package com.itbaizhan.dubbo_consumer.service;
-
-
import com.itbaizhan.pojo.User;
-
import org.apache.dubbo.config.annotation.Reference;
-
import org.springframework.stereotype.Service;
-
-
import java.util.List;
-
-
-
public class UserService {
-
-
private com.itbaizhan.service.UserService userService;
-
-
//新增用户
-
public void add(User user){
-
userService.add(user);
-
}
-
-
//根据id删除用户
-
public void delete(Long userId){
-
userService.delete(userId);
-
}
-
-
//根据id修改用户
-
public void update(User user){
-
userService.update(user);
-
}
-
-
//查询所有用户
-
public List<User> selectAll(){
-
return userService.selectAll();
-
}
-
-
//根据id查询用户
-
public User selectById(Long userId){
-
return userService.selectById(userId);
-
}
-
}
编写PageController(该控制层的作用就是跳转到对应页面)
-
package com.itbaizhan.dubbo_consumer.controller;
-
-
import org.springframework.stereotype.Controller;
-
import org.springframework.web.bind.annotation.PathVariable;
-
import org.springframework.web.bind.annotation.RequestMapping;
-
-
-
public class PageController {
-
-
-
public String page({ String page)
-
return page;
-
}
-
}
编写UserController
-
package com.itbaizhan.dubbo_consumer.controller;
-
-
import com.itbaizhan.dubbo_consumer.service.UserService;
-
import com.itbaizhan.pojo.User;
-
import org.springframework.beans.factory.annotation.Autowired;
-
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 java.util.List;
-
-
-
-
public class UserController {
-
-
private UserService userService;
-
-
//新增用户
-
-
public String add(User user){
-
userService.add(user);
-
return "redirect:/ok";
-
}
-
-
//根据id删除用户
-
-
public String delete(Long userId){
-
userService.delete(userId);
-
return "redirect:/ok";
-
}
-
-
//根据id修改用户
-
-
public String preUpdate(Long userId, Model model){
-
User user = userService.selectById(userId);
-
model.addAttribute("user",user);
-
return "update";
-
}
-
-
//根据id查询用户
-
-
public String update(User user){
-
userService.update(user);
-
return "redirect:/ok";
-
}
-
-
//查询所有用户
-
-
public String selectAll(Model model){
-
List<User> userList = userService.selectAll();
-
model.addAttribute("userList",userList);
-
return "showuser";
-
}
-
-
}
-
编写index.html主页
-
-
<html lang="en">
-
<head>
-
<meta charset="UTF-8">
-
<title>主页</title>
-
</head>
-
<body>
-
<a href="/adduser">添加用户</a>
-
<a href="/user/selectAll">查询用户</a>
-
</body>
-
</html>
配置dubbo和zookeeper
-
dubbo:
-
#项目名字
-
application:
-
name: myConsumer
-
#注册中心地址
-
registry:
-
address: zookeeper://192.168.138.101:2181
-
timeout: 50000
-
#端口号和协议名
-
protocol:
-
port: 20881
-
name: dubbo
-
#扫描的包
-
scan:
-
base-packages: com.itbaizhan.dubbo_consumer.service
运行producer模块和consumer模块,访问localhost:8080/index
此时发现整个项目可以正常运行,那么我们就可以继续编写页面了
新增用户业务实现
编写adduser.html
-
-
<html lang="en">
-
<head>
-
<meta charset="UTF-8">
-
<title>添加用户</title>
-
</head>
-
<body>
-
<form action="/user/add" method="post">
-
用户名:<input type="text" name="name">
-
年龄:<input type="text" name="age"><br/>
-
<input type="submit" value="提交">
-
</form>
-
-
</body>
-
</html>
编写ok.html
-
-
<html lang="en">
-
<head>
-
<meta charset="UTF-8">
-
<title>操作成功</title>
-
</head>
-
<body>
-
操作成功,点击<a href="/index.html">返回首页</a>
-
</body>
-
</html>
添加用户测试:
点击添加用户
点击提交
查看是否添加用户成功
测试成功之后编写查询所有用户(需要用到thymeleaf)
查询用户业务实现
编写showuser.html对用户有两个操作,修改和删除
-
-
<html lang="en" xmlns:th="http://www.thymeleaf.org">
-
<head>
-
<meta charset="UTF-8">
-
<title>用户列表</title>
-
</head>
-
<body>
-
<table border="1px solid black" align="center">
-
<tr>
-
<th>id</th>
-
<th>用户姓名</th>
-
<th>用户年龄</th>
-
<th>操作</th>
-
</tr>
-
<tr th:each="user:${userList}">
-
<td th:text="${user.id}"></td>
-
<td th:text="${user.name}"></td>
-
<td th:text="${user.age}"></td>
-
<td>
-
<a th:href="@{/user/preUpdate(userId=${user.id})}">修改</a>
-
<a th:href="@{/user/delete(userId=${user.id})}">删除</a>
-
</td>
-
</tr>
-
</table>
-
</body>
-
</html>
查询用户测试
点击查询用户
修改用户业务实现
编写update.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">
-
<!-- userId的隐藏域 -->
-
<input type="hidden" name="id" th:value="${user.id}">
-
用户名:<input type="text" name="name" th:value="${user.name}">
-
年龄:<input type="text" name="age" th:value="${user.age}"><br/>
-
<input type="submit" value="修改">
-
</form>
-
</body>
-
</html>
修改用户测试
点击修改用户
修改用户数据,点击修改按钮过后跳转到操作成功页面,回到首页再次查询用户会发现,用户数据已经更改
删除用户业务实现
删除用户的业务在实现查询用户业务的时候已经写好了,只要点击删除即可删除用户
这篇好文章是转载于:学新通技术网
- 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
- 本站站名: 学新通技术网
- 本文地址: /boutique/detail/tanhfichhh
-
photoshop保存的图片太大微信发不了怎么办
PHP中文网 06-15 -
《学习通》视频自动暂停处理方法
HelloWorld317 07-05 -
word里面弄一个表格后上面的标题会跑到下面怎么办
PHP中文网 06-20 -
Android 11 保存文件到外部存储,并分享文件
Luke 10-12 -
photoshop扩展功能面板显示灰色怎么办
PHP中文网 06-14 -
微信公众号没有声音提示怎么办
PHP中文网 03-31 -
excel下划线不显示怎么办
PHP中文网 06-23 -
excel打印预览压线压字怎么办
PHP中文网 06-22 -
TikTok加速器哪个好免费的TK加速器推荐
TK小达人 10-01 -
怎样阻止微信小程序自动打开
PHP中文网 06-13