0%

Java|JavaWeb入门讲解

pngkey.com-java-logo-png-2232144

学习目标

  • 学会本地搭建环境,运行springboot项目
  • 了解javaweb开发基本技术与工具使用
  • 了解spring重要概念
  • 清楚基本的开发架构
  • 学会开发Springboot入门实例
  • 学会开发SpringBoot JPA 持久层支持实例

参考资料

Demo下载

MyBatis中文文档

Spring Framework 5 中文文档

SpringBoot中文文档

SpringCloud中文文档

廖雪峰Java教程博客

autovy博客:基于SSM评论管理系统开发

基本工具的使用

IDE推荐

image-20210911090207325

推荐JetBrains公司的IDE全家桶,保持风格一致,减少对IDE的学习成本

使用toolbox下载更方便

构建工具

使用构建工具管理java项目的依赖项并实现自动化构建

(1)基本介绍

Maven

Apache_Maven_logo.svg

Ant

1024px-Apache-Ant-logo.svg

Gradle

Gradle_logo

(2)比较

image-20210911085448524

  • Ant:纯java编写,需要自定义构建过程
  • Maven:实现了自动化构建,并内置了依赖管理
  • Gradle:Gradle结合了前两者的优点,是Android Studio指定构建工具

通过自动化构建工具,springboot大大减少了依赖项的添加工作

(3)Maven结构

img

(4)Maven基本使用操作

IDEA创建Maven项目:

  • 左边选择Maven
  • 创建空Maven项目

查看配置文件pom.xml:

配置jar包的仓库地址

maven的仓库默认在国外,这里可以更换为阿里云的仓库

1
2
3
4
5
6
7
8
9
10
11
<repositories>
<repository>
<id>public</id>
<name>aliyun nexus</name>

# 仓库地址 <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>

添加依赖项:

在mvnrepository查找依赖项:https://mvnrepository.com/

查找并复制junit 4.12的依赖配置信息

增加依赖标签<dependencies>

在idea中导入依赖项

image-20210911095458093

查看外部库:

image-20210911095520948

Web服务器

Web服务器一般指网站服务器,是指驻留于[因特网]上某种类型计算机的程序,可以处理浏览器等Web客户端的请求并返回相应响应

(1)Tomcat介绍

Java学习中常常使用Tomcat,这个个小型、轻量级的支持JSP和Servlet 技术的Web服务器,新版的springboot直接就内嵌了这个web服务器放在了启动项中

img
(2)Tomcat下载

新版的springboot已内嵌tomcat,不需要再下载,所以这块做简单的介绍,了解一下运行的原理就好

官网下载:http://tomcat.apache.org/

(3)Tomcat运行
  • 新建文件html文件在webapps\www文件夹

  • 启动bin/startup.bat

    image-20210911104424694

  • 访问http://127.0.0.1:8080/www/test.html

tomcat的默认端口是8080端口,所以springboot启动的网页服务默认也是8080端口

(4)Tomcat修改端口

网页的默认端口使80端口

  • 查看文件conf\server.xml
  • 修改端口为80端口
  • 重新启动bin/startup.bat
  • 80端口占用问题
1
2
3
4
5
6
7
8
// 参看端口号含80的条目
netstat -ano|findstr "80"

// 根据pid查询对应的应用程序
tasklist|findstr "1828"

// 杀死进程
taskkill /f /pid 1828
  • 如果是被系统占用,可以进入服务中心services.msc,停止或禁用SQL Server Reporting Services (MSSQLSERVER) (日志服务,一般用不上)

  • 访问http://127.0.0.1/www/test.html

本地数据库环境搭建

(1)PHPstudy介绍

phpstudy集成了web服务(apache和nginx),数据库服务(mysql),还有数据库缓存工具redis等。

能比较方便得搭建本地环境(如果没有docker进行容器化的话,确实是最佳选择)

下载地址:https://www.xp.cn/

(2)创建数据库

这里使用mysql8.0.12版本

无代码创建好数据库

image-20210911142052336

(3)数据库连接

