什么是微服务
微服务是一种架构风格,是将一个单一的应用拆分为多个小型的服务,每个服务运行在自己的进程中,服务间采用轻量级的通信机制(HTTP /webservice等)。
微服务围绕业务能力构建并且可以全自动独立部署,它采用不同的语言和存储技术开发。微服务架构的优点有:
- 易于开发和维护:一个微服务只关注一个特定的业务功能,所以它的业务清晰、代码量少,开发和维护单个微服务相对简单。而整个应用是由若干个微服务构建而成,所以整个应用会被维持在一个可控状态。
- 部署成本低:单个微服务所需要的服务器要求比较低,所以可以合理的控制服务器的性能要求,降低了成本。
微服务架构的挑战有:
- 运维要求较高:由于单体应用拆分为多个微服务,需要同时保证所有的微服务正常运行,运维人员将面临新的挑战。
- 分布式带来的复杂性:微服务构建的是分布式系统,那么分布式带来的系统容错性、网络延迟、分布式事务都是新的挑战。
系统架构的演变
系统架构的演变分为以下阶段:
- 单体应用架构。互联网早期,一般的网站应用流量较小,只需一个应用,将所有功能代码都部署在一起就可以,这样可以减少开发、部署和维护的成本。
- 垂直应用架构。随着访问量的逐渐增大,单一应用只能依靠增加节点来应对,但是这时会发现并不是所有的模块都会有比较大的访问量,因此希望只增加几个订单模块,而不增加消息模块,此时垂直应用架构就应运而生了。
- 分布式架构。将原来的一个应用拆成互不相干的几个应用,以提升效率。
- SOA架构。SOA架构提出了服务注册中心,容易服务雪崩。
- 微服务架构。微服务架构将服务原子化拆分,成本高。
- Service Mesh 架构。Service Mesh 架构暂未普及。
为什么使用微服务
使用微服务的原因有:
- 提高可扩展性:单个服务可以独立进行部署和扩展,不需要整个应用同时扩展。
- 提高可靠性:每个服务都是隔离的,可以防止级联失败导致整个系统崩溃。
- 提高效率:使用微服务,开发人员可以专注于自己的服务,减少了不同团队之间的协调成本。
- 降低成本:通过使用微服务,可以按需使用云资源,避免资源的浪费。
- 易于维护:每个微服务都可以独立地进行维护和更新,降低了整体应用的复杂性。
微服务架构的组件
微服务架构的组件有很多,例如:
- Eureka:是注册中心,专门负责服务的注册与发现。
- Zuul:是服务网关,是服务调用的唯一入口,可以在这个组件中实现用户鉴权、动态路由、灰度发布、负载限流等功能。
- Ribbon:是负载均衡器,它的作用是负载均衡,会帮你在每次请求时选择一台机器,均匀的把请求分发到各个机器上。
- Feign:是声明式Web Service客户端,是一种简化HTTP客户端的方式。
- Hystrix:是熔断器,用于处理分布式系统的延迟问题和故障隔离。
- Consul:是服务发现与配置管理工具。
微服务案例搭建
新建父工程
修改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>org.example</groupId>
<artifactId>spring-cloud-bk-2023</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.4</version>
<scope>provided</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2021.0.8</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>http://repo.spring.io/libs-release-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>http://repo.spring.io/libs-snapshot-local</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>http://repo.spring.io/libs-milestone-local</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
添加依赖后,需要刷新依赖即可
创建子工程(product-service)
创建product-service子模块(商品服务),右键父工程->New->Module
添加依赖(product-service)
添加以下依赖在pom.xml里
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
添加依赖后,需要刷新依赖即可
商品模块业务开发结构
实体类(entity)
package com.example.productservice.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;
/**
* 商品实体类
*/
@Data
@Entity
@Table(name="tb_product")
public class Product {
@Id
private Long id;
private String productName;
private Integer status;
private BigDecimal price;
private String productDesc;
private String caption;
private Integer inventory;
}
Dao接口
package com.example.productservice.dao;
import com.example.productservice.entity.Product;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface ProductDao extends JpaRepository<Product, Long>, JpaSpecificationExecutor<Product> {
}
Service接口
package com.example.productservice.service;
import com.example.productservice.entity.Product;
public interface ProductService {
/**
* 根据id查询
*/
Product findById(Long id);
/**
* 保存
*/
void save(Product product);
/**
* 更新
*/
void update(Product product);
/**
* 删除
*/
void delete(Long id);
}
Service接口实现类
package com.example.productservice.service.impl;
import com.example.productservice.dao.ProductDao;
import com.example.productservice.entity.Product;
import com.example.productservice.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
private ProductDao productDao;
@Override
public Product findById(Long id) {
return productDao.findById(id).get();
}
@Override
public void save(Product product) {
productDao.save(product);
}
@Override
public void update(Product product) {
productDao.save(product);
}
@Override
public void delete(Long id) {
productDao.deleteById(id);
}
}
Controller类 (控制类)
package com.example.productservice.controller;
import com.example.productservice.entity.Product;
import com.example.productservice.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@Value("${server.port}")
private String port;
@Value("${spring.cloud.client.ip-address}")
private String ip;
@RequestMapping(value = "/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
Product product = productService.findById(id);
product.setProductName("访问的服务地址:"+ip + ":" + port);
return product;
}
@RequestMapping(value = "",method = RequestMethod.POST)
public String save(@RequestBody Product product) {
productService.save(product);
return "保存成功";
}
}
启动类
package com.example.productservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
@SpringBootApplication
@EntityScan("com.example.productservice.entity")
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
application.yml配置
server:
port: 9001
spring:
application:
name: service-product
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shop1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: #你的数据库用户名
password: #你的数据库密码
jpa:
database: MySQL
show-sql: true
open-in-view: true
generate-ddl: true #自动创建表
client:
ip-address: 10.111.50.229
注意修改数据库信息,例如url、username、password
使用mysql创建数据库:shop1
创建子工程(order-service)
创建order-service子模块(订单服务),右键父工程->New->Module(后面步骤重复商品服务 依赖也相同)
订单模块业务开发结构
实体类(entity)
package com.example.orderservice.entity;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import java.math.BigDecimal;
@Data
@Entity
@Table(name="tb_product")
public class Product {
@Id
private Long id;
private String productName;
private Integer status;
private BigDecimal price;
private String productDesc;
private String caption;
private Integer inventory;
}
Controller类 (控制类)
@RestController
@RequestMapping("/product")
public class ProductController {
@Autowired
private ProductService productService;
@Value("${server.port}")
private String port;
@Value("${client.ip-address}")
private String ip;
@RequestMapping(value = "/{id}",method = RequestMethod.GET)
public Product findById(@PathVariable Long id) {
Product product = productService.findById(id);
product.setProductName("访问的服务地址:"+ip + ":" + port);
return product;
}
@RequestMapping(value = "",method = RequestMethod.POST)
public String save(@RequestBody Product product) {
productService.save(product);
return "保存成功";
}
}
启动类
@SpringBootApplication
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class,args);
}
}
application.yml配置
server:
port: 9001
spring:
application:
name: service-product
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/shop1?useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8
username: #你的数据库用户名
password: #你的数据库密码
jpa:
database: MySQL
show-sql: true
open-in-view: true
generate-ddl: true #自动创建表
client:
ip-address: 10.111.50.229
启动商品和订单浏览器访问http://localhost:9001/product/1和http://localhost:9002/order/buy/1
当然需要在数据库中添加信息 再去访问