分布式的应用
- 手机应用;
- 手机app(前台应用)
- java管理程序(后台应用)
后台应用功能拆分,不同的应用可以部署在不同的机器上;不同应用程序之间也需要互相调用;
分布式应用程序如何相互调用?
-
http(httpurlConnection) 好处:调用简单,使用80端口一般不会被防火墙拦截;短连接,用到时就建立连接,用完了就断开连接;
-
RPC(remote procedure Call 远程方法调用)-tcp 长连接:在进行数据交换时效率会高一些;
RestTemplate()(基于http协议调用) -
服务端应用(spring boot 已经内嵌了tomcat 所以支持对http协议的支持)
服务器端的开发就是用之前的springmvc技术就可以完成;服务器端只需要提供json数据就可以了; -
客户端应用
- 使用java原生的api完成客户端的调用
public class Client {
//将json格式转为对象
static ObjectMapper om=new ObjectMapper();
public static void main(String[] args) throws IOException {
HttpURLConnection conn = (HttpURLConnection)
new URL("http://192.168.9.2:8080/user").openConnection();
//转换获取到的字节流为字符流
InputStream in = conn.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
BufferedReader r = new BufferedReader(reader);
//输出字符流
while (true){
String s = r.readLine();
if(s==null){
break;
}
User user = om.readValue(s, User.class);
System.out.println(user);
}
r.close();
conn.disconnect();
}
}
- 使用spring的RestTemplate工具类对刚才的调用进行简化;
加入jar包依赖
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.1.5.RELEASE</version>
</dependency>
</dependencies>
public class Client2 {
public static void main(String[] args) {
RestTemplate template = new RestTemplate();
User user = template.getForObject("http://192.168.9.2:8080/user", User.class);
System.out.println(user);
}
}
Dubbo(RPC 框架)
provider 服务提供者
consumer 服务消费者
registry 注册中心:可以把提供者发生的一些变更通知给消费者;
- 服务提供者启动后,会向注册中心注册提供者信息(ip、服务名、方法定义);
- 消费者启动后,向注册中心订阅服务信息;
- 一旦服务提供者的信息发生了变更,注册中心负责把这些变更通知给消费者;
- 消费者调用服务者的方法是直接调用的,不用通过注册中心;
- 注册中心
第三方的zookeeper(分布式的协调框架),可以把各种服务进行统一的配置放入注册中心;其中会存储服务提供者和服务消费者的相关信息;
5. 下载zookeeper
6. 修改配置文件 conf 将zoo_sample.cfd复制一份改名为zoo.cfg;
7. 进入解压目录bin,执行zkServer.cmd脚本文件;
8. 可以通过一个叫ZooInspector查看注册中心的运行信息;
注册中心提供的端口,下来provider和Consumer都需要连接这个端口;
- dubbo 控制台
子项目,以springboot开发的可以以图形界面的方式查看dubbo中提供者、消费者的信息;
安装
- 下载源代码
git clone
- 编译源代码
mvn -Dmaven.test.skip=true clean package
用idea打包
3)运行获得的jar包
java -jar dubbo-admin-server-0.1.jar --server.port=7070
需要先启动注册中心,再启动控制台;
- 开发dubbo项目
- 开发公共api项目
公共类与接口的定义,UserService、User
打成jar包
package com.westos.api;
public interface UserService {
public void insert(User user);
public void update(User user);
public User find(String user);
}
- 开发privider提供者
pom.xml中要添加必要的依赖spring-boot,dubbo,zookeeper
<!-- spring boot 父依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>2.1.1.RELEASE</version>
</parent>
<!-- 常量 设置 spring boot,dubbo 等版本 -->
<properties>
<spring-boot.version>2.1.1.RELEASE</spring-boot.version>
<dubbo.version>2.7.0</dubbo.version>
<zookeeper.version>3.4.6</zookeeper.version>
<curator.version>4.1.0</curator.version>
</properties>
<!-- 依赖管理,以后可以把这些移入一个 pom 项目,方便进行统一版本控制 -->
<dependencyManagement>
<dependencies>
<!-- Spring Boot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- Apache Dubbo -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-bom</artifactId>
<version>${dubbo.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- springboot 与 dubbo 整合 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo.version}</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>${dubbo.version}</version>
<exclusions>
<!-- 排除 dubbo 引用的 spring,避免与外面指定的 spring 冲突 -->
<exclusion>
<groupId>org.springframework</groupId>
<artifactId>spring</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
<!-- 排除 dubbo 使用的 log4j 日志系统,避免和 springboot 默认的 logback 冲突 -->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- dubbo 注册中心依赖,zookeeper -->
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
<version>${zookeeper.version}</version>
<exclusions>
<!-- 排除 zookeeper 使用的 log4j 日志系统,避免和 springboot 默认的 logback 冲突 -->
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
<exclusion>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- dubbo 注册中心依赖, dubbo 官网给出的 curator 的版本和包名是错误的 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- spring boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
</dependency>
<dependency>
<groupId>org.apache.zookeeper</groupId>
<artifactId>zookeeper</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<!-- 公共 api -->
<dependency>
<groupId>com.westos</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<!-- 用 java.version 不能生效,可能被 dubbo 覆盖了 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
配置
# 配置端口
server.port=8080
# 应用程序的名字, 需要唯一, 不能和注册中心中其他程序冲突
spring.application.name=provider
# 注册中心
dubbo.registry.address=zookeeper://localhost:2181
# 设置连接注册中心的超时时间 3 分钟
dubbo.registry.timeout=180000
# 把元数据信息 发布至注册中心
dubbo.metadata-report.address=zookeeper://localhost:2181
# 指定 导出服务 的包名
dubbo.scan.base-packages=com.westos.provider
package com.westos.provider;
import com.westos.User;
import com.westos.UserService;
import org.apache.dubbo.config.annotation.Service;
@Service
public class UserServiceImpl implements UserService {
@Override
public void insert(User user) {
System.out.println("insert" +user.getName());
}
@Override
public void update(User user) {
}
@Override
public User find(String name, int age, String sex) {
User user = new User();
user.setName(name);
user.setAge(age);
user.setSex(sex);
return user;
}
@Override
public void delete() {
}
}
3.开发consume消费者
spring配置
# 端口
server.port=9090
# 给消费者应用起一个唯一的名字
spring.application.name=Msk-consumer
# 注册中心地址
dubbo.registry.address=zookeeper://localhost:2181
dubbo.registry.timeout=180000
package com.westos.controller;
import com.westos.User;
import com.westos.UserService;
import org.apache.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ClientController {
// 使用公共的api接口把provider和consumer联系起来
@Reference
private UserService userService;
@RequestMapping("/user")
public User find(){
return userService.find("李四",19,"男");
}
}
调用流程
- 浏览器中访问消费者http://localhost:9090/user
- 根据此地址找到控制器方法,接下来调用UserService;
- 但UserService是一个接口,实现不在消费者这边;
- dubbo 针对这个UserService接口生成一个代理对象
- 代理对象:
- 代理对象会访问注册中心,把UserService服务的信息下载到本地;
- 这些服务信息会缓存至本地,后续的调用不会再依赖注册中心;
- 底层netty nio 非阻塞io 跟服务器
Rest和Dubbo的优缺点
- dubbo:应用于同一语言编写的两个应用之间;性能优于rest,基于tcp传输的是字节;服务应用程序之间;更适合长链接;支持服务的治理;
- rest:任意语言任意平台之间进行调用;基于http传输的是字符;建立短连接;