在idea中连接数据库,测试连接后出现时区问题则填写GMT等时区,推荐使用serverTimezone=Asia/Shanghai

创建数据表student,可在类型处填入长度例如char(20)

image-20210911144428199

J2EE

Java EE是一系列技术标准所组成的平台,它定义了动态Web页面功能(Servlet和Jsp)、商业组件(EJB)、异步消息传输机制(JMS)、名称和目录定位服务(JNDI)、数据库访问(JDBC)、与子系统的连接器(JCA)和安全服务等

这里主要介绍Servlet(服务端程序,可处理请求生成动态web内容),JDBC(数据库访问连接),java的web开发框架都是在此基础上的延拓

image-20210913202431607

Servlet

(1)浏览器访问Servlet流程

image-20210911145431318

(2)Servlet demo 开发

1.新建一个空maven的项目

2.maven导入Servlet依赖

1
2
3
4
5
6
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>

3.编写Servlet类

编写Servlet类接收请求,返回内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 继承Servlet提供的http处理类
public class HelloServlet extends HttpServlet {

// 重写doGet方法,处理get请求
public void doGet(HttpServletRequest request, HttpServletResponse response) {

// 捕捉http请求异常
try{
// 返回响应输出到页面
response.getWriter().println("<h1>Hello Servlet<h1>");
response.getWriter().println(new Date().toString());

}catch (IOException e){
e.printStackTrace();
}

}
}

4.编写web.xml配置文件

编写web.xml配置Servlet

image-20210911153159249

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8" ?>
<web-app>

<!-- 配置servlet信息-->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>HelloServlet</servlet-class>
</servlet>

<!-- 配置http处理类与url映射-->
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/hello</url-pattern>
</servlet-mapping>

</web-app>

5.将Servlet部署到tomcat上

打开模块设置(F4) > 工件 > 创建web工件

image-20210911153909470

添加配置 > tomcat本地服务器 > 添加刚刚创建的工件 > 注意修改应用程序上下文(影响访问的url)

image-20210911154152177

开启服务进行测试

image-20210911155646449

JDBC

JDBC (Java DataBase Connection) 是通过JAVA访问数据库

(1)Java连接数据库流程

undefined

(2)JDBC查询数据库开发

1.新建一个空maven的项目

2.添加mysql-connector-java依

1
2
3
4
5
6
7
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.23</version>
</dependency>

3.注意开启phpstudy的mysql服务,并在idea中连接,记录jdbc链接

4.编写JDBC查询demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class TestJDBC {

public static void main(String[] args) {

try{
// 导入数据库驱动包
Class.forName("com.mysql.jdbc.Driver");

// 建立与数据库的连接
// 数据库名称, 账号,密码
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "test", "123456");

// 创建Statement,用于执行sql语句
Statement s = c.createStatement();

// 编写sql语句
String sql = "select * from student";

// 执行sql语句,并返回结果
ResultSet res = s.executeQuery(sql);

// 处理返回结果
while(res.next()){

int id = res.getInt("id");
String name = res.getString("name");

System.out.printf("%d.%s\n", id, name);

}


}
// 捕捉数据库加载异常
catch (ClassNotFoundException e){
e.printStackTrace();
}
// 捕捉数据库连接异常
catch (SQLException e){
e.printStackTrace();
}

}

}

(3)JDBC ORM 持久化存储

ORM=Object Relationship Database Mapping

对象和关系数据库的映射 简单说,一个对象,对应数据库里的一条记录,使用Java对象来将数据库内的数据持久化

JDBC 是面向 SQL 的,使用起来比较繁琐。所以就有了 ORM 框架,建立了 Java 对象与数据库表之间的映射关系,可以通过直接操作对象来实现持久化,简化了操作的繁杂度

java目前流行的数据库访问框架都是ORM框架

img

1.创建Student类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 一般将一个数据表抽象为一个类
public class Student {

// 将表中的字段作为类的属性
private int id;
private String name;
private int age;

// 提供外界操作属性的方法
public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}


public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

}

