一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>
效果截图