项目模块预览
一般我们做项目使用的springboot,但是一旦项目做的大了之后,服务功能越做越多就会导致代码冗余,可能一个服务中提供了多项功能,可能导致越到后面就会出现单个工程项目越来越大,代码冗余的情况;并且集群部署时,可能一个服务提供了多项功能导致大量的请求来临到某个服务。
基于种种原因出现了微服务,微服务指的是将原本的大的服务模块进行拆分,例如订单模块、日志模块、基础数据模块等等等,每一个模块都是服务,服务与服务之间也能够进行相互调用,下面我介绍一下springcloud中每个组件的功能及出现的目的:
最原始阶段:后台管理服务、前台服务、小程序服务,后台管理提供给用户后台管理的功能,前台负责数据展示的功能,小程序提供一些小程序需要的功能 问题:后台管理服务到之后也会涉及很多的功能模块,若是不进行拆分,后台管理做的很大时就会不利于代码扩展与编写等等导致冗余等情况,其他部分也是如此 springcloud搭建微服务 ——————1、搭建一个服务中心服务 首先微服务需要有一个服务中心(Eureka Server),对应的服务在启动时都能够进行注册到服务中心上去。 服务中心为之后远程调用、网关统一鉴权都提供了很大的便利 ————————2、改造基本服务为eureka client 有了服务中心,接着我们需要将我们的服务注册到服务中心上去,如何注册呢?就需要将我们的原本服务改造为Eureka client并进行配置服务中心地址,当服务启动时就会自动注册到服务中心。 ————3、引入openfeign,让服务具有远程调用的功能 注册好以后,其实我们某个服务可能需要去调用其他远程服务的接口,此时急需要在eureka client中引入openfeign,编写feign client接口来进行远程调用。 ————4、解决远程可能会出现的问题,引入Hystrix 能够远程调用了,此时就会出现问题,因为远程调用难免会出现一系列的问题如调用的服务瘫痪,功能不可用情况,如何解决呢?springcloud也给我们提供了一个组件断路器Hystrix,其能够在我们调用远程服务出现不可避免的问题时返回默认内容,根据我们需求自己定义。 ————5、实现鉴权等功能,引入Zuul 此时我们的服务中心已经初步具备管理多个节点功能,此时我们又出现了一个需求就是对应的服务也不能够被人随意访问,那么就需要对我们的服务提供保护措施,此时需要有一个统一的鉴权服务,Zuul出现了,我们想要访问某个服务中得接口可以统一通过zuul网关来进行访问,在zuul中我们可以通过设置过滤器来实现一些特定的功能。 ————6、负载均衡,Ribbon 在3中引入openfeign具有调用远程服务接口的能力,一般的话远程服务不会独有一份,可能有多个相同节点服务,如何解决大量请求会去调用远程服务时的选择策略,springcloud提供了一个Ribbon组件,其包含三个策略用于我们进行远程调用服务的选择等等
总而言之:要想把大的服务模块进行拆分,拆分为多个微服务并且服务与服务之前进行相互调用就会面临一系列的问题,springcloud组织给出了一系列的解决方案,每个组件都有其存在的意义,都能够解决相对应的痛点。
完整项目
本次项目:主要就是两个服务,一个服务提供课程列表的功能,另一个服务提供课程价格的功能,通过这两个简单服务来整合springcloud,进行学习springcloud中的六个组件。
数据库
一个是课程表、另一个是课程价格表,前者与后者是一对多的关系。
/* Navicat Premium Data Transfer Source Server : 本地mysql5.7 Source Server Type : MySQL Source Server Version : 50732 Source Host : localhost:3306 Source Schema : test Target Server Type : MySQL Target Server Version : 50732 File Encoding : 65001 Date: 05/10/2021 10:51:03 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; -- ---------------------------- -- Table structure for course -- ---------------------------- DROP TABLE IF EXISTS `course`; CREATE TABLE `course` ( `id` int(11) NOT NULL, `course_id` int(11) NULL DEFAULT NULL, `name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `valid` int(1) NULL DEFAULT NULL COMMENT '是否上架,0不上架,1上架\r\n', PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of course -- ---------------------------- INSERT INTO `course` VALUES (1, 362, 'Java并发核心知识体系靖江', 1); INSERT INTO `course` VALUES (2, 409, '玩转Java并发工具,精通JUC', 1); INSERT INTO `course` VALUES (3, 121, 'Nginx入门到实践', 0); -- ---------------------------- -- Table structure for course_price -- ---------------------------- DROP TABLE IF EXISTS `course_price`; CREATE TABLE `course_price` ( `id` int(11) NOT NULL, `course_id` int(11) NULL DEFAULT NULL, `price` decimal(10, 2) NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Records of course_price -- ---------------------------- INSERT INTO `course_price` VALUES (1, 362, 348.50); INSERT INTO `course_price` VALUES (2, 409, 399.68); INSERT INTO `course_price` VALUES (3, 121, 266.78); SET FOREIGN_KEY_CHECKS = 1;
spring-cloud-course-practice(总模块)
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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <!-- 模块化管理 --> <packaging>pom</packaging> <modules> <module>course-service</module> <module>eurake-server</module> <module>course-zuul</module> </modules> <!-- 父模块 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.12.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.changlu</groupId> <artifactId>spring-cloud-course-practice</artifactId> <version>1.0.0</version> <name>spring-cloud-course-practice</name> <description>course project for Spring Cloud</description> <properties> <java.version>1.8</java.version> <mybatis.plus.version>3.4.3</mybatis.plus.version> <mysql-version>8.0.23</mysql-version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <!-- 表示Spring Cloud的版本--> <dependencyManagement> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql-version}</version> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>${mybatis.plus.version}</version> </dependency> <!-- SpringCloud指定版本 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>Greenwich.SR5</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>》
eurake-server(服务中心服务)
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"> <parent> <artifactId>spring-cloud-course-practice</artifactId> <groupId>com.changlu</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>eurake-server</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <!-- 模块名及描述信息 --> <name>course-eureka-server</name> <description>Spring Cloud Eureka</description> <dependencies> <!-- 服务中心依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
EurekaServerApplication.java:
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; /** * @ClassName EurakeServerApplication * @Author ChangLu * @Date 2021/10/4 13:42 * @Description 服务中心服务 */ @EnableEurekaServer //开启Eureka Server服务 @SpringBootApplication public class EurekaServerApplication { public static void main(String[] args) { SpringApplication.run(EurekaServerApplication.class, args); } }
application.yaml:
server: port: 8000 spring: application: name: eureka-server # 应用名称 eureka: instance: hostname: localhost client: fetch-registry: false #fetch-registry:获取注册表。不需要同步其他节点数据。(当前没有建立eureka server集群,这里不需要同步节点) register-with-eureka: false # 代表是否将自己也注册到Eureka Server,这里不注册 service-url: # 设置服务中心的地址 => http://localhost:8000/eureka/ defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
此时我们访问服务中心:http://localhost:8000/
course-service(课程模块)
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"> <parent> <artifactId>spring-cloud-course-practice</artifactId> <groupId>com.changlu</groupId> <version>1.0.0</version> </parent> <modelVersion>4.0.0</modelVersion> <packaging>pom</packaging> <groupId>com.changlu</groupId> <artifactId>course-service</artifactId> <!-- 管理两个服务 --> <modules> <module>course-list</module> <module>course-price</module> </modules> </project>
course-list(课程服务)
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 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.changlu</groupId> <artifactId>course-service</artifactId> <version>1.0.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.changlu</groupId> <artifactId>course-list</artifactId> <version>1.0.0</version> <name>course-list</name> <description>course list</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>compile</scope> <optional>true</optional> </dependency> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.8.1</version> <scope>test</scope> </dependency> <!-- Eureka-client:用于注册到服务中心 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
application.yaml:
spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai username: root password: 123456 application: name: course-list # 应用名 server: port: 8080 # 指定注册的服务中心地址,一般与eureka-server中配置的对应,此时该服务启动就会将自己注册到服务中心 eureka: client: service-url: defaultZone: http://localhost:8000/eureka/ # 被course-price调用并设置ribbon,所以这里要开启 ribbon: eureka: enabled: true
启动器:
import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @MapperScan("com.changlu.democourse.mapper") public class CourseListApplication { public static void main(String[] args) { SpringApplication.run(CourseListApplication.class, args); } }
controller、service、mapper一系列
@Data public class Course implements Serializable { private static final long serialVersionUID = -6849794470748667710L; private Integer id; private Integer courseId; private String name; private Integer valid; } /** * @ClassName CourseController * @Author ChangLu * @Date 2021/10/4 13:03 * @Description 课程控制器 */ @RestController @RequestMapping("/course") public class CourseController { @Autowired private CourseService courseService; @GetMapping("/list") public List<Course> getList(){ return courseService.getCourseList(); } } public interface CourseService { List<Course> getCourseList(); } @Service public class CourseServiceImpl implements CourseService { @Autowired private CourseMapper courseMapper; @Override public List<Course> getCourseList() { return courseMapper.getCourseList(); } } @Repository public interface CourseMapper { @Select("select * from course") List<Course> getCourseList(); }
该服务提供了查询课程的能力,该服务启动时将会被注册到服务中心。