在idea中实体类的创建有以下三种方法:

  • 选定类的字段生成setter和getter方法

    image-20210920095441605

  • 使用数据库工具创建实体类

    image-20210904165034192
  • 使用Lombok工具自动生成getter和setter方法

image-20210904165746685

2.修改demo

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class TestJDBC {

public static void main(String[] args) {

try{
// 导入数据库驱动包
Class.forName("com.mysql.jdbc.Driver");

// 建立与数据库的连接
// 数据库名称, 账号,密码
Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/test", "test", "123456");

// 创建Statement,用于执行sql语句
Statement s = c.createStatement();

// >>>>>> 修改sql语句
String sql = "select * from student where id = 1";

// 执行sql语句,并返回结果
ResultSet res = s.executeQuery(sql);

// >>>>去掉while处理返回结果
if(res.next()){
//>>>>>> 实例化一个对象,用于存储一条数据
Student student = new Student();

// 将数据库中的值存储在对象中
student.setId(res.getInt("id"));
student.setName(res.getString("name"));
System.out.println(student);


}

}
// 捕捉数据库加载异常
catch (ClassNotFoundException e){
e.printStackTrace();
}
// 捕捉数据库连接异常
catch (SQLException e){
e.printStackTrace();
}

}


}

3.打断点参看student对象

image-20210911175137132

Spring

Spring重要概念

参考资料:https://blog.csdn.net/qq_40587575/article/details/79901550

(1)IoC与DI概念

IoC:

  • Ioc—Inversion of Control,即“控制反转”
  • 在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制
  • IoC很好的体现了面向对象设计法则之一—— 好莱坞法则:“别找我们,我们找你”;即由IoC容器帮对象找相应的依赖对象并注入,而不是由对象主动去找
Ioc特点 传统java程序 Ioc设计
控制 在对象内部通过new进行创建对象,是程序主动去创建依赖对象 IoC是有专门一个容器来创建这些对象,即由Ioc容器来控制对象的创建
反转 由我们自己在对象中主动控制去直接获取依赖对象,也就是正转 反转则是由容器来帮忙创建及注入依赖对象,对象只是被动的接受依赖对象

DI:

  • DI—Dependency Injection,即“依赖注入”
  • 组件之间依赖关系由容器在运行期决定,由容器动态的将某个依赖关系注入到组件之中
  • 通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现
  • “依赖注入”明确描述了“被注入对象依赖IoC容器配置依赖对象”
(2)IoC与DI概念图例

传统的java程序

image-20210912072844684

使用了loC/DI的程序

image-20210912072938515

(3)Spring的应用

只需要理解一点:Spring帮我们完成了类的创建,多个类的合作的工作,即将IoC容器与其在其中注册的类看作黑盒,通过注解配置文件,可以让类在平台上注册,而这些注册的类叫Bean,我们要做的工作实际上就是注册类和拿到IoC装配好的类

image-20210912093936648

(4)Spring模块

参考资料:

Spring常用注解

Spring的@bean注解

spring-overview

Spring提供了一堆组件,通过拼接这些组件我们可以组装出web应用(比较经典的缝合怪有:SSI,SSH,SSM,他们的首字母就代表Spring)

Spring怎么知道应该把哪些Java类当成bean注册到容器中呢?
使用配置文件或者注解的方式进行标识需要处理的java类!

放在具体的实例中可以这样理解:将数据库的配置信息注册在容器中,在需要访问数据库的对象中用户通过注解(java程序中的特殊标记)让该对象依赖注入了数据库配置信息,从而可以访问到数据库;

开发架构

(1)业务逻辑

Controller–>service接口–>serviceImpl–>dao接口–>daoImpl–>mapper–>db

(2)执行流程

img

pojo则是实体类作为各层次处理传递的对象:

image-20210629104056016

(3)各层职能

image-20210912095119480

  • dao/mapper层即数据持久层,dao层的作用为访问数据库,向数据库发送sql语句,完成数据的增删改查任务
  • service层调用dao层的接口进行业务逻辑应用的处理,封装Service层的业务逻辑有利于业务逻辑的独立性和重复利用性
  • controller层即控制层,控制请求和响应,负责前后端交互 controller层主要调用Service层里面的接口控制具体的业务流程
  • view层即视图层,用户可以看到并操作,可以理解为前端

