Apache Dubbo是一个高可用的,基于java的开源RPC框架
不仅包含RPC访问功能,还包含服务治理功能
由阿里巴巴建立,最后由apache维护至今,所以我们选择由apache维护的dubbo
官方地址:https://mvnrepository.com/artifact/org.apache.dubbo/dubbo
常用版本2.7.3
Dubbo架构
Dubbo支持的协议
Dubbo协议(官方推荐)
采用NIO复用单一长连接,使用线程池并发处理请求,减少握手和加大并发效率
大文件上传时,可能出现问题(不适用Dubbo文件上传)
RMI协议(Remote Method Invocation)
优点:JDK自带的能力
缺点:偶尔连接失败
Hessian协议
优点:可以与原生Hessian互操作,基于HTTP协议
缺点:需hessian.jar支持,http短连接的开销大
Dubbo支持的注册中心
Zookeeper(官方推荐)
优点:支持分布式,周边产品
缺点:受限于Zookeeper软件的稳定性,Zookeeper专门分布式辅助软件,稳定较优
Multicast
优点:去中心化,不需要单独安装
缺点:Provider和Consumer和Registry不能跨机房(只能在局域网内使用)
Redis
优点:支持集群,性能高
缺点:要求服务器时间同步,否则可能出现集群失败问题
Simple
优点:标准RPC服务,没有兼容问题
缺点:不支持集群
第一个Dubbo的Provider
Dubbo目录结构
创建父工程,添加依赖
<parent> <group>org.springframework.boot</group> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.10.RELEASE</version> </parent>
<dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.4.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> <version>2.4.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.1.10 RELEASE</version> </dependency> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.3</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-recipes</artifactId> <version>4.2.0</version> </dependency> <dependency> <groupId>org.apache.curator</groupId> <artifactId>curator-framework</artifactId> <version>4.2.0</version> </dependency> </dependencyManagement>
DubboService接口
public interface DubboService{ public String service(String param); }
接口实现
@Service public class DubboServiceImpl implements DubboService{ @Reference private dubboService DubboService; @Override public String service(String param){ return DubboService.service("dubbo"); } }
启动类
@SpringBootApplication @EnableDubbo public class ProviderApplication{ public static void main(String[] args){ SpringApplication.run(ProviderApplication.class, args); } }
控制器
public class DubboController{ @Autowired private DubboService dubboService; @RequestMapping("/dubboservice") @RequestBody public String service(){ return dubboService.service(); } }
provider中的application.yml
dubbo:
application:
name: dubbo-provider
registry:
address: zookeeper://192.168.0.1:2181
protocol:
port: 20884
consumer中的application.yml
dubbo:
application:
name: dubbo-consumer
registry:
address: zookeeper://192.168.0.1:2181
protocol:
port: 20884
Admin管理界面搭建
负载均衡
集群:一个内容,部署多次,形成的整体称为集群,每个个体应该部署到不同的服务器
伪集群:集群中内容部署到同一台服务器上,通过不同端口区分不同个体
负载均衡是在集群前提下,当访问整个集群时,集群中每个节点都被访问次数或频率的规则
Dubbo内置了四个负载均衡策略,默认为Random
内置策略
- Random,随机,随机访问集群中结点,访问概率和权重有关
- RoundRobin,轮询,访问频率和权重有关;权重,占有比例,集群中每个项目部署的服务器性能可能不同,性能好的权重高
- LeastActive,活跃数相同的随机,不同的活跃数高的放前面
- ConsistentHash,一致性Hash,相同参数请求总是发到一个提供者
Provider集群
新建四个启动类
每次启动启动类修改配置文件dubbo.protocal.port
设置负载均衡
调用的服务采用负载均衡
@Reference(loadbalance = "roundrobin") private DubboService dubboService;
当前拂去采用的负载均衡算法
@Service(loadbalance = "random") public class DubboServiceImpl implements DubboService{}
设置权重
@Service(weight = 4)
配置文件
dubbo:
application:
name: dubbo-provider
registry:
address: zookeeper://192.168.32.128:2181
protocol:
port: 20884
结构图
pojo.Dept.java
public class Dept implements Serializable{ private Integer id; private String name; // getter setter }
pojo.Emp.java
public class Emp implements Serializable{ private Integer id; private String name; private Stgring phote; private Integer did; // getter setter }
持久层myBatis
application-mybatis.yml
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/test
username: root
password: root
mybatis:
mapper-locations: classpath:mybatis/*.xml
type-aliases-package: com.test.pojo
mapper.DeptMapper
mapper.EmpMapper
provider启动类
@SpringBootApplication @EnableDubbo @MapperScan(com.test.mapper) public class ProviderApplication{ public static void main(String[] args){ SpringApplication.run(ProviderApplication.class, args); } }
provider的applicaton.yml
dubbo:
application:
name: dubbo-provider
registry:
address: zookeeper://192.168.0.1:2181
# 加载其它配置文件, 加载其它的application-*.yml文件
# 多个名称之间用 "," 分隔
spring:
profiles:
active: mybatis
dept子项目的创建
DeptMapper.xml
<mapper namespace="com.test.mapper.DeptMapper"> <select id="findAll" resultType="com.test.pojo.Dept"> select id, name from dept; </select> </mapper>
DeptDubboService
public interface DeptDubboService{ public List<Dept> findAllDept(); }
DeptMapper
public interface DeptMapper{ public List<Dept> findAll(); }
DeptDubboServiceImpl
// 选择Dubbo注解 @Service public class DeptDuboServiceImpl implements DeptDubboService(){ @Autowired private DeptMapper deptMapper; @Override public List<Dept> findAllDept(){ return deptMapper.findAll(); } }
DeptService
public interface DeptService{ public List<Dept> findAll(); public List<Emp> findEmpByDeptId(Integer did); }
DeptServiceImpl
public class DeptServiceImpl implements DeptService{ @Reference private DeptDubboService deptDubboService; @Override public List<Dept> findAll(){ return null; } }
DeptController
@Controller public class DeptController{ @Autowired private DeptService deptService; @GetMapping("/dept") public String showDept(Model model){ model.setAttribute("list", deptService.findAll()); return "dept"; } }
启动类
@SpringBootApplication @EnableDubbo @MapperScan("com.test.mapper") public class ProviderApplication{ public static void main(String[] args){ SpringApplication.run(ProviderApplication.class, args); } }
emp下的application.yml
dubbo:
application:
name: dubbo-emp-consumer
registry:
address: zookeeper://192.168.0.1
server:
port: 8081
EmpApplication
@SpringBootApplication @EnableDubbo public class EmpApplication{ public static void main(String[] args){ SpringApplication.run(EmpApplication.class, args); } }
EmpDubboService
public interface EmpDubboService{ public int insertEmp(Emp emp); public List<Emp> findEmpByDeptId(Integer did); }
EmpDubboServiceImpl
public class EmpDubboServiceImpl implements EmpDubboService{ @Autowired private EmpMapper empMapper; @Override public int insertEmp(Emp emp){ return empMapper.insertEmp(emp); } }
EmpMapper.xml
<mapper namespace="com.test.mapper.EmpMapper" > <insert id="insertEmp" parameterType="com.test.pojo.Emp"> insert into emp(name, photo, did) values(#{name}, #{photo}, #{did}) </insert>
<select id="findEmpByDeptId" parameterType="int" resultType="com.test.pojo.Emp">
select id, name, photo from emp where did = #(did)
</select> </mapper>
EmpService
public interface EmpService{ public List<Dept> showAll(); public int insert(Emp emp, MultipartFile file); }
EmpDubboServiceImpl
public class EmpDubboServiceImpl implements EmpService{ // Dubbo 的 Reference @Reference private DeptDubboService deptDubboService; @Reference private EmpDubboService empDubboService; @Override public List<Dept> showAll(){ return deptDubboService.findAllDept(); } @Override public int insert(Emp emp, MultipartFile file){ try{ // 通过spring容器获取HttpServletRequeest对象 HttpServletRequeest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest(); // 通过HttpServletRequest对象获取图片上传的路径 String path = request.getServletContext().getRealPath("/img"); System.out.println("path == " + path); // 为上传到服务器中的图片的名称不重复, 编写随机数 long currentTimeMills = System.currentTimeMillis(); Random random = new Random(); String fileName = currentTimeMills + "" + random.nextInt(1000); String oldName = file.getOriginalFilename(); fileName += oldName.substring(oldName.lastIndexOf(".")); File pathFile = new File(path); // 第一次上传图片, 检查目录是否存在, 如果不存在, 创建响应目录 if(!pathFile.exist()){ pathFile.mkdirs(); } // 图片上传 file.transferTo(new File(path, fileName)); // 封装emp对象, 把图片路径封装到emp对象中 emp.setPhoto("http://localhost:8081/img/" + fileName); return empDubboService.insertEmp(emp); }catch(IOException e){ e.printStackTrace(); } return 0; } }
EmpController
public class EmpController{ @Autowired private EmpService empService; @GetMapping("/empadd") public String empAdd(Model model){ model.addAttribute("list", empService.showAll()); return "emp-add"; } @PostMapping("/add") public String add(Emp emp, MultipartFile file){ empService.insert(emp, file); return "emp-add"; } }
DeptController
@Controller public class DeptController{ @Autowired private DeptService deptService; @GetMapping("/dept") public String showDept(Model model){ model.addAttribute("list", deptService.findAll()); return "dept"; } @GetMapping("/showEmp") public String showEmp(Integer did, Model model){ model.addAttribute("list", deptService.findEmpByDeptId(did)); return "showEmp"; } }