在诞⽣之初,项目的⽤户量、数据量规模都⽐较⼩,项目所有的功能模块都放在一个工程中编码、
编译、打包并且部署在一个Tomcat容器中的架构模式就是单体应用架构,这样的架构既简单实 ⽤、便
于维护,成本⼜低,成为了那个时代的主流架构⽅式。
单体项目优点
单体架构的应用比较容易部署、测试, 在项目的初期,单体应用可以很好地运行。
然而,随着需求的不断增加, 越来越多的人加入开发团队,代码库也在飞速地膨胀。慢慢地,单体应用变得越来越臃肿,可维护性、灵活性逐渐降低,维护成本越来越高。
单体项目的缺点
业务量上涨之后,单体应用架构进一步丰富变化,比如应用集群部署、使用Nginx进行负载均衡、增加
缓存服务器、增加文件服务器、数据库集群并做读写分离等,通过以上措施增强应对高并发的能力、应
对一定的复杂业务场景,但依然属于单体应用架构。
为了避免上⾯提到的那些问题,开始做模块的垂直划分,做垂直划分的原则是基于现有的业务
特性来做,核心目标标第⼀个是为了业务之间互不影响,第⼆个是在研发团队的壮⼤后为了提⾼效率,
减少组件之间的依赖。
垂直应用架构优点
垂直应用架构缺点
在做了垂直划分以后,模块随之增多,维护的成本在也变⾼,⼀些通⽤的业务和模块重复的越来越
多,为了解决上⾯提到的接⼝协议不统⼀、服务⽆法监控、服务的负载均衡,引⼊了阿⾥巴巴开源的
Dubbo ,⼀款⾼性能、轻量级的开源Java RPC框架,可以和Spring框架无缝集成。
它提供了三⼤核⼼能⼒:⾯向接⼝的远程⽅法调⽤,智能容错和负载均衡,以及服务⾃动注册和发现。
SOA (Service-Oriented Architecture),即面向服务的架构。根据实际业务,把系统拆分成合适
的、独立部署的模块,模块之间相互独立(通过Webservice/Dubbo等技术进行通信)。
优点:分布式、松耦合、扩展灵活、可重用。
缺点:服务抽取粒度较大、服务调用方和提供方耦合度较高(接口耦合度)
微服务架构可以说是SOA架构的一种拓展,这种架构模式下它拆分粒度更小、服务更独立。把应用
拆分成为一个个微小的服务,不同的服务可以使用不同的开发语言和存储,服务之间往往通过Restful等
轻量级通信。微服务架构关键在于微小、独立、轻量级通信。微服务是在 SOA 上做的升华粒度更加细致,微服务架构强调的⼀个重点是业务需要彻底的组件化和服务化
微服务架构设计的核心思想就是“微”,拆分的粒度相对比较小,这样的话单一职责、开发的耦合度
就会降低、微小的功能可以独立部署扩展、灵活性强,升级改造影响范围小
微服务架构的优点
微服务架构的缺点
服务注册与服务发现
服务注册: 服务提供者将所提供服务的信息(服务器IP和端口、服务访问协议等)注册/登记到注册
中心
服务发现: 服务消费者能够从注册中心获取到较为实时的服务列表,然后根究一定的策略选择一个
服务访问
微服务架构越发流行,一个项目往往拆分成很多个服务,那么一次请求就需要涉及到很多个服务。不同
的微服务可能是由不同的团队开发、可能使用不同的编程语言实现、整个项目也有可能部署在了很多服
务器上(甚至百台、千台)横跨多个不同的数据中心。
所谓链路追踪,就是对一次请求涉及的很多个服务链路进行日志记录、性能监控
Dubbo是阿里巴巴公司开源的一个高性能优秀的服务框架,基于RPC调用,对于目前使用率较高的
Spring Cloud Netflix来说,它是基于HTTP的,所以效率上没有Dubbo高,但问题在于Dubbo体系的组
件不全,不能够提供一站式解决方案,比如服务注册与发现需要借助于Zookeeper等实现,而Spring
Cloud Netflix则是真正的提供了一站式服务化解决方案,且有Spring大家族背景
CREATE TABLE products
(
id INT PRIMARY KEY AUTO_INCREMENT,
NAME VARCHAR(50), #商品名称
price DOUBLE,
flag VARCHAR(2), #上架状态
goods_desc VARCHAR(100), #商品描述
images VARCHAR(400), #商品图片
goods_stock INT, #商品库存
goods_type VARCHAR(20) #商品类型
);
添加maven配置
修改打包方式为 pom
<packaging>pompackaging>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.1.6.RELEASEversion>
parent>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-loggingartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<version>1.18.4version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
<optional>trueoptional>
dependency>
dependencies>
添加打包插件
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.pluginsgroupId>
<artifactId>maven-compiler-pluginartifactId>
<configuration>
<source>8source>
<target>8target>
<encoding>utf-8encoding>
configuration>
plugin>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<executions>
<execution>
<goals>
<goal>repackagegoal>
goals>
execution>
executions>
plugin>
plugins>
build>
删除 src 目录
maven配置如下 :
<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>lg-parentartifactId>
<groupId>cn.knightzzgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>lg-service-commonartifactId>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>com.baomidougroupId>
<artifactId>mybatis-plus-boot-starterartifactId>
<version>3.3.2version>
dependency>
<dependency>
<groupId>javax.persistencegroupId>
<artifactId>javax.persistence-apiartifactId>
<version>2.2version>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
dependencies>
project>
需要下载 MybatisX 插件
点击数据库表, 选中插件
生成实体类
实体类代码
package cn.knightzz.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import lombok.Data;
/**
*
* @author knightzz98
* @TableName products
*/
@TableName(value ="products")
@Data
public class Products implements Serializable {
@TableId(type = IdType.AUTO)
private Integer id;
private String name;
private Double price;
private String flag;
private String goodsDesc;
private String images;
private Integer goodsStock;
private String goodsType;
@TableField(exist = false)
private static final long serialVersionUID = 1L;
}
<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>lg-parentartifactId>
<groupId>cn.knightzzgroupId>
<version>1.0-SNAPSHOTversion>
parent>
<modelVersion>4.0.0modelVersion>
<artifactId>lg-service-productartifactId>
<properties>
<maven.compiler.source>8maven.compiler.source>
<maven.compiler.target>8maven.compiler.target>
properties>
<dependencies>
<dependency>
<groupId>cn.knightzzgroupId>
<artifactId>lg-service-commonartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
dependencies>
project>
添加数据库连接配置
server:
port: 9000
spring:
application:
# 微服务名称
name: lg-service-product
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 123456
ProductsService接口
package cn.knightzz.service;
import cn.knightzz.entity.Products;
import com.baomidou.mybatisplus.extension.service.IService;
/**
*
* @author knightzz98
*/
public interface ProductsService extends IService<Products> {
/**
* 根据id查询产品信息
* @param id
* @return
*/
public Products findById(Integer id);
}
ProductsServiceImpl
package cn.knightzz.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.knightzz.entity.Products;
import cn.knightzz.service.ProductsService;
import cn.knightzz.mapper.ProductsMapper;
import org.springframework.stereotype.Service;
/**
*
* @author knightzz98
*/
@Service
public class ProductsServiceImpl extends ServiceImpl<ProductsMapper, Products>
implements ProductsService{
@Override
public Products findById(Integer id) {
// 可以直接使用 baseMapper 查询数据
Products products = baseMapper.selectById(id);
return products;
}
}
package cn.knightzz.controller;
import cn.knightzz.entity.Products;
import cn.knightzz.service.ProductsService;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author 王天赐
* @title: ProductController
* @projectName springcloud-lg
* @description:
* @website http://knightzz.cn/
* @github https://github.com/knightzz1998
* @date 2022/2/11 10:56
*/
@RestController
@RequestMapping("/products")
public class ProductController {
@Resource
ProductsService productsService;
@RequestMapping("/query/{id}")
public Products query(@PathVariable Integer id){
return productsService.findById(id);
}
}
package cn.knightzz;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@MapperScan("cn.knightzz.mapper")
public class ProductApplication {
public static void main(String[] args) {
SpringApplication.run(ProductApplication.class, args);
}
}
添加 maven 配置
<dependencies>
<dependency>
<groupId>cn.knightzzgroupId>
<artifactId>lg-service-commonartifactId>
<version>1.0-SNAPSHOTversion>
dependency>
dependencies>
application.yml
server:
port: 9100
spring:
application:
# 微服务名称
name: lg-service-page
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC&characterEncoding=UTF-8
username: root
password: 123456
PageController
package cn.knightzz.page.controller;
import cn.knightzz.entity.Products;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
/**
* @author 王天赐
* @title: PageController
* @projectName springcloud-lg
* @description:
* @website http://knightzz.cn/
* @github https://github.com/knightzz1998
* @date 2022/2/11 11:55
*/
@RestController
@RequestMapping("/page")
public class PageController {
@Resource
private RestTemplate restTemplate;
@GetMapping("/getData/{id}")
public Products findDataById(@PathVariable Integer id){
Products product = restTemplate.getForObject("http://localhost:9000/products/query/" + id, Products.class);
System.out.println("从 lg-service-product 模块得到的数据 " + product);
return product;
}
}
页面启动类
package cn.knightzz;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
@SpringBootApplication
public class PageApplication {
public static void main(String[] args) {
SpringApplication.run(PageApplication.class, args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
从形式上来说,Feign一个顶三,Feign = RestTemplate + Ribbon + Hystrix