SpringBoot

SpringBoot让Spring应用更加轻量化,并简化了了配置,实现自动化配置

Spring Boot是一个基于Spring的套件,它帮我们预组装了Spring的一系列组件,以便以尽可能少的代码和配置来开发基于Spring的Java应用程序

总而言之,Springboot是Spring的一套快速开发整合包

img

(1)SpringBoot启动原理

参考资料:

https://www.cnblogs.com/theRhyme/p/11057233.html

https://juejin.cn/post/6895341123816914958#heading-1

img

  • 启动过程中,将注册类装配到Ioc容器,到时候我们可以直接获得装配好的类

  • 反射:通过反射,我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的

  • @ComponentScan :扫描所在类的package;告诉Spring扫描哪个包下面类,加载符合条件的组件(比如@Component和@Repository以及@RestController,@Service等类)

  • @EnableAutoConfiguration:开启自动配置;经过层层调用,最终通过loadSpringFactories()方法加载META-INF/spring.factories中的配置类

  • @SpringBootConfiguration:标注当前类是配置类;将当前类内声明的一个或多个以@Bean注解标记的方法的实例纳入到spring容器中,并且实例名就是方法名

(2)SpringBoot Web Demo

1.新建Spring Initializr项目

image-20210911193904203

2.勾选web模块

image-20210911194039612

3.查看pom.xml

查看pom.xml等待依赖下载完毕(springboot内置的依赖项过多,下载时间较长,start-web简化了Maven的依赖加载)

4.查看SpringbootApplication.java文件

项目创建好之后,就自带一个SpringbootApplication, 其被@SpringBootApplication 所标记,表示这个是一个Springboot 应用,其为Springboot 应用的入口

5.新建web文件存放控制器

新建HelloController.java

1
2
3
4
5
6
7
8
9
10
11
12
// 注解为控制器
@RestController
public class HelloController {

// 注解为映射url
@RequestMapping("/hello")
public String hello(){
return "Hello SpringBoot!";
}

}

这里就相当于实现了Servlet的功能:处理http请求,返回响应内容

而这里的注解就相当于实现了Servlet的web.xml配置文件的功能

注解是java一个强大的特性,简单来说可以理解为代码中的特殊标记,开发人员可以在不改变原有代码情况下,在源代码中嵌入补充信息

image-20210911200155436

6.运行测试

访问链接:http://localhost:8080/hello

感觉少了什么……我的tomcat呢?好像没有配web服务器😰

原来tomcat已经内嵌在SpringbootApplication中一起启动了

image-20210911200952174

也可以看到依赖项中也加载了tomcat,Tomcat的属性都在org.springframework.boot.autoconfigure.web.ServerProperties配置类中做了定义

image-20210911202642854

7.修改端口和上下文

resources/application.properties文件修改配置(可以修改端口和上下文以及视图定位)

1
2
server.port=80
server.servlet.context-path=/test

测试访问http://localhost/test/hello,如果出现了端口占用情况,可以参考tomcat的处理方法

image-20210911204412242

(3)持久层支持

Hibernate

Hibernate是jpa的具体实现,springboot默认使用的就是Hibernate,可以让我们不写一句sql,便于移植,同时也缺乏灵活性

image-20210912105841614

MyBatis

MyBatis也是一个持久化框架,不完全是一个ORM框架(Mybatis是将java方法与sql语句关联起来,而没有将java对象与数据库关联起来)不是依照的JPA规范,可以进行更细致的SQL优化,比较灵活适合处理大量数据的业务,推荐学习

@mybatis

(4)SpringBoot JPA Demo

JPA(Java Persistence API)是Sun官方提出的Java持久化规范,用来方便大家操作数据库

1.准备数据库,参考本地服务器环境搭建章节

2.在前一个demo中进行修改(或新建一个spring项目)

3.增加对mysql和jpa的支持

1
2
3
4
5
6
7
8
9
10
11
12
<!-- mysql-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.21</version>
</dependency>

