本项目的笔记和资料的Download,请点击这一句话自行获取。html
随着互联网的发展,网站应用的规模不断扩大。需求的激增,带来的是技术上的压力。系统架构也所以也不断的演进、升级、迭代。程序员
从单一应用,到垂直拆分,到分布式服务,到SOA面向服务,以及如今火热的微服务架构,还有在Google带领下来势汹涌的Service Mesh。web
当网站流量很小时,只需一个应用,将全部功能都部署在一块儿,以减小部署节点和成本。此时,用于简化增删改查工做量的数据访问框架(ORM)是影响项目开发的关键。spring
存在的问题:数据库
当访问量逐渐增大,单一应用没法知足需求,此时为了应对更高的并发和业务需求,咱们根据业务功能对系统进行拆分:apache
优势:编程
缺点:json
当垂直应用愈来愈多,应用之间交互不可避免,将核心业务抽取出来,做为独立的服务,逐渐造成稳定的服务中心,使前端应用能更快速的响应多变的市场需求。此时,用于提升业务复用及整合的分布式调用是关键。
优势:
缺点:
当服务愈来愈多,容量的评估,小服务资源的浪费等问题逐渐显现,此时需增长一个调度中心基于访问压力实时管理集群容量,提升集群利用率。此时,用于提升机器利用率的资源调度和治理中心(SOA)是关键
之前出现了什么问题?
服务治理要作什么?
缺点:
前面说的SOA,英文翻译过来是面向服务。微服务,彷佛也是服务,都是对系统进行拆分。所以二者很是容易混淆,但其实缺有一些差异:
微服务的特色:
微服务结构图:
不管是微服务仍是SOA,都面临着服务间的远程调用。那么服务间的远程调用方式有哪些呢?
常见的远程调用方式有如下两种:
RPC:Remote Produce Call远程过程调用,相似的还有RMI。自定义数据格式,基于原生TCP通讯,速度快,效率高。如今热门的dubbo,就是RPC的典型。
Http:http实际上是一种网络传输协议,基于TCP,规定了数据传输的格式。如今客户端浏览器与服务端通讯基本都是采用Http协议。也能够用来进行远程服务调用。缺点是消息封装臃肿。
如今热门的Rest风格,就能够经过http协议来实现。
RPC,即 Remote Procedure Call(远程过程调用),是一个计算机通讯协议。 该协议容许运行于一台计算机的程序调用另外一台计算机的子程序,而程序员无需额外地为这个交互做用编程。说得通俗一点就是:A计算机提供一个服务,B计算机能够像调用本地服务那样调用A计算机的服务。
经过上面的概念,咱们能够知道,实现RPC主要是作到两点:
RPC调用流程图:
Http协议:超文本传输协议,是一种应用层协议。规定了网络传输的请求格式、响应格式、资源定位和操做的方式等。可是底层采用什么网络传输协议,并无规定,不过如今都是采用TCP协议做为底层传输协议。说到这里,你们可能以为,Http与RPC的远程调用很是像,都是按照某种规定好的数据格式进行网络通讯,有请求,有响应。没错,在这点来看,二者很是类似,可是仍是有一些细微差异。
例如咱们经过浏览器访问网站,就是经过Http协议。只不过浏览器把请求封装,发起请求以及接收响应,解析响应的事情都帮咱们作了。若是是不经过浏览器,那么这些事情都须要本身去完成。
既然两种方式均可以实现远程调用,咱们该如何选择呢?
所以,二者都有不一样的使用场景:
那么咱们该怎么选择呢?
微服务,更增强调的是独立、自治、灵活。而RPC方式的限制较多,所以微服务框架中,通常都会采用基于Http的Rest风格服务。
既然微服务选择了Http,那么咱们就须要本身来实现对请求和响应的处理。好在开源世界已经有不少的http客户端工具,可以帮助咱们作这些事情,例如:
接下来,咱们就一块儿了解一款比较流行的客户端工具:HttpClient
HttpClient是Apache公司的产品,是Http Components下的一个组件。
官网地址:http://hc.apache.org/index.html
特色:
咱们导入课前资料提供的demo工程:《http-demo》
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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.leyou.demo</groupId> <artifactId>http-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>http-demo</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.9.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies> <!--核心依赖,包括auto-configuration , logging等--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- springboot测试模块的起步依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- http客户端工具,个性化实现对请求和响应的处理 --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.10</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
HttpTests
package com.leyou.httpdemo; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.BasicResponseHandler; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.junit.Before; import org.junit.Test; import java.io.IOException; public class HttpTests { CloseableHttpClient httpClient; @Before //初始化 public void init() { httpClient = HttpClients.createDefault(); } @Test public void testGet() throws IOException { //发起get请求 HttpGet request = new HttpGet("http://www.baidu.com"); String response = this.httpClient.execute(request, new BasicResponseHandler()); System.out.println(response); } @Test public void testPost() throws IOException { //发起Post请求 HttpGet request = new HttpGet("http://www.oschina.net/"); request.setHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"); String response = this.httpClient.execute(request, new BasicResponseHandler()); System.out.println(response); } //==========我是一个分割线============// }
HttpClient请求数据后是json字符串,须要咱们本身把Json字符串反序列化为对象,可使用JacksonJson工具来实现。
JacksonJson
是SpringMVC内置的json处理工具,其中有一个ObjectMapper
类,能够方便的实现对json的处理:
对象转json
// json处理工具 private ObjectMapper mapper = new ObjectMapper(); // 成员变量 @Test public void testJson() throws JsonProcessingException { User user = new User(); // 局部变量 user.setId(8L); user.setAge(21); user.setName("柳岩"); user.setUserName("liuyan"); // 序列化 String json = mapper.writeValueAsString(user); System.out.println("json = " + json); }
结果:
// json处理工具:json转普通对象 private ObjectMapper mapper = new ObjectMapper(); @Test public void testJson() throws IOException { User user = new User(); user.setId(8L); user.setAge(21); user.setName("柳岩"); user.setUserName("liuyan"); // 序列化 String json = mapper.writeValueAsString(user); // 反序列化,接收两个参数:json数据,反序列化的目标类字节码 User result = mapper.readValue(json, User.class); System.out.println("result = " + result); }
结果:
json转集合相对比较麻烦,由于你没法同时把集合的class和元素的class同时传递到那一个字节码参数的位置。
所以Jackson作了一个类型工厂,用来解决这个问题:
// json处理工具:json转集合 private ObjectMapper mapper = new ObjectMapper(); @Test public void testJson() throws IOException { User user = new User(); user.setId(8L); user.setAge(21); user.setName("柳岩"); user.setUserName("liuyan"); // 序列化,获得对象集合的json字符串 String json = mapper.writeValueAsString(Arrays.asList(user, user)); // 反序列化,接收两个参数:json数据,反序列化的目标类字节码 List<User> users = mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, User.class)); for (User u : users) { System.out.println("u = " + u); } }
当对象泛型关系复杂时,类型工厂也很差使了。这个时候Jackson提供了TypeReference来接收类型泛型,而后底层经过反射来获取泛型上的具体类型。实现数据转换。
// json转任意复杂类型 private ObjectMapper mapper = new ObjectMapper(); @Test public void testJson() throws IOException { User user = new User(); user.setId(8L); user.setAge(21); user.setName("柳岩"); user.setUserName("liuyan"); Country country = new Country(); country.setId(2L); country.setCountryname("中国"); country.setCountrycode("+86"); // 序列化,获得对象集合的json字符串 String json = mapper.writeValueAsString(Arrays.asList(user, user)); System.out.println("json = " + json); System.out.println("=============="); // 反序列化,接收两个参数:json数据,反序列化的目标类字节码 TypeReference ref = new TypeReference<List<User>>(){}; List<User> users = mapper.readValue(json, ref); for (User u : users) { System.out.println("u = " + u); } }
结果:
Spring提供了一个RestTemplate模板工具类,对基于Http的客户端进行了封装,而且实现了对象与json的序列化和反序列化,很是方便。RestTemplate并无限定Http的客户端类型,而是进行了抽象,目前经常使用的3种都有支持:
首先在项目中注册一个RestTemplate
对象,能够在启动类位置注册:
@SpringBootApplication public class HttpDemoApplication { public static void main(String[] args) { SpringApplication.run(HttpDemoApplication.class, args); } @Bean public RestTemplate restTemplate() { // 默认的RestTemplate,底层是走JDK的URLConnection方式。 return new RestTemplate(); } }
在测试类中直接@Autowired
注入:
import java.io.IOException; import java.util.Arrays; import java.util.List; @RunWith(SpringRunner.class) @SpringBootTest(classes = HttpDemoApplication.class) public class HttpDemoApplicationTests { @Autowired private RestTemplate restTemplate; @Test public void httpGet() { /*经过RestTemplate的getForObject()方法,传递url地址及实体类的字节码, RestTemplate会自动发起请求,接收响应,而且帮咱们对响应结果进行反序列化。*/ User user = this.restTemplate.getForObject("http://localhost/hello", User.class); System.out.println(user); } //==============华丽的分割线==================//
学习完了Http客户端工具,接下来就能够正式学习微服务了。
- 知道什么是SpringCloud
================================================
参考资料:
关于SpringBoot中spring-boot-starter-*起步依赖参考指南
end