<!-- jpa-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>

4.修改springboot配置文件,连接数据库

1
2
3
4
5
6
# 数据库配置信息(注意配置数据库的编码和时区)
spring.datasource.url=jdbc:mysql://localhost:3306/test?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai
spring.datasource.username=test
spring.datasource.password=123456
# 数据库连接驱动
spring.datasource.driver-class-name=com.mysql.jdbc.Driver

5.根据orm创建实体类Entity

实体层是各层次用于输入输出处理的数据对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
@Entity // 标记为实体类
@Table(name = "student") // 表明类对应的表名
public class Student {

// 类的私有属性
@Id // 标记为主键
@GeneratedValue(strategy = GenerationType.IDENTITY) // 表明为自增长方式
@Column(name = "id") // 表明对应的数据库字段名
private int id;
@Column(name = "name")
private String name;
@Column(name = "age")
private int age;


// 提供外界操作属性的方法
public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}


public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}


public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

}

6.编写DAO层

DAO与选择的数据库框架有关

DAO层提供与数据库交互的接口,继承JpaRepository父接口,提供了一系列操作数据库方法

1
2
3
4
5
// 继承JpaRepository父接口,提供了一系列操作数据库方法
// 并且提供了泛型<类 , 主键类型>
public interface StudentDAO extends JpaRepository<Student, Integer> {

}

7.编写Service层

定义会用到的操作数据库接口

1
2
3
4
5
6
7
8
9
10
11
// 定义会用到的操作数据库接口
public interface StudentService {


// 查找所有
List<Student> listAll();
// 查找指定id
Student get(int id);


}

实现接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 实现接口中具体的操作数据库的方法
@Service
public class StudentServicempl implements StudentService {


@Autowired
StudentDAO studentDAO;

public List<Student> listAll() {
return studentDAO.findAll();

}

public Student get(int id){
return studentDAO.getById(id);
}


}

8.编写控制器

负责调用服务层的方法,并映射路径提供给客户端使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
@RestController // 注解为控制器
public class StudentController {
// 自动装配service层
@Autowired
StudentServicempl studentServicempl;

@RequestMapping("list")
public String list(){
// 存储数据库返回的列表
List<Student> list = studentServicempl.listAll();

// 输出的字符串
String str = "";

// 遍历列表,获得对象属性的值
for (Student item: list) {

// 拼接为字符串输出
str += item.getId() + "." + item.getName() + "<br>";

}

return str;

}


// 映射get url
@RequestMapping("get")
public String get(){
Student student = studentServicempl.get(3);
return student.getName() + student.getId();

}

}

9.编写单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
@RunWith(SpringRunner.class)
@SpringBootTest
@WebAppConfiguration
public class BTest {

// 测试controller层
MockMvc mockMvc;
@Autowired
WebApplicationContext context;



@Before
public void setUp() throws Exception{
System.out.println(context);
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
}

@Test
public void get() throws Exception{
mockMvc.perform(MockMvcRequestBuilders.get("/list").accept(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResultMatchers.status().isOk())
.andDo(MockMvcResultHandlers.print())
.andReturn();
}

// 测试Dao层
@Autowired
StudentDAO dao;

@Test
public void test(){

List<Student> students = dao.findAll();
for(Student student : students){
System.out.println(student.getName());
}

}

// 测试service层
@Autowired
StudentServicempl studentServicempl;

@Test
public void test2(){

List<Student> students = studentServicempl.listAll();
for(Student student : students){
System.out.println(student.getName());
}
}


}
(5)SpringBoot Mybatis Demo

修改JPA Demo的dao层与实体类,为service提供操作数据库的方法,有注解法和xml两种方式

这里采用比较方便的注解法

  • 修改Dao,映射sql语句

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 标注为mybatis的mapper接口
    @Mapper
    public interface StudentDAO{

    // 使用@Select注解表示调用方法会去执行对应的sql语句
    @Select("select * from student")
    List<Student> findAll();

    @Select("select * from student where id= #{id}")
    Student getById(int id);

    }

  • 修改pojo

    Mybatis是将java方法与sql语句关联起来,而没有将java对象与数据库关联起来。所以不需要注解实体类与数据库的联系

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    public class Student {

    private long id;
    private String name;
    private long age;


    public long getId() {
    return id;
    }

    public void setId(long id) {
    this.id = id;
    }


    public String getName() {
    return name;
    }

    public void setName(String name) {
    this.name = name;
    }


    public long getAge() {
    return age;
    }

    public void setAge(long age) {
    this.age = age;
    }

    }

SpringCloud Netflix

分布式与集群

(1)微服务概念

微服务简单来说,一个springboot就是一个微服务,不同的是这个springboot只做一项单纯的任务

(2)服务注册

springcloud有个微服务注册中eureka server,通过它把微服务注册起来以供来调用

(3)服务访问

微服务直接可以通过注册中心的定位相互访问

(4)分布式概念

简单说,原来是在一个 springboot里就完成的事情,现在分布在多个 springboot里做,这就是初步具备分布式雏形了

  • 如果我要更新数据微服务,视图微服务是不受影响的
  • 可以让不同的团队开发不同的微服务,他们之间只要约定好接口,彼此之间是低耦合的。
  • 如果视图微服务挂了,数据微服务依然可以继续使用
    等等
(5)集群

提供相同功能,只是端口不一样的微服务称为集群

  • 比起一个 springboot, 两个springboot 可以分别部署在两个不同的机器上,那么理论上来说,能够承受的负载就是 x 2. 这样系统就具备通过横向扩展而提高性能的机制
  • 如果 8001 挂了,还有 8002 继续提供微服务,这就叫做高可用

SpringCloud介绍

参考资料:四种软件架构

(1)单体架构

image-20210912153357714

典型的三级架构,前端(Web/手机端)+中间业务逻辑层+数据库层

(2)分布式架构

img

将一个大的系统划分为多个业务模块,业务模块分别部署在不同的服务器上,各个业务模块之间通过接口进行数据交互。数据库也大量采用分布式数据库,通过LVS/Nginx代理应用,将用户请求均衡的负载到不同的服务器上

(3)微服务架构

img

将系统拆分成很多小应用(微服务),微服务可以部署在不同的服务器上,也可以部署在相同的服务器不同的容器上。当应用的故障不会影响到其他应用,单应用的负载也不会影响到其他应用

(4)SpringCloud基本组成

Spring将目前各家公司开发的比较成熟、经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装屏蔽掉了复杂的配置和实现原理,最终给开发者留出了一套简单易懂、易部署和易维护的分布式系统开发工具包

SpringCloud 就是一套工具,帮助我们很容易地搭建出这么一个 集群和分布式的架子出来,Spring Cloud 专注于为典型用例提供良好的开箱即用体验,并为其他用户提供可扩展性机制

img

  • Spring Cloud Netflix:cloud各项服务依赖与它,与各种Netflix OSS组件集成,组成微服务的核心,它的主要有组成有Eureka, Hystrix, Zuul
  • Eureka注册中心服务:SpringCloud服务中心,云端服务发现,一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移
  • Microservice:微服务,在springcloud可以简单理解为专职做一项任务的springboot,微服务之间可以通过Ribbon和Feign两种方式进行微服务之间的访问(Feign是主流方式)
  • Zipkin链路跟踪:从属于Spring Cloud Sleuth(日志收集工具包),为SpringCloud应用实现了一种分布式追踪解决方案,可以查看微服务之间的复杂的调用关系
  • Config Server 配置服务器:俗称配置中心,配置管理工具包,让你可以把配置放到远程服务器(比如集中放在git),集中化管理集群配置
  • Bus 消息总线:事件、消息总线,用于在集群(例如,配置变化事件)中传播状态变化,可与Config Server 联合,再使用RabbitMQ实现热部署(所谓热部署即不需要重启微服务,对配置信息自动更新)
  • 断路器Hystrix:容错管理工具,旨在通过熔断机制控制服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力,简单来说就是提供异常或错误的处理微服务,比如说某个微服务寄了,断路器就可以调用其他微服务顶上(一般是错误处理的微服务)
  • Hystrix dashboard 断路器监控:通过turbine将集群中多个实例汇聚在一起,对微服务进行断路器监控
  • 网关Zuul:Zuul 是在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架,通过网关简化了对各个服务的访问:不再需要记录各个微服务的地址和端口,而是通过网关去访问他们

Springcloud 启动测试

(1)项目启动
  • 启动RabbitMQ(访问http://127.0.0.1:15672/#即已开启)

  • 启动链路追踪服务器(这里开启的端口要与微服务中的配置一致)

    1
    java -jar zipkin-server-2.10.1-exec.jar  --server.port=8050 --zipkin.collector.rabbitmq.addresses=localhost
  • 访问配置仓库https://github.com/Autovy/SpringCloudConfig/(也可以在config-server模块的配置文件修改成自己的仓库)

  • 运行EurekaServerApplication,启动注册中心服务(端口为8761)

  • 运行ConfigServerApplication,启动配置服务器(端口为8030)

  • 运行ProductDataServiceApplication,启动数据微服务(端口填写8001,8002形成集群)

  • 运行ProductViewServiceFeignApplication,启动视图微服务(端口可填写8012,8013)

  • 运行ProductServiceHystrixDashboardApplication,开启断路器监控,监控单个微服务(端口为8020)

  • 运行ProductServiceTurbineApplication,开启聚合断路器监控以监控集群(端口为8021)

  • 运行视图微服务里的 AccessViewService 来周期性地访问 http://127.0.0.1:8012/productshttp://127.0.0.1:8013/products,以提供监控数据

  • 运行ProductServiceZuulApplication,开启网关服务(端口为8060)

(2)测试服务注册中心

打开链接http://127.0.0.1:8761/,即可查看到注册服务中心Eureka

image-20210919135602819

(3)测试数据微服务

打开链接http://127.0.0.1:8001/productshttp://127.0.0.1:8002/products 都可以访问到返回的数据

image-20210919135818137

(4)测试视图微服务

打开链接http://127.0.0.1:8012/productshttp://127.0.0.1:8013/products 可以访问到视图页面,并且可以发现视图微服务会随机选择端口访问数据微服务实现负载均衡

image-20210919140106927

(5)测试服务链路追踪

打开链接http://127.0.0.1:8050/zipkin/dependency/ 即可访问到

Zipkin链路跟踪服务页面,即可看到微服务间的访问关系

image-20210919140414948

(6)测试Bus消息总线

可访问http://127.0.0.1:8030/version/dev查看到配置服务器的信息

访问视图查看当前版本号

image-20210919140727703

修改配置服务器git上的版本号,这里我的仓库地址为https://github.com/Autovy/SpringCloudConfig/

image-20210919141137143

启动视图微服务中的FreshConfigUtil使用 post 的方式访问 http://localhost:8012/actuator/bus-refresh 地址,更新配置信息

image-20210919141416336

最后再查看视图上的更新

image-20210919141503558

可以访问RabbitMQ页面:http://127.0.0.1:15672/,查看队列,连接,还有交换机

(7)测试Hystrix断路器及其监控

打开链接http://localhost:8020/hystrix即可进入Hystrix断路器的监控入口

image-20210919141754328

框内输入http://localhost:8012/actuator/hystrix.stream即可对8012端口的视图微服务进行监控

image-20210919141940229

框内输入http://localhost:8021/turbine.stream即可实现对整个集群的视图微服务进行监控

image-20210919142137829

停止数据微服务ProductDataServiceApplication集群,触发断路器:

访问视图可得

image-20210919142903819

访问单个微服务监控页面可得

image-20210919143250565

访问聚合集群微服务监控页面可得

image-20210919143120242

(8)网关测试

可以在zuul的配置文件中修改微服务的访问路由,我绑定的路由如下:

http://localhost:8060/api-data/products :访问数据微服务集群

image-20210919135818137

http://localhost:8060/api-view/products :访问视图微服务集群

image-20210919142625877

可以发现其访问集群的端口也是负载均衡的

可以发现其访问集群的端口也是负载